Initial version.
[udpkey] / udpkey.c
1 /* -*-c-*-
2 *
3 * Request a key over UDP, or respond to such a request
4 *
5 * (c) 2012 Mark Wooding
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of udpkey.
11 *
12 * The udpkey program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The udpkey program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with udpkey; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40
41 #include <syslog.h>
42
43 #include <sys/socket.h>
44 #include <arpa/inet.h>
45 #include <netinet/in.h>
46 #include <netdb.h>
47
48 #include <mLib/alloc.h>
49 #include <mLib/buf.h>
50 #include <mLib/daemonize.h>
51 #include <mLib/dstr.h>
52 #include <mLib/fdflags.h>
53 #include <mLib/fwatch.h>
54 #include <mLib/hex.h>
55 #include <mLib/mdwopt.h>
56 #include <mLib/quis.h>
57 #include <mLib/report.h>
58 #include <mLib/sub.h>
59 #include <mLib/tv.h>
60
61 #include <catacomb/buf.h>
62 #include <catacomb/dh.h>
63 #include <catacomb/ec.h>
64 #include <catacomb/ec-keys.h>
65 #include <catacomb/gcipher.h>
66 #include <catacomb/gmac.h>
67 #include <catacomb/group.h>
68 #include <catacomb/key.h>
69 #include <catacomb/mp.h>
70 #include <catacomb/mprand.h>
71 #include <catacomb/noise.h>
72 #include <catacomb/rand.h>
73
74 #include <catacomb/rijndael-counter.h>
75 #include <catacomb/sha256.h>
76
77 #ifdef DEBUG
78 # define D(x) x
79 #else
80 # define D(x)
81 #endif
82
83 /*---- Static variables ---------------------------------------------------*/
84
85 static unsigned flags = 0;
86 #define f_bogus 1u
87 #define f_listen 2u
88 #define f_daemon 4u
89 #define f_syslog 8u
90
91 #define BUFSZ 65536
92 static unsigned char ibuf[BUFSZ], obuf[BUFSZ];
93
94 static key_file *kf;
95 static const char *kfname = "keyring";
96 static const char *pidfile;
97 static fwatch kfwatch;
98 static unsigned nq;
99
100 /*----- Miscellaneous utilities -------------------------------------------*/
101
102 /* Resolve NAME, storing the address in *ADDR. Exit on error. */
103 static void resolve(const char *name, struct in_addr *addr)
104 {
105 struct hostent *h;
106
107 if ((h = gethostbyname(name)) == 0)
108 die(1, "failed to resolve `%s': %s", name, hstrerror(h_errno));
109 if (h->h_addrtype != AF_INET)
110 die(1, "unexpected address type %d", h->h_addrtype);
111 memcpy(addr, h->h_addr, sizeof(struct in_addr));
112 }
113
114 /* Convert PORT to a port number (in host byte order). Exit on error. */
115 static unsigned short getport(const char *port)
116 {
117 unsigned long i = 0;
118 char *q;
119 int e = errno;
120
121 errno = 0;
122 if (!isdigit(*port) ||
123 (i = strtoul(port, &q, 0)) == 0 ||
124 i >= 65536 || *q || errno)
125 die(1, "invalid port number `%s'", port);
126 errno = e;
127 return ((unsigned short)i);
128 }
129
130 /* Read the file named by NAME into a buffer -- or at least an initial
131 * portion of it; set *P to the start and *SZ to the length. Return -1 if it
132 * didn't work. The buffer doesn't need to be freed: the data is stashed in
133 * ibuf.
134 */
135 static int snarf(const char *name, void **p, size_t *sz)
136 {
137 ssize_t n;
138 int fd;
139
140 if ((fd = open(name, O_RDONLY)) < 0) return (-1);
141 n = read(fd, ibuf, sizeof(ibuf));
142 close(fd);
143 if (n < 0) return (-1);
144 *p = ibuf; *sz = n;
145 return (0);
146 }
147
148 /* Complain about something. If f_syslog is set then complain to that;
149 * otherwise write to stderr. Don't use `%m' because that won't work when
150 * writing to stderr.
151 */
152 static void complain(int sev, const char *msg, ...)
153 {
154 va_list ap;
155
156 va_start(ap, msg);
157 if (flags & f_syslog)
158 vsyslog(sev, msg, ap);
159 else {
160 fprintf(stderr, "%s: ", QUIS);
161 vfprintf(stderr, msg, ap);
162 fputc('\n', stderr);
163 }
164 }
165
166 /*----- Reading key data --------------------------------------------------*/
167
168 struct kinfo {
169 group *g;
170 ge *X;
171 mp *x;
172 const gccipher *cc;
173 const gcmac *mc; size_t tagsz;
174 const gchash *hc;
175 };
176
177 /* Clear a kinfo structure so it can be freed without trouble. */
178 static void k_init(struct kinfo *k) { k->g = 0; k->x = 0; k->X = 0; }
179
180 /* Free a kinfo structure. This is safe on any initialized kinfo
181 * structure.
182 */
183 static void k_free(struct kinfo *k)
184 {
185 if (k->X) { G_DESTROY(k->g, k->X); k->X = 0; }
186 if (k->x) { MP_DROP(k->x); k->x = 0; }
187 if (k->g) { G_DESTROYGROUP(k->g); k->g = 0; }
188 }
189
190 /* Empty macro arguments are forbidden. But arguments are expended during
191 * replacement, not while the call is being processed, so this hack is OK.
192 * Unfortunately, if a potentially empty argument is passed on to another
193 * macro then it needs to be guarded with a use of EMPTY too...
194 */
195 #define EMPTY
196
197 /* Table of key types. Entries have the form
198 *
199 * _(name, NAME, SETGROUP, SETPRIV, SETPUB)
200 *
201 * The name and NAME are lower- and uppercase names for the type used for
202 * constructing various type name constant names. The code fragment SETGROUP
203 * initializes k->g given the name_{pub,priv} structure in p; SETPRIV and
204 * SETPUB set up k->x and k->X respectively. (In this last case, k->X will
205 * have been created as a group element already.)
206 */
207 #define KEYTYPES(_) \
208 \
209 _(dh, DH, \
210 { k->g = group_prime(&p.dp); }, \
211 { k->x = MP_COPY(p.x); }, \
212 { if (G_FROMINT(k->g, k->X, p.y)) { \
213 complain(LOG_ERR, "bad public key in `%s'", t->buf); \
214 goto fail; \
215 } \
216 }) \
217 \
218 _(ec, EC, \
219 { ec_info ei; const char *e; \
220 if ((e = ec_getinfo(&ei, p.cstr)) != 0) { \
221 complain(LOG_ERR, "bad elliptic curve in `%s': %s", t->buf, e); \
222 goto fail; \
223 } \
224 k->g = group_ec(&ei); \
225 }, \
226 { k->x = MP_COPY(p.x); }, \
227 { if (G_FROMEC(k->g, k->X, &p.p)) { \
228 complain(LOG_ERR, "bad public point in `%s'", t->buf); \
229 goto fail; \
230 } \
231 })
232
233 /* Define load_tywhich, where which is `pub' or `priv', to load a public or
234 * private key. Other parameters are as for the KEYTYPES list above.
235 */
236 #define KLOAD(ty, TY, which, WHICH, setgroup, setpriv, setpub) \
237 static int load_##ty##which(key_data *kd, struct kinfo *k, dstr *t) \
238 { \
239 key_packstruct kps[TY##_##WHICH##FETCHSZ]; \
240 key_packdef *kp; \
241 ty##_##which p; \
242 int rc; \
243 \
244 /* Extract the key data from the keydata. */ \
245 kp = key_fetchinit(ty##_##which##fetch, kps, &p); \
246 if ((rc = key_unpack(kp, kd, t)) != 0) { \
247 complain(LOG_ERR, "failed to unpack key `%s': %s", \
248 t->buf, key_strerror(rc)); \
249 goto fail; \
250 } \
251 \
252 /* Extract the components as abstract group elements. */ \
253 setgroup; \
254 setpriv; \
255 k->X = G_CREATE(k->g); \
256 setpub; \
257 \
258 /* Dispose of stuff we don't need. */ \
259 key_fetchdone(kp); \
260 return (0); \
261 \
262 /* Tidy up after mishaps. */ \
263 fail: \
264 k_free(k); \
265 key_fetchdone(kp); \
266 return (-1); \
267 }
268
269 /* Map over the KEYTYPES to declare the load_tywhich functions using KLOAD
270 * above.
271 */
272 #define KEYTYPE_KLOAD(ty, TY, setgroup, setpriv, setpub) \
273 KLOAD(ty, TY, priv, PRIV, setgroup, setpriv, \
274 { G_EXP(k->g, k->X, k->g->g, k->x); }) \
275 KLOAD(ty, TY, pub, PUB, setgroup, { }, setpub)
276 KEYTYPES(KEYTYPE_KLOAD)
277
278 /* Define a table of group key-loading operations. */
279 struct kload_ops {
280 const char *name;
281 int (*loadpriv)(key_data *, struct kinfo *, dstr *);
282 int (*loadpub)(key_data *, struct kinfo *, dstr *);
283 };
284
285 static const struct kload_ops kload_ops[] = {
286 #define KEYTYPE_OPS(ty, TY, setgroup, setpriv, setpub) \
287 { #ty, load_##ty##priv, load_##ty##pub },
288 KEYTYPES(KEYTYPE_OPS)
289 { 0 }
290 };
291
292 /* Load a private or public (indicated by PRIVP) key named TAG into a kinfo
293 * structure K. Also fill in the cipher suite selections extracted from the
294 * key attributes.
295 */
296 static int loadkey(const char *tag, struct kinfo *k, int privp)
297 {
298 const struct kload_ops *ops;
299 dstr d = DSTR_INIT, dd = DSTR_INIT;
300 key *ky;
301 key_data **kd;
302 const char *ty, *p;
303 char *q;
304 int tsz;
305 int rc;
306
307 /* Find the key data. */
308 if (key_qtag(kf, tag, &d, &ky, &kd)) {
309 complain(LOG_ERR, "unknown key tag `%s'", tag);
310 goto fail;
311 }
312
313 /* Find the key's group type and locate the group operations. */
314 ty = key_getattr(kf, ky, "group");
315 if (!ty && strncmp(ky->type, "udpkey-", 7) == 0) ty = ky->type + 7;
316 if (!ty) {
317 complain(LOG_ERR, "no group type for key %s", d.buf);
318 goto fail;
319 }
320 for (ops = kload_ops; ops->name; ops++) {
321 if (strcmp(ty, ops->name) == 0)
322 goto found;
323 }
324 complain(LOG_ERR, "unknown group type `%s' in key %s", ty, d.buf);
325 goto fail;
326
327 found:
328 /* Extract the key data into an appropriately abstract form. */
329 k->g = 0; k->x = 0; k->X = 0;
330 if ((rc = (privp ? ops->loadpriv : ops->loadpub)(*kd, k, &d)) != 0)
331 goto fail;
332
333 /* Extract the chosen symmetric cipher. */
334 if ((p = key_getattr(kf, ky, "cipher")) == 0)
335 k->cc = &rijndael_counter;
336 else if ((k->cc = gcipher_byname(p)) == 0) {
337 complain(LOG_ERR, "unknown cipher `%s' in key %s", p, d.buf);
338 goto fail;
339 }
340
341 /* And the chosen hash function. */
342 if ((p = key_getattr(kf, ky, "hash")) == 0)
343 k->hc = &sha256;
344 else if ((k->hc = ghash_byname(p)) == 0) {
345 complain(LOG_ERR, "unknown hash `%s' in key %s", p, d.buf);
346 goto fail;
347 }
348
349 /* And finally a MAC. This is more fiddly because we must handle (a)
350 * truncation and (b) defaulting based on the hash.
351 */
352 if ((p = key_getattr(kf, ky, "mac")) == 0)
353 dstr_putf(&dd, "%s-hmac", k->hc->name);
354 else
355 dstr_puts(&dd, p);
356 if ((q = strchr(dd.buf, '/')) != 0) *q++ = 0;
357 else q = 0;
358 if ((k->mc = gmac_byname(dd.buf)) == 0) {
359 complain(LOG_ERR, "unknown mac `%s' in key %s", dd.buf, d.buf);
360 goto fail;
361 }
362 if (!q)
363 k->tagsz = k->mc->hashsz/2;
364 else {
365 tsz = atoi(q);
366 if (tsz <= 0 || tsz%8 || tsz/8 > k->mc->hashsz) {
367 complain(LOG_ERR, "bad tag size for mac `%s' in key %s",
368 q, k->mc->name, d.buf);
369 goto fail;
370 }
371 k->tagsz = tsz/8;
372 }
373
374 /* Done. */
375 rc = 0;
376 goto done;
377
378 fail:
379 rc = -1;
380 done:
381 dstr_destroy(&d);
382 dstr_destroy(&dd);
383 return (rc);
384 }
385
386 static void keymoan(const char *file, int line, const char *err, void *p)
387 { complain(LOG_ERR, "%s:%d: %s", file, line, err); }
388
389 /* Update the keyring `kf' if the file has been changed since we last looked.
390 */
391 static void kfupdate(void)
392 {
393 key_file *kfnew;
394
395 if (!fwatch_update(&kfwatch, kfname)) return;
396 kfnew = CREATE(key_file);
397 if (key_open(kfnew, kfname, KOPEN_READ, keymoan, 0)) {
398 DESTROY(kfnew);
399 return;
400 }
401 key_close(kf);
402 DESTROY(kf);
403 kf = kfnew;
404 }
405
406 /*----- Low-level crypto operations ---------------------------------------*/
407
408 /* Derive a key, writing its address to *KK and size to *N. The size is
409 * compatible with the keysz rules KSZ. It is generated for the purpose of
410 * keying a WHAT (used for key separation and in error messages), and NAME is
411 * the name of the specific instance (e.g., `twofish-counter') from the class
412 * name. The kinfo structure K tells us which algorithms to use for the
413 * derivation. The group elements U and Z are the cryptographic inputs
414 * for the derivation.
415 *
416 * Basically all we do is compute H(what || U || Z).
417 */
418 static int derive(struct kinfo *k, ge *U, ge *Z,
419 const char *what, const char *name, const octet *ksz,
420 octet **kk, size_t *n)
421 {
422 buf b;
423 ghash *h;
424 octet *p;
425
426 /* Find a suitable key size. */
427 if ((*n = keysz(k->hc->hashsz, ksz)) == 0) {
428 complain(LOG_ERR,
429 "failed to find suitable key size for %s `%s' and hash `%s'",
430 what, name, k->hc->name);
431 return (-1);
432 }
433
434 /* Build the hash preimage. */
435 buf_init(&b, obuf, sizeof(obuf));
436 buf_put(&b, "udpkey-", 7);
437 buf_putstrz(&b, what);
438 G_TORAW(k->g, &b, U);
439 G_TORAW(k->g, &b, Z);
440 if (BBAD(&b)) {
441 complain(LOG_ERR, "overflow while deriving key (prepare preimage)!");
442 return (-1);
443 }
444
445 /* Derive the output key. */
446 h = GH_INIT(k->hc);
447 GH_HASH(h, BBASE(&b), BLEN(&b));
448 buf_init(&b, obuf, sizeof(obuf));
449 if ((p = buf_get(&b, h->ops->c->hashsz)) == 0) {
450 complain(LOG_ERR, "overflow while deriving key (output hash)!");
451 GH_DESTROY(h);
452 return (-1);
453 }
454 GH_DONE(h, p);
455 GH_DESTROY(h);
456 *kk = p;
457 return (0);
458 }
459
460 #ifdef DEBUG
461 static void debug_mp(const char *what, mp *x)
462 { fprintf(stderr, "%s: *** ", QUIS); MP_EPRINT(what, x); }
463 static void debug_ge(const char *what, group *g, ge *X)
464 {
465 fprintf(stderr, "%s: *** %s = ", QUIS, what);
466 group_writefile(g, X, stderr);
467 fputc('\n', stderr);
468 }
469 #endif
470
471 /*----- Listening for requests --------------------------------------------*/
472
473 /* Rate limiting parameters.
474 *
475 * There's a probabilistic rate-limiting mechanism. A counter starts at 0.
476 * Every time we oricess a request, we increment the counter. The counter
477 * drops by RATE_REFILL every second. If the counter is below RATE_CREDIT
478 * then the request is processed; otherwise it is processed with probability
479 * 1/(counter - RATE_CREDIT).
480 */
481 #define RATE_REFILL 10 /* Credits per second. */
482 #define RATE_CREDIT 1000 /* Initial credit. */
483
484 static int dolisten(int argc, char *argv[])
485 {
486 int sk;
487 char *p, *q, ch;
488 const char *pp;
489 char *aspec;
490 ssize_t n;
491 size_t sz;
492 fd_set fdin;
493 struct sockaddr_in sin;
494 struct in_addr in;
495 int mlen;
496 socklen_t len;
497 buf bin, bout;
498 dstr d = DSTR_INIT, dd = DSTR_INIT;
499 FILE *fp = 0;
500 key *ky;
501 key_data **kkd;
502 mp *r = MP_NEW, *v = MP_NEW;
503 ge *R = 0, *U = 0, *V = 0, *W = 0, *Y = 0, *Z = 0;
504 ghash *h = 0;
505 gmac *m = 0;
506 gcipher *c = 0;
507 octet *kk, *t, *tt;
508 size_t ksz;
509 struct kinfo k;
510 unsigned bucket = 0, toks;
511 time_t last = 0, now;
512
513 /* Set up the socket address. */
514 sin.sin_family = AF_INET;
515 aspec = xstrdup(argv[0]);
516 if ((p = strchr(aspec, ':')) == 0) {
517 p = aspec;
518 sin.sin_addr.s_addr = INADDR_ANY;
519 } else {
520 *p++ = 0;
521 resolve(aspec, &sin.sin_addr);
522 }
523 sin.sin_port = htons(getport(p));
524
525 /* Create and set up the socket itself. */
526 if ((sk = socket(PF_INET, SOCK_DGRAM, 0)) < 0 ||
527 fdflags(sk, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC) ||
528 bind(sk, (struct sockaddr *)&sin, sizeof(sin)))
529 die(1, "failed to create socket: %s", strerror(errno));
530
531 /* That's enough initialization. If we should fork, then do that. */
532 if (flags & f_daemon) {
533 if (pidfile && (fp = fopen(pidfile, "w")) == 0)
534 die(1, "failed to open pidfile `%s': %s", pidfile, strerror(errno));
535 openlog(QUIS, LOG_PID, LOG_DAEMON);
536 if (daemonize())
537 die(1, "failed to become background process: %s", strerror(errno));
538 if (pidfile) { fprintf(fp, "%ld\n", (long)getpid()); fclose(fp); }
539 flags |= f_syslog;
540 }
541
542 for (;;) {
543
544 /* Clear out the key state. */
545 k_init(&k);
546
547 /* Wait for something to happen. */
548 FD_ZERO(&fdin);
549 FD_SET(sk, &fdin);
550 if (select(sk + 1, &fdin, 0, 0, 0) < 0)
551 die(1, "select failed: %s", strerror(errno));
552 noise_timer(RAND_GLOBAL);
553
554 /* Fetch a packet. */
555 len = sizeof(sin);
556 n = recvfrom(sk, ibuf, sizeof(ibuf), 0, (struct sockaddr *)&sin, &len);
557 if (n < 0) {
558 if (errno != EAGAIN && errno != EINTR)
559 complain(LOG_ERR, "unexpected receive error: %s", strerror(errno));
560 goto again;
561 }
562
563 /* Refill the bucket, and see whether we should reject this packet. */
564 now = time(0);
565 if (bucket && now != last) {
566 toks = (now - last)*RATE_REFILL;
567 bucket = bucket < toks ? 0 : bucket - toks;
568 }
569 last = now;
570 if (bucket > RATE_CREDIT &&
571 grand_range(&rand_global, bucket - RATE_CREDIT))
572 goto again;
573 bucket++;
574
575 /* Set up the input buffer for parsing the request. */
576 buf_init(&bin, ibuf, n);
577
578 /* Extract the key tag name. */
579 if ((p = buf_getmemz(&bin, &sz)) == 0) {
580 complain(LOG_WARNING, "invalid key tag from %s:%d",
581 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
582 goto again;
583 }
584
585 /* Find the key. */
586 kfupdate();
587 if (key_qtag(kf, p, &d, &ky, &kkd)) {
588 complain(LOG_WARNING, "unknown key tag `%s' from %s:%d",
589 p, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
590 goto again;
591 }
592
593 /* And make sure that it has the right shape. */
594 if ((ky->k->e & KF_ENCMASK) != KENC_BINARY) {
595 complain(LOG_ERR, "key %s is not plain binary data", d.buf);
596 goto again;
597 }
598
599 /* Find the list of clients, and look up the caller's address in the
600 * list. Entries have the form ADDRESS[/LEN][=TAG] and are separated by
601 * `;'.
602 */
603 if ((pp = key_getattr(kf, ky, "clients")) == 0) {
604 complain(LOG_WARNING,
605 "key %s requested from %s:%d has no `clients' attribute",
606 d.buf, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
607 goto again;
608 }
609 dstr_puts(&dd, pp);
610 p = dd.buf;
611 while (*p) {
612 q = p;
613 while (isdigit((unsigned char)*q) || *q == '.') q++;
614 ch = *q; *q++ = 0;
615 if (!inet_aton(p, &in)) goto skip;
616 if (ch != '/')
617 mlen = 32;
618 else {
619 p = q;
620 while (isdigit((unsigned char)*q)) q++;
621 ch = *q; *q++ = 0;
622 mlen = atoi(p);
623 }
624 if (((sin.sin_addr.s_addr ^ in.s_addr) &
625 (0xffffffff << (32 - mlen))) == 0)
626 goto match;
627 skip:
628 if (!ch) break;
629 p = q;
630 while (*p && *p != ';') p++;
631 if (*p) p++;
632 }
633 complain(LOG_WARNING, "access to key %s denied to %s:%d",
634 d.buf, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
635 goto again;
636
637 match:
638 /* Build a tag name for the caller's KEM key, either from the client
639 * match or the source address.
640 */
641 if (ch != '=') {
642 DRESET(&dd);
643 dstr_puts(&dd, "client-");
644 dstr_puts(&dd, inet_ntoa(sin.sin_addr));
645 p = dd.buf;
646 } else {
647 p = q;
648 while (*q && *q != ';') q++;
649 if (*q == ';') *q++ = 0;
650 }
651
652 /* Report the match. */
653 complain(LOG_NOTICE, "client %s:%d (`%s') requests key %s",
654 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), p, d.buf);
655
656 /* Load the KEM key. */
657 if (loadkey(p, &k, 0)) goto again;
658 D( debug_ge("X", k.g, k.X); )
659
660 /* Read the caller's ephemeral key. */
661 R = G_CREATE(k.g); W = G_CREATE(k.g);
662 U = G_CREATE(k.g); V = G_CREATE(k.g);
663 Y = G_CREATE(k.g); Z = G_CREATE(k.g);
664 if (G_FROMBUF(k.g, &bin, U)) {
665 complain(LOG_WARNING, "failed to read ephemeral vector from %s:%d",
666 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
667 goto again;
668 }
669 D( debug_ge("U", k.g, U); )
670 if (BLEFT(&bin)) {
671 complain(LOG_WARNING, "trailing junk in request from %s:%d",
672 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
673 goto again;
674 }
675
676 /* Ephemeral Diffie--Hellman. Choose v in GF(q) at random; compute
677 * V = v P and -Y = (-v) U.
678 */
679 v = mprand_range(v, k.g->r, &rand_global, 0);
680 G_EXP(k.g, V, k.g->g, v);
681 D( debug_mp("v", v); debug_ge("V", k.g, V); )
682 v = mp_sub(v, k.g->r, v);
683 G_EXP(k.g, Y, U, v);
684 D( debug_ge("-Y", k.g, Y); )
685
686 /* DLIES. Choose r in GF(q) at random; compute R = r P and Z = r X.
687 * Mask the clue R as W = R - Y. (Doing the subtraction here makes life
688 * easier at the other end, since we can determine -Y by negating v
689 * whereas the recipient must subtract vectors which may be less
690 * efficient.)
691 */
692 r = mprand_range(r, k.g->r, &rand_global, 0);
693 G_EXP(k.g, R, k.g->g, r);
694 D( debug_mp("r", r); debug_ge("R", k.g, R); )
695 G_EXP(k.g, Z, k.X, r);
696 G_MUL(k.g, W, R, Y);
697 D( debug_ge("Z", k.g, Z); debug_ge("W", k.g, W); )
698
699 /* Derive encryption and integrity keys. */
700 derive(&k, R, Z, "cipher", k.cc->name, k.cc->keysz, &kk, &ksz);
701 c = GC_INIT(k.cc, kk, ksz);
702 derive(&k, R, Z, "mac", k.mc->name, k.mc->keysz, &kk, &ksz);
703 m = GM_KEY(k.mc, kk, ksz);
704
705 /* Build the ciphertext and compute a MAC tag over it. */
706 buf_init(&bout, obuf, sizeof(obuf));
707 if (G_TOBUF(k.g, &bout, V) ||
708 G_TOBUF(k.g, &bout, W))
709 goto bad;
710 if ((t = buf_get(&bout, k.tagsz)) == 0) goto bad;
711 sz = ky->k->u.k.sz;
712 if (BENSURE(&bout, sz)) goto bad;
713 GC_ENCRYPT(c, ky->k->u.k.k, BCUR(&bout), sz);
714 h = GM_INIT(m);
715 GH_HASH(h, BCUR(&bout), sz);
716 tt = GH_DONE(h, 0); memcpy(t, tt, k.tagsz);
717 BSTEP(&bout, sz);
718
719 /* Send the reply packet back to the caller. */
720 if (sendto(sk, BBASE(&bout), BLEN(&bout), 0,
721 (struct sockaddr *)&sin, len) < 0) {
722 complain(LOG_ERR, "failed to send response to %s:%d: %s",
723 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port),
724 strerror(errno));
725 goto again;
726 }
727
728 goto again;
729
730 bad:
731 /* Report a problem building the reply. */
732 complain(LOG_ERR, "failed to construct response to %s:%d",
733 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
734
735 again:
736 /* Free stuff for the next iteration. */
737 DRESET(&d); DRESET(&dd);
738 if (R) { G_DESTROY(k.g, R); R = 0; }
739 if (U) { G_DESTROY(k.g, U); U = 0; }
740 if (V) { G_DESTROY(k.g, V); V = 0; }
741 if (W) { G_DESTROY(k.g, W); W = 0; }
742 if (Y) { G_DESTROY(k.g, Y); Y = 0; }
743 if (Z) { G_DESTROY(k.g, Z); Z = 0; }
744 if (c) { GC_DESTROY(c); c = 0; }
745 if (m) { GM_DESTROY(m); m = 0; }
746 if (h) { GH_DESTROY(h); h = 0; }
747 k_free(&k);
748 }
749
750 return (-1);
751 }
752
753 /*----- Sending requests and processing responses -------------------------*/
754
755 struct query {
756 struct query *next;
757 octet *k;
758 size_t sz;
759 struct server *s;
760 };
761
762 struct server {
763 struct server *next;
764 struct sockaddr_in sin;
765 struct kinfo k;
766 mp *u;
767 ge *U;
768 octet *h;
769 };
770
771 /* Record a successful fetch of key material for a query Q. The data starts
772 * at K and is SZ bytes long. The data is copied: it's safe to overwrite it.
773 */
774 static void donequery(struct query *q, const void *k, size_t sz)
775 { q->k = xmalloc(sz); memcpy(q->k, k, sz); q->sz = sz; nq--; }
776
777 /* Initialize a query to a remote server. */
778 static struct query *qinit_net(const char *tag, const char *spec)
779 {
780 struct query *q;
781 struct server *s, **stail;
782 dstr d = DSTR_INIT, dd = DSTR_INIT;
783 hex_ctx hc;
784 char *p, *pp, ch;
785
786 /* Allocate the query block. */
787 q = CREATE(struct query);
788 stail = &q->s;
789
790 /* Put the spec somewhere we can hack at it. */
791 dstr_puts(&d, spec);
792 p = d.buf;
793
794 /* Parse the query spec. Entries have the form ADDRESS:PORT[=TAG][#HASH]
795 * and are separated by `;'.
796 */
797 while (*p) {
798
799 /* Allocate a new server node. */
800 s = CREATE(struct server);
801 s->sin.sin_family = AF_INET;
802
803 /* Extract the server address. */
804 if ((pp = strchr(p, ':')) == 0)
805 die(1, "invalid syntax: missing `:PORT'");
806 *pp++ = 0;
807 resolve(p, &s->sin.sin_addr);
808
809 /* Extract the port number. */
810 p = pp;
811 while (isdigit((unsigned char)*pp)) pp++;
812 ch = *pp; *pp++ = 0;
813 s->sin.sin_port = htons(getport(p));
814
815 /* If there's a key tag then extract that; otherwise use a default. */
816 if (ch != '=')
817 p = "udpkey-kem";
818 else {
819 p = pp;
820 pp += strcspn(pp, ";#");
821 ch = *pp; *pp++ = 0;
822 }
823 if (loadkey(p, &s->k, 1)) exit(1);
824 D( debug_mp("x", s->k.x); debug_ge("X", s->k.g, s->k.X); )
825
826 /* Choose an ephemeral private key u. Let x be our private key. We
827 * compute U = u P and transmit this.
828 */
829 s->u = mprand_range(MP_NEW, s->k.g->r, &rand_global, 0);
830 s->U = G_CREATE(s->k.g);
831 G_EXP(s->k.g, s->U, s->k.g->g, s->u);
832 D( debug_mp("u", s->u); debug_ge("U", s->k.g, s->U); )
833
834 /* Link the server on. */
835 *stail = s; stail = &s->next;
836
837 /* If there's a trailing hash then extract it. */
838 if (ch != '#')
839 s->h = 0;
840 else {
841 p = pp;
842 while (*pp == '-' || isxdigit((unsigned char)*pp)) pp++;
843 hex_init(&hc);
844 DRESET(&dd);
845 hex_decode(&hc, p, pp - p, &dd);
846 if (dd.len != s->k.hc->hashsz) die(1, "incorrect hash length");
847 s->h = xmalloc(dd.len);
848 memcpy(s->h, dd.buf, dd.len);
849 ch = *pp++;
850 }
851
852 /* If there are more servers, then continue parsing. */
853 if (!ch) break;
854 else if (ch != ';') die(1, "invalid syntax: expected `;'");
855 p = pp;
856 }
857
858 /* Terminate the server list and return. */
859 *stail = 0;
860 q->k = 0;
861 dstr_destroy(&d);
862 dstr_destroy(&dd);
863 return (q);
864 }
865
866 /* Handle a `query' to a local file. */
867 static struct query *qinit_file(const char *tag, const char *file)
868 {
869 struct query *q;
870 void *k;
871 size_t sz;
872
873 /* Snarf the file. */
874 q = CREATE(struct query);
875 if (snarf(file, &k, &sz))
876 die(1, "failed to read `%s': %s", file, strerror(errno));
877 q->s = 0;
878 donequery(q, k, sz);
879 return (q);
880 }
881
882 /* Reransmission and timeout parameters. */
883 #define TO_NEXT(t) (((t) + 2)*4/3) /* Timeout growth function */
884 #define TO_MAX 30 /* When to give up */
885
886 static int doquery(int argc, char *argv[])
887 {
888 struct query *q = 0, *qq, **qtail = &qq;
889 struct server *s = 0;
890 const char *tag = argv[0];
891 octet *p;
892 int i;
893 int sk;
894 fd_set fdin;
895 struct timeval now, when, tv;
896 struct sockaddr_in sin;
897 ge *R, *V = 0, *W = 0, *Y = 0, *Z = 0;
898 octet *kk, *t, *tt;
899 gcipher *c = 0;
900 gmac *m = 0;
901 ghash *h = 0;
902 socklen_t len;
903 unsigned next = 0;
904 buf bin, bout;
905 size_t n, j, ksz;
906 ssize_t nn;
907
908 /* Create a socket. We just use the one socket for everything. We don't
909 * care which port we get allocated.
910 */
911 if ((sk = socket(PF_INET, SOCK_DGRAM, 0)) < 0 ||
912 fdflags(sk, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC))
913 die(1, "failed to create socket: %s", strerror(errno));
914
915 /* Parse the query target specifications. The adjustments of `nq' aren't
916 * in the right order but that doesn't matter.
917 */
918 for (i = 1; i < argc; i++) {
919 if (*argv[i] == '.' || *argv[i] == '/') q = qinit_file(tag, argv[i]);
920 else if (strchr(argv[i], ':')) q = qinit_net(tag, argv[i]);
921 else die(1, "unrecognized query target `%s'", argv[i]);
922 *qtail = q; qtail = &q->next; nq++;
923 }
924 *qtail = 0;
925
926 /* Find the current time so we can compute retransmission times properly.
927 */
928 gettimeofday(&now, 0);
929 when = now;
930
931 /* Continue retransmitting until we have all the answers. */
932 while (nq) {
933
934 /* Work out when we next want to wake up. */
935 if (TV_CMP(&now, >=, &when)) {
936 do {
937 if (next >= TO_MAX) die(1, "no responses: giving up");
938 next = TO_NEXT(next);
939 TV_ADDL(&when, &when, next, 0);
940 } while (TV_CMP(&when, <=, &now));
941 for (q = qq; q; q = q->next) {
942 if (q->k) continue;
943 for (s = q->s; s; s = s->next) {
944 buf_init(&bout, obuf, sizeof(obuf));
945 buf_putstrz(&bout, tag);
946 G_TOBUF(s->k.g, &bout, s->U);
947 if (BBAD(&bout)) {
948 moan("overflow while constructing request!");
949 continue;
950 }
951 sendto(sk, BBASE(&bout), BLEN(&bout), 0,
952 (struct sockaddr *)&s->sin, sizeof(s->sin));
953 }
954 }
955 }
956
957 /* Wait until something interesting happens. */
958 FD_ZERO(&fdin);
959 FD_SET(sk, &fdin);
960 TV_SUB(&tv, &when, &now);
961 if (select(sk + 1, &fdin, 0, 0, &tv) < 0)
962 die(1, "select failed: %s", strerror(errno));
963 gettimeofday(&now, 0);
964
965 /* If we have an input event, process incoming packets. */
966 if (FD_ISSET(sk, &fdin)) {
967 for (;;) {
968
969 /* Read a packet and capture its address. */
970 len = sizeof(sin);
971 nn = recvfrom(sk, ibuf, sizeof(ibuf), 0,
972 (struct sockaddr *)&sin, &len);
973 if (nn < 0) {
974 if (errno == EAGAIN) break;
975 else if (errno == EINTR) continue;
976 else {
977 moan("error receiving reply: %s", strerror(errno));
978 goto again;
979 }
980 }
981
982 /* Wee whether this corresponds to any of our servers. Don't just
983 * check the active servers, since this may be late replies caused by
984 * retransmissions or similar.
985 */
986 for (q = qq; q; q = q->next) {
987 for (s = q->s; s; s = s->next) {
988 if (s->sin.sin_addr.s_addr == sin.sin_addr.s_addr &&
989 s->sin.sin_port == sin.sin_port)
990 goto found;
991 }
992 }
993 moan("received reply from unexpected source %s:%d",
994 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
995 goto again;
996
997 found:
998 /* If the query we found has now been satisfied, ignore this packet.
999 */
1000 if (q->k) goto again;
1001
1002 /* Start parsing the reply. */
1003 buf_init(&bin, ibuf, nn);
1004 R = G_CREATE(s->k.g);
1005 V = G_CREATE(s->k.g); W = G_CREATE(s->k.g);
1006 Y = G_CREATE(s->k.g); Z = G_CREATE(s->k.g);
1007 if (G_FROMBUF(s->k.g, &bin, V)) {
1008 moan("invalid Diffie--Hellman vector from %s:%d",
1009 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
1010 goto again;
1011 }
1012 if (G_FROMBUF(s->k.g, &bin, W)) {
1013 moan("invalid clue vector from %s:%d",
1014 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
1015 goto again;
1016 }
1017 D( debug_ge("V", s->k.g, V); debug_ge("W", s->k.g, W); )
1018
1019 /* We have V and W from the server; determine Y = u V, R = W + Y and
1020 * Z = x R, and then derive the symmetric keys.
1021 */
1022 G_EXP(s->k.g, Y, V, s->u);
1023 G_MUL(s->k.g, R, W, Y);
1024 G_EXP(s->k.g, Z, R, s->k.x);
1025 D( debug_ge("R", s->k.g, R);
1026 debug_ge("Y", s->k.g, Y);
1027 debug_ge("Z", s->k.g, Z); )
1028 derive(&s->k, R, Z, "cipher", s->k.cc->name, s->k.cc->keysz,
1029 &kk, &ksz);
1030 c = GC_INIT(s->k.cc, kk, ksz);
1031 derive(&s->k, R, Z, "mac", s->k.cc->name, s->k.cc->keysz,
1032 &kk, &ksz);
1033 m = GM_KEY(s->k.mc, kk, ksz);
1034
1035 /* Find where the MAC tag is. */
1036 if ((t = buf_get(&bin, s->k.tagsz)) == 0) {
1037 moan("missing tag from %s:%d",
1038 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
1039 goto again;
1040 }
1041
1042 /* Check the integrity of the ciphertext against the tag. */
1043 p = BCUR(&bin); n = BLEFT(&bin);
1044 h = GM_INIT(m);
1045 GH_HASH(h, p, n);
1046 tt = GH_DONE(h, 0);
1047 if (memcmp(t, tt, s->k.tagsz) != 0) {
1048 moan("incorrect tag from %s:%d",
1049 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
1050 goto again;
1051 }
1052
1053 /* Decrypt the result and declare this server done. */
1054 GC_DECRYPT(c, p, p, n);
1055 if (s->h) {
1056 GH_DESTROY(h);
1057 h = GH_INIT(s->k.hc);
1058 GH_HASH(h, p, n);
1059 tt = GH_DONE(h, 0);
1060 if (memcmp(tt, s->h, h->ops->c->hashsz) != 0) {
1061 moan("response from %s:%d doesn't match hash",
1062 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
1063 goto again;
1064 }
1065 }
1066 donequery(q, p, n);
1067
1068 again:
1069 /* Tidy things up for the next run through. */
1070 if (R) { G_DESTROY(s->k.g, R); R = 0; }
1071 if (V) { G_DESTROY(s->k.g, V); V = 0; }
1072 if (W) { G_DESTROY(s->k.g, W); W = 0; }
1073 if (Y) { G_DESTROY(s->k.g, Y); Y = 0; }
1074 if (Z) { G_DESTROY(s->k.g, Z); Z = 0; }
1075 if (c) { GC_DESTROY(c); c = 0; }
1076 if (m) { GM_DESTROY(m); m = 0; }
1077 if (h) { GH_DESTROY(h); h = 0; }
1078 }
1079 }
1080 }
1081
1082 /* Check that all of the responses match up and XOR them together. */
1083 n = qq->sz;
1084 if (n > BUFSZ) die(1, "response too large");
1085 memset(obuf, 0, n);
1086 for (q = qq; q; q = q->next) {
1087 if (!q->k) die(1, "INTERNAL: query not complete");
1088 if (q->sz != n) die(1, "inconsistent response sizes");
1089 for (j = 0; j < n; j++) obuf[j] ^= q->k[j];
1090 }
1091
1092 /* Write out the completed answer. */
1093 p = obuf;
1094 while (n) {
1095 if ((nn = write(STDOUT_FILENO, p, n)) < 0)
1096 die(1, "error writing response: %s", strerror(errno));
1097 p += nn; n -= nn;
1098 }
1099 return (0);
1100 }
1101
1102 /*----- Main program ------------------------------------------------------*/
1103
1104 static void usage(FILE *fp)
1105 {
1106 pquis(fp, "Usage: \n\
1107 $ [-OPTS] LABEL {ADDR:PORT | FILE} ...\n\
1108 $ [-OPTS] -l [ADDR:]PORT\n\
1109 ");
1110 }
1111
1112 static void version(FILE *fp)
1113 { pquis(fp, "$, version " VERSION); }
1114
1115 static void help(FILE *fp)
1116 {
1117 version(fp);
1118 putc('\n', fp);
1119 usage(fp);
1120 fputs("\n\
1121 Options:\n\
1122 \n\
1123 -d, --daemon Run in the background while listening.\n\
1124 -k, --keyring=FILE Read keys from FILE. [default = `keyring']\n\
1125 -l, --listen Listen for incoming requests and serve keys.\n\
1126 -p, --pidfile=FILE Write process id to FILE if in daemon mode.\n\
1127 -r, --random=FILE Key random number generator with contents of FILE.\n\
1128 ", fp);
1129 }
1130
1131 int main(int argc, char *argv[])
1132 {
1133 int argmin, argmax;
1134 void *k;
1135 size_t sz;
1136
1137 ego(argv[0]);
1138 for (;;) {
1139 static const struct option opts[] = {
1140 { "help", 0, 0, 'h' },
1141 { "version", 0, 0, 'v' },
1142 { "usage", 0, 0, 'u' },
1143 { "daemon", 0, 0, 'd' },
1144 { "keyfile", OPTF_ARGREQ, 0, 'k' },
1145 { "listen", 0, 0, 'l' },
1146 { "pidfile", OPTF_ARGREQ, 0, 'p' },
1147 { "random", OPTF_ARGREQ, 0, 'r' },
1148 { 0 }
1149 };
1150
1151 int i = mdwopt(argc, argv, "hvu" "dk:lp:r:", opts, 0, 0, 0);
1152 if (i < 0) break;
1153
1154 switch (i) {
1155 case 'h': help(stdout); exit(0);
1156 case 'v': version(stdout); exit(0);
1157 case 'u': usage(stdout); exit(0);
1158
1159 case 'd': flags |= f_daemon; break;
1160 case 'k': kfname = optarg; break;
1161 case 'l': flags |= f_listen; break;
1162 case 'p': pidfile = optarg; break;
1163 case 'r':
1164 if (snarf(optarg, &k, &sz))
1165 die(1, "failed to read `%s': %s", optarg, strerror(errno));
1166 rand_key(RAND_GLOBAL, k, sz);
1167 break;
1168
1169 default: flags |= f_bogus; break;
1170 }
1171 }
1172
1173 argv += optind; argc -= optind;
1174 if (flags & f_listen) argmin = argmax = 1;
1175 else argmin = 2, argmax = -1;
1176 if ((flags & f_bogus) || argc < argmin || (argmax >= 0 && argc > argmax))
1177 { usage(stderr); exit(1); }
1178
1179 fwatch_init(&kfwatch, kfname);
1180 kf = CREATE(key_file);
1181 if (key_open(kf, kfname, KOPEN_READ, keymoan, 0))
1182 die(1, "failed to open keyring file `%s'", kfname);
1183
1184 rand_noisesrc(RAND_GLOBAL, &noise_source);
1185 rand_seed(RAND_GLOBAL, 512);
1186
1187 if (flags & f_listen) return dolisten(argc, argv);
1188 else return doquery(argc, argv);
1189 }
1190
1191 /*----- That's all, folks -------------------------------------------------*/