3 * Various handy server-only utilities
5 * (c) 2001 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Trivial IP Encryption (TrIPE).
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
26 /*----- Header files ------------------------------------------------------*/
30 /*----- Global variables --------------------------------------------------*/
32 octet buf_i
[PKBUFSZ
], buf_o
[PKBUFSZ
], buf_t
[PKBUFSZ
], buf_u
[PKBUFSZ
];
34 /*----- Sequence numbers --------------------------------------------------*/
36 /* --- @seq_reset@ --- *
38 * Arguments: @seqwin *s@ = sequence-checking window
42 * Use: Resets a sequence number window.
45 void seq_reset(seqwin
*s
) { s
->seq
= 0; s
->win
= 0; }
47 /* --- @seq_check@ --- *
49 * Arguments: @seqwin *s@ = sequence-checking window
50 * @uint32 q@ = sequence number to check
51 * @const char *service@ = service to report message from
53 * Returns: Zero on success, nonzero if the sequence number was bad.
55 * Use: Checks a sequence number against the window, updating things
59 int seq_check(seqwin
*s
, uint32 q
, const char *service
)
65 a_warn(service
, "replay", "old-sequence", A_END
);
68 if (q
>= s
->seq
+ SEQ_WINSZ
) {
69 n
= q
- (s
->seq
+ SEQ_WINSZ
- 1);
76 qbit
= 1 << (q
- s
->seq
);
78 a_warn(service
, "replay", "duplicated-sequence", A_END
);
85 /*----- Rate limiting -----------------------------------------------------*/
87 /* --- @ratelim_init@ --- *
89 * Arguments: @ratelim *r@ = rate-limiting state to fill in
90 * @unsigned persec@ = credit to accumulate per second
91 * @unsigned max@ = maximum credit to retain
95 * Use: Initialize a rate-limiting state.
98 void ratelim_init(ratelim
*r
, unsigned persec
, unsigned max
)
102 gettimeofday(&r
->when
, 0);
105 /* --- @ratelim_withdraw@ --- *
107 * Arguments: @ratelim *r@ = rate-limiting state
108 * @unsigned n@ = credit to withdraw
110 * Returns: Zero if successful; @-1@ if there is unsufficient credit
112 * Use: Updates the state with any accumulated credit. Then, if
113 * there there are more than @n@ credits available, withdraw @n@
114 * and return successfully; otherwise, report failure.
117 int ratelim_withdraw(ratelim
*r
, unsigned n
)
119 struct timeval now
, delta
;
122 gettimeofday(&now
, 0);
123 TV_SUB(&delta
, &now
, &r
->when
);
124 d
= (unsigned long)r
->persec
*delta
.tv_sec
+
125 (unsigned long)r
->persec
*delta
.tv_usec
/MILLION
;
126 if (d
< r
->max
- r
->n
) r
->n
+= d
;
130 if (n
> r
->n
) return (-1);
131 else { r
->n
-= n
; return (0); }
134 /*----- Crypto ------------------------------------------------------------*/
136 /* --- @ies_encrypt@ --- *
138 * Arguments: @kdata *kpub@ = recipient's public key
139 * @unsigned ty@ = message type octet
140 * @buf *b@ = input message buffer
141 * @buf *bb@ = output buffer for the ciphertext
143 * Returns: On error, returns a @KSERR_...@ code or breaks the buffer;
144 * on success, returns zero and the buffer is good.
146 * Use: Encrypts a message for a recipient, given their public key.
147 * This does not (by itself) provide forward secrecy or sender
148 * authenticity. The ciphertext is self-delimiting (unlike
152 int ies_encrypt(kdata
*kpub
, unsigned ty
, buf
*b
, buf
*bb
)
154 dhgrp
*g
= kpub
->grp
;
155 dhsc
*u
= g
->ops
->randsc(g
);
156 dhge
*U
= g
->ops
->mul(g
, u
, 0), *Z
= g
->ops
->mul(g
, u
, kpub
->K
);
157 bulkalgs
*algs
= kpub
->algs
.bulk
;
165 IF_TRACING(T_CRYPTO
, {
167 "crypto: encrypting IES message (type 0x%02x) for recipient `%s'",
169 trace_block(T_CRYPTO
, "crypto: plaintext message", BCUR(b
), BLEFT(b
));
172 a
.hc
= kpub
->algs
.h
; a
.what
= "tripe:ecies-"; a
.f
= DF_OUT
;
173 buf_init(&bk
, buf_u
, sizeof(buf_u
)); a
.k
= BBASE(&bk
);
174 g
->ops
->stge(g
, &bk
, U
, DHFMT_HASH
); a
.x
= a
.y
= BLEN(&bk
);
175 g
->ops
->stge(g
, &bk
, Z
, DHFMT_HASH
); a
.z
= BLEN(&bk
);
177 T( trace_block(T_CRYPTO
, "crypto: KEM clue", a
.k
, a
.x
);
178 trace_block(T_CRYPTO
, "crypto: shared secret", a
.k
+ a
.y
, a
.z
- a
.y
); )
180 len
= BCUR(bb
); buf_get(bb
, 2);
181 bulk
= algs
->ops
->genkeys(algs
, &a
);
182 bulk
->ops
= algs
->ops
;
183 g
->ops
->stge(g
, bb
, U
, DHFMT_VAR
); if (BBAD(bb
)) goto end
;
184 rc
= bulk
->ops
->encrypt(bulk
, ty
, b
, bb
, 0);
185 if (rc
|| BBAD(bb
)) goto end
;
186 n
= BCUR(bb
) - len
- 2; assert(n
<= MASK16
); STORE16(len
, n
);
189 bulk
->ops
->freectx(bulk
);
190 g
->ops
->freesc(g
, u
);
191 g
->ops
->freege(g
, U
);
192 g
->ops
->freege(g
, Z
);
196 /* --- @ies_decrypt@ --- *
198 * Arguments: @kdata *kpub@ = private key key
199 * @unsigned ty@ = message type octet
200 * @buf *b@ = input ciphertext buffer
201 * @buf *bb@ = output buffer for the message
203 * Returns: On error, returns a @KSERR_...@ code; on success, returns
204 * zero and the buffer is good.
206 * Use: Decrypts a message encrypted using @ies_encrypt@, given our
210 int ies_decrypt(kdata
*kpriv
, unsigned ty
, buf
*b
, buf
*bb
)
212 dhgrp
*g
= kpriv
->grp
;
213 bulkalgs
*algs
= kpriv
->algs
.bulk
;
222 IF_TRACING(T_CRYPTO
, {
224 "crypto: decrypting IES message (type 0x%02x) to recipient `%s'",
226 trace_block(T_CRYPTO
, "crypto: ciphertext message", BCUR(b
), BLEFT(b
));
229 if (buf_getbuf16(b
, &bc
) ||
230 (U
= g
->ops
->ldge(g
, &bc
, DHFMT_VAR
)) == 0 ||
231 g
->ops
->checkge(g
, U
))
232 { rc
= KSERR_MALFORMED
; goto end
; }
233 Z
= g
->ops
->mul(g
, kpriv
->k
, U
);
235 a
.hc
= kpriv
->algs
.h
; a
.what
= "tripe:ecies-"; a
.f
= DF_IN
;
236 buf_init(&bk
, buf_u
, sizeof(buf_u
)); a
.k
= BBASE(&bk
); a
.x
= 0;
237 g
->ops
->stge(g
, &bk
, U
, DHFMT_HASH
); a
.y
= BLEN(&bk
);
238 g
->ops
->stge(g
, &bk
, Z
, DHFMT_HASH
); a
.z
= BLEN(&bk
);
239 T( trace_block(T_CRYPTO
, "crypto: KEM clue", a
.k
+ a
.x
, a
.y
- a
.x
);
240 trace_block(T_CRYPTO
, "crypto: shared secret", a
.k
+ a
.y
, a
.z
- a
.y
); )
243 bulk
= algs
->ops
->genkeys(algs
, &a
);
244 bulk
->ops
= algs
->ops
;
246 rc
= bulk
->ops
->decrypt(bulk
, ty
, &bc
, bb
, &seq
);
248 if (seq
) { rc
= KSERR_SEQ
; goto end
; }
250 T( trace_block(T_CRYPTO
, "crypto: decrypted message", m
, BCUR(bb
) - m
); )
253 if (bulk
) bulk
->ops
->freectx(bulk
);
254 g
->ops
->freege(g
, U
);
255 g
->ops
->freege(g
, Z
);
259 /*----- Random odds and sods ----------------------------------------------*/
261 /* --- @timestr@ --- *
263 * Arguments: @time_t t@ = a time to convert
265 * Returns: A pointer to a textual representation of the time.
267 * Use: Converts a time to a textual representation. Corrupts
271 const char *timestr(time_t t
)
277 strftime((char *)buf_u
, sizeof(buf_u
), "%Y-%m-%dT%H:%M:%S", tm
);
278 return ((const char *)buf_u
);
281 /* --- @mystrieq@ --- *
283 * Arguments: @const char *x, *y@ = two strings
285 * Returns: True if @x@ and @y are equal, up to case.
288 int mystrieq(const char *x
, const char *y
)
291 if (!*x
&& !*y
) return (1);
292 if (tolower((unsigned char)*x
) != tolower((unsigned char)*y
))
298 /*----- Address handling --------------------------------------------------*/
300 const struct addrfam aftab
[] = {
302 # define DEF(af, qf) { AF_##af, #af, adns_qf_##qf },
304 # define DEF(af, qf) { AF_##af, #af },
312 * Arguments: @int af@ = an address family code
314 * Returns: The index of the address family's record in @aftab@, or @-1@.
321 for (i
= 0; i
< NADDRFAM
; i
++)
322 if (af
== aftab
[i
].af
) return (i
);
326 /* --- @addrsz@ --- *
328 * Arguments: @const addr *a@ = a network address
330 * Returns: The size of the address, for passing into the sockets API.
333 socklen_t
addrsz(const addr
*a
)
335 switch (a
->sa
.sa_family
) {
336 case AF_INET
: return (sizeof(a
->sin
));
337 case AF_INET6
: return (sizeof(a
->sin6
));
342 /* --- @getport@, @setport@ --- *
344 * Arguments: @addr *a@ = a network address
345 * @unsigned port@ = port number to set
349 * Use: Retrieves or sets the port number in an address structure.
352 unsigned getport(addr
*a
)
354 switch (a
->sa
.sa_family
) {
355 case AF_INET
: return (ntohs(a
->sin
.sin_port
)); break;
356 case AF_INET6
: return (ntohs(a
->sin6
.sin6_port
)); break;
361 void setport(addr
*a
, unsigned port
)
363 switch (a
->sa
.sa_family
) {
364 case AF_INET
: a
->sin
.sin_port
= htons(port
); break;
365 case AF_INET6
: a
->sin6
.sin6_port
= htons(port
); break;
370 /*----- That's all, folks -------------------------------------------------*/