chiark / gitweb /
server/admin.c: Remove spurious `ping' in usage message.
[tripe] / server / servutil.c
CommitLineData
410c8acf 1/* -*-c-*-
410c8acf 2 *
3 * Various handy server-only utilities
4 *
5 * (c) 2001 Straylight/Edgeware
6 */
7
e04c2d50 8/*----- Licensing notice --------------------------------------------------*
410c8acf 9 *
10 * This file is part of Trivial IP Encryption (TrIPE).
11 *
11ad66c2
MW
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.
e04c2d50 16 *
11ad66c2
MW
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
20 * for more details.
e04c2d50 21 *
410c8acf 22 * You should have received a copy of the GNU General Public License
11ad66c2 23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
410c8acf 24 */
25
410c8acf 26/*----- Header files ------------------------------------------------------*/
27
28#include "tripe.h"
29
df9dfccf 30/*----- Global variables --------------------------------------------------*/
31
a4b808b0 32octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ], buf_u[PKBUFSZ];
df9dfccf 33
82ba25cf 34/*----- Sequence numbers --------------------------------------------------*/
52b86648 35
37941236 36/* --- @seq_reset@ --- *
37 *
38 * Arguments: @seqwin *s@ = sequence-checking window
39 *
40 * Returns: ---
41 *
42 * Use: Resets a sequence number window.
43 */
44
45void seq_reset(seqwin *s) { s->seq = 0; s->win = 0; }
46
47/* --- @seq_check@ --- *
48 *
49 * Arguments: @seqwin *s@ = sequence-checking window
50 * @uint32 q@ = sequence number to check
f43df819 51 * @const char *service@ = service to report message from
37941236 52 *
f43df819 53 * Returns: Zero on success, nonzero if the sequence number was bad.
37941236 54 *
55 * Use: Checks a sequence number against the window, updating things
56 * as necessary.
57 */
58
f43df819 59int seq_check(seqwin *s, uint32 q, const char *service)
37941236 60{
61 uint32 qbit;
62 uint32 n;
63
f43df819
MW
64 if (q < s->seq) {
65 a_warn(service, "replay", "old-sequence", A_END);
66 return (-1);
67 }
37941236 68 if (q >= s->seq + SEQ_WINSZ) {
69 n = q - (s->seq + SEQ_WINSZ - 1);
70 if (n < SEQ_WINSZ)
71 s->win >>= n;
72 else
73 s->win = 0;
74 s->seq += n;
75 }
76 qbit = 1 << (q - s->seq);
f43df819
MW
77 if (s->win & qbit) {
78 a_warn(service, "replay", "duplicated-sequence", A_END);
79 return (-1);
80 }
37941236 81 s->win |= qbit;
82 return (0);
83}
84
e9fcf28e
MW
85/*----- Rate limiting -----------------------------------------------------*/
86
87/* --- @ratelim_init@ --- *
88 *
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
92 *
93 * Returns: ---
94 *
95 * Use: Initialize a rate-limiting state.
96 */
97
98void ratelim_init(ratelim *r, unsigned persec, unsigned max)
99{
100 r->n = r->max = max;
101 r->persec = persec;
102 gettimeofday(&r->when, 0);
103}
104
105/* --- @ratelim_withdraw@ --- *
106 *
107 * Arguments: @ratelim *r@ = rate-limiting state
108 * @unsigned n@ = credit to withdraw
109 *
110 * Returns: Zero if successful; @-1@ if there is unsufficient credit
111 *
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.
115 */
116
117int ratelim_withdraw(ratelim *r, unsigned n)
118{
119 struct timeval now, delta;
120 unsigned long d;
121
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;
127 else r->n = r->max;
128 r->when = now;
129
130 if (n > r->n) return (-1);
131 else { r->n -= n; return (0); }
132}
133
0c1cede3
MW
134/*----- Crypto ------------------------------------------------------------*/
135
136/* --- @ies_encrypt@ --- *
137 *
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
142 *
143 * Returns: On error, returns a @KSERR_...@ code or breaks the buffer;
144 * on success, returns zero and the buffer is good.
145 *
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
149 * @ks_encrypt@).
150 */
151
152int ies_encrypt(kdata *kpub, unsigned ty, buf *b, buf *bb)
153{
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;
158 octet *len;
159 bulkctx *bulk;
160 deriveargs a;
161 size_t n;
162 buf bk;
163 int rc = 0;
164
165 IF_TRACING(T_CRYPTO, {
166 trace(T_CRYPTO,
167 "crypto: encrypting IES message (type 0x%02x) for recipient `%s'",
168 ty, kpub->tag);
169 trace_block(T_CRYPTO, "crypto: plaintext message", BCUR(b), BLEFT(b));
170 })
171
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);
176 assert(BOK(&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); )
179
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);
187
188end:
189 bulk->ops->freectx(bulk);
190 g->ops->freesc(g, u);
191 g->ops->freege(g, U);
192 g->ops->freege(g, Z);
193 return (rc);
194}
195
196/* --- @ies_decrypt@ --- *
197 *
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
202 *
203 * Returns: On error, returns a @KSERR_...@ code; on success, returns
204 * zero and the buffer is good.
205 *
206 * Use: Decrypts a message encrypted using @ies_encrypt@, given our
207 * private key.
208 */
209
210int ies_decrypt(kdata *kpriv, unsigned ty, buf *b, buf *bb)
211{
212 dhgrp *g = kpriv->grp;
213 bulkalgs *algs = kpriv->algs.bulk;
214 bulkctx *bulk = 0;
215 T( const octet *m; )
216 dhge *U = 0, *Z = 0;
217 deriveargs a;
218 uint32 seq;
219 buf bk, bc;
220 int rc;
221
222 IF_TRACING(T_CRYPTO, {
223 trace(T_CRYPTO,
224 "crypto: decrypting IES message (type 0x%02x) to recipient `%s'",
225 ty, kpriv->tag);
226 trace_block(T_CRYPTO, "crypto: ciphertext message", BCUR(b), BLEFT(b));
227 })
228
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);
234
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); )
241 assert(BOK(&bk));
242
243 bulk = algs->ops->genkeys(algs, &a);
244 bulk->ops = algs->ops;
245 T( m = BCUR(bb); )
246 rc = bulk->ops->decrypt(bulk, ty, &bc, bb, &seq);
247 if (rc) goto end;
248 if (seq) { rc = KSERR_SEQ; goto end; }
249 assert(BOK(bb));
250 T( trace_block(T_CRYPTO, "crypto: decrypted message", m, BCUR(bb) - m); )
251
252end:
253 if (bulk) bulk->ops->freectx(bulk);
254 g->ops->freege(g, U);
255 g->ops->freege(g, Z);
256 return (rc);
257}
258
82ba25cf
MW
259/*----- Random odds and sods ----------------------------------------------*/
260
261/* --- @timestr@ --- *
262 *
263 * Arguments: @time_t t@ = a time to convert
264 *
265 * Returns: A pointer to a textual representation of the time.
266 *
267 * Use: Converts a time to a textual representation. Corrupts
268 * @buf_u@.
269 */
270
271const char *timestr(time_t t)
272{
273 struct tm *tm;
274 if (!t)
275 return ("NEVER");
276 tm = localtime(&t);
277 strftime((char *)buf_u, sizeof(buf_u), "%Y-%m-%dT%H:%M:%S", tm);
278 return ((const char *)buf_u);
279}
280
281/* --- @mystrieq@ --- *
282 *
283 * Arguments: @const char *x, *y@ = two strings
284 *
285 * Returns: True if @x@ and @y are equal, up to case.
286 */
287
288int mystrieq(const char *x, const char *y)
289{
290 for (;;) {
291 if (!*x && !*y) return (1);
292 if (tolower((unsigned char)*x) != tolower((unsigned char)*y))
293 return (0);
294 x++; y++;
295 }
296}
297
5d06f63e
MW
298/*----- Address handling --------------------------------------------------*/
299
300const struct addrfam aftab[] = {
a8211197
MW
301#ifdef HAVE_LIBADNS
302# define DEF(af, qf) { AF_##af, #af, adns_qf_##qf },
303#else
304# define DEF(af, qf) { AF_##af, #af },
305#endif
5d06f63e
MW
306 ADDRFAM(DEF)
307#undef DEF
308};
309
310/* --- @afix@ --- *
311 *
312 * Arguments: @int af@ = an address family code
313 *
314 * Returns: The index of the address family's record in @aftab@, or @-1@.
315 */
316
317int afix(int af)
318{
319 int i;
320
321 for (i = 0; i < NADDRFAM; i++)
322 if (af == aftab[i].af) return (i);
323 return (-1);
324}
325
cb2c2bfc
MW
326/* --- @addrsz@ --- *
327 *
328 * Arguments: @const addr *a@ = a network address
329 *
330 * Returns: The size of the address, for passing into the sockets API.
331 */
332
333socklen_t addrsz(const addr *a)
334{
335 switch (a->sa.sa_family) {
336 case AF_INET: return (sizeof(a->sin));
47828bd9 337 case AF_INET6: return (sizeof(a->sin6));
cb2c2bfc
MW
338 default: abort();
339 }
340}
341
d98625f4
MW
342/* --- @getport@, @setport@ --- *
343 *
344 * Arguments: @addr *a@ = a network address
345 * @unsigned port@ = port number to set
346 *
347 * Returns: ---
348 *
349 * Use: Retrieves or sets the port number in an address structure.
350 */
351
352unsigned getport(addr *a)
353{
354 switch (a->sa.sa_family) {
355 case AF_INET: return (ntohs(a->sin.sin_port)); break;
47828bd9 356 case AF_INET6: return (ntohs(a->sin6.sin6_port)); break;
d98625f4
MW
357 default: abort();
358 }
359}
360
361void setport(addr *a, unsigned port)
362{
363 switch (a->sa.sa_family) {
364 case AF_INET: a->sin.sin_port = htons(port); break;
47828bd9 365 case AF_INET6: a->sin6.sin6_port = htons(port); break;
cb2c2bfc
MW
366 default: abort();
367 }
368}
369
410c8acf 370/*----- That's all, folks -------------------------------------------------*/