chiark / gitweb /
Found in crybaby's working tree.
[udpkey] / udpkey.c
CommitLineData
247f344a
MW
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>
a5f873be 62#include <catacomb/ct.h>
247f344a
MW
63#include <catacomb/dh.h>
64#include <catacomb/ec.h>
65#include <catacomb/ec-keys.h>
66#include <catacomb/gcipher.h>
67#include <catacomb/gmac.h>
68#include <catacomb/group.h>
69#include <catacomb/key.h>
70#include <catacomb/mp.h>
71#include <catacomb/mprand.h>
72#include <catacomb/noise.h>
73#include <catacomb/rand.h>
74
75#include <catacomb/rijndael-counter.h>
76#include <catacomb/sha256.h>
77
78#ifdef DEBUG
79# define D(x) x
80#else
81# define D(x)
82#endif
83
84/*---- Static variables ---------------------------------------------------*/
85
86static unsigned flags = 0;
87#define f_bogus 1u
88#define f_listen 2u
89#define f_daemon 4u
90#define f_syslog 8u
91
92#define BUFSZ 65536
93static unsigned char ibuf[BUFSZ], obuf[BUFSZ];
94
95static key_file *kf;
96static const char *kfname = "keyring";
97static const char *pidfile;
98static fwatch kfwatch;
99static unsigned nq;
100
101/*----- Miscellaneous utilities -------------------------------------------*/
102
103/* Resolve NAME, storing the address in *ADDR. Exit on error. */
104static void resolve(const char *name, struct in_addr *addr)
105{
106 struct hostent *h;
107
108 if ((h = gethostbyname(name)) == 0)
109 die(1, "failed to resolve `%s': %s", name, hstrerror(h_errno));
110 if (h->h_addrtype != AF_INET)
111 die(1, "unexpected address type %d", h->h_addrtype);
112 memcpy(addr, h->h_addr, sizeof(struct in_addr));
113}
114
115/* Convert PORT to a port number (in host byte order). Exit on error. */
116static unsigned short getport(const char *port)
117{
118 unsigned long i = 0;
119 char *q;
120 int e = errno;
121
122 errno = 0;
123 if (!isdigit(*port) ||
124 (i = strtoul(port, &q, 0)) == 0 ||
125 i >= 65536 || *q || errno)
126 die(1, "invalid port number `%s'", port);
127 errno = e;
128 return ((unsigned short)i);
129}
130
131/* Read the file named by NAME into a buffer -- or at least an initial
132 * portion of it; set *P to the start and *SZ to the length. Return -1 if it
133 * didn't work. The buffer doesn't need to be freed: the data is stashed in
134 * ibuf.
135 */
136static int snarf(const char *name, void **p, size_t *sz)
137{
138 ssize_t n;
139 int fd;
140
141 if ((fd = open(name, O_RDONLY)) < 0) return (-1);
142 n = read(fd, ibuf, sizeof(ibuf));
143 close(fd);
144 if (n < 0) return (-1);
145 *p = ibuf; *sz = n;
146 return (0);
147}
148
149/* Complain about something. If f_syslog is set then complain to that;
150 * otherwise write to stderr. Don't use `%m' because that won't work when
151 * writing to stderr.
152 */
92469bdf 153static void PRINTF_LIKE(2, 3) complain(int sev, const char *msg, ...)
247f344a
MW
154{
155 va_list ap;
156
157 va_start(ap, msg);
158 if (flags & f_syslog)
159 vsyslog(sev, msg, ap);
160 else {
161 fprintf(stderr, "%s: ", QUIS);
162 vfprintf(stderr, msg, ap);
163 fputc('\n', stderr);
164 }
165}
166
167/*----- Reading key data --------------------------------------------------*/
168
169struct kinfo {
170 group *g;
171 ge *X;
172 mp *x;
173 const gccipher *cc;
174 const gcmac *mc; size_t tagsz;
175 const gchash *hc;
176};
177
178/* Clear a kinfo structure so it can be freed without trouble. */
179static void k_init(struct kinfo *k) { k->g = 0; k->x = 0; k->X = 0; }
180
181/* Free a kinfo structure. This is safe on any initialized kinfo
182 * structure.
183 */
184static void k_free(struct kinfo *k)
185{
186 if (k->X) { G_DESTROY(k->g, k->X); k->X = 0; }
187 if (k->x) { MP_DROP(k->x); k->x = 0; }
188 if (k->g) { G_DESTROYGROUP(k->g); k->g = 0; }
189}
190
191/* Empty macro arguments are forbidden. But arguments are expended during
192 * replacement, not while the call is being processed, so this hack is OK.
193 * Unfortunately, if a potentially empty argument is passed on to another
194 * macro then it needs to be guarded with a use of EMPTY too...
195 */
196#define EMPTY
197
198/* Table of key types. Entries have the form
199 *
200 * _(name, NAME, SETGROUP, SETPRIV, SETPUB)
201 *
202 * The name and NAME are lower- and uppercase names for the type used for
203 * constructing various type name constant names. The code fragment SETGROUP
204 * initializes k->g given the name_{pub,priv} structure in p; SETPRIV and
205 * SETPUB set up k->x and k->X respectively. (In this last case, k->X will
206 * have been created as a group element already.)
207 */
208#define KEYTYPES(_) \
209 \
210 _(dh, DH, \
211 { k->g = group_prime(&p.dp); }, \
212 { k->x = MP_COPY(p.x); }, \
213 { if (G_FROMINT(k->g, k->X, p.y)) { \
214 complain(LOG_ERR, "bad public key in `%s'", t->buf); \
215 goto fail; \
216 } \
217 }) \
218 \
219 _(ec, EC, \
220 { ec_info ei; const char *e; \
221 if ((e = ec_getinfo(&ei, p.cstr)) != 0) { \
222 complain(LOG_ERR, "bad elliptic curve in `%s': %s", t->buf, e); \
223 goto fail; \
224 } \
225 k->g = group_ec(&ei); \
226 }, \
227 { k->x = MP_COPY(p.x); }, \
228 { if (G_FROMEC(k->g, k->X, &p.p)) { \
229 complain(LOG_ERR, "bad public point in `%s'", t->buf); \
230 goto fail; \
231 } \
232 })
233
234/* Define load_tywhich, where which is `pub' or `priv', to load a public or
235 * private key. Other parameters are as for the KEYTYPES list above.
236 */
237#define KLOAD(ty, TY, which, WHICH, setgroup, setpriv, setpub) \
238static int load_##ty##which(key_data *kd, struct kinfo *k, dstr *t) \
239{ \
240 key_packstruct kps[TY##_##WHICH##FETCHSZ]; \
241 key_packdef *kp; \
242 ty##_##which p; \
243 int rc; \
244 \
245 /* Extract the key data from the keydata. */ \
246 kp = key_fetchinit(ty##_##which##fetch, kps, &p); \
247 if ((rc = key_unpack(kp, kd, t)) != 0) { \
248 complain(LOG_ERR, "failed to unpack key `%s': %s", \
249 t->buf, key_strerror(rc)); \
250 goto fail; \
251 } \
252 \
253 /* Extract the components as abstract group elements. */ \
254 setgroup; \
255 setpriv; \
256 k->X = G_CREATE(k->g); \
257 setpub; \
258 \
259 /* Dispose of stuff we don't need. */ \
260 key_fetchdone(kp); \
261 return (0); \
262 \
263 /* Tidy up after mishaps. */ \
264fail: \
265 k_free(k); \
266 key_fetchdone(kp); \
267 return (-1); \
268}
269
270/* Map over the KEYTYPES to declare the load_tywhich functions using KLOAD
271 * above.
272 */
273#define KEYTYPE_KLOAD(ty, TY, setgroup, setpriv, setpub) \
274 KLOAD(ty, TY, priv, PRIV, setgroup, setpriv, \
275 { G_EXP(k->g, k->X, k->g->g, k->x); }) \
276 KLOAD(ty, TY, pub, PUB, setgroup, { }, setpub)
277KEYTYPES(KEYTYPE_KLOAD)
278
279/* Define a table of group key-loading operations. */
280struct kload_ops {
281 const char *name;
282 int (*loadpriv)(key_data *, struct kinfo *, dstr *);
283 int (*loadpub)(key_data *, struct kinfo *, dstr *);
284};
285
286static const struct kload_ops kload_ops[] = {
287#define KEYTYPE_OPS(ty, TY, setgroup, setpriv, setpub) \
288 { #ty, load_##ty##priv, load_##ty##pub },
289KEYTYPES(KEYTYPE_OPS)
290 { 0 }
291};
292
293/* Load a private or public (indicated by PRIVP) key named TAG into a kinfo
294 * structure K. Also fill in the cipher suite selections extracted from the
295 * key attributes.
296 */
297static int loadkey(const char *tag, struct kinfo *k, int privp)
298{
299 const struct kload_ops *ops;
300 dstr d = DSTR_INIT, dd = DSTR_INIT;
301 key *ky;
302 key_data **kd;
303 const char *ty, *p;
304 char *q;
305 int tsz;
306 int rc;
307
308 /* Find the key data. */
309 if (key_qtag(kf, tag, &d, &ky, &kd)) {
310 complain(LOG_ERR, "unknown key tag `%s'", tag);
311 goto fail;
312 }
313
314 /* Find the key's group type and locate the group operations. */
315 ty = key_getattr(kf, ky, "group");
316 if (!ty && strncmp(ky->type, "udpkey-", 7) == 0) ty = ky->type + 7;
317 if (!ty) {
318 complain(LOG_ERR, "no group type for key %s", d.buf);
319 goto fail;
320 }
321 for (ops = kload_ops; ops->name; ops++) {
322 if (strcmp(ty, ops->name) == 0)
323 goto found;
324 }
325 complain(LOG_ERR, "unknown group type `%s' in key %s", ty, d.buf);
326 goto fail;
327
328found:
329 /* Extract the key data into an appropriately abstract form. */
330 k->g = 0; k->x = 0; k->X = 0;
331 if ((rc = (privp ? ops->loadpriv : ops->loadpub)(*kd, k, &d)) != 0)
332 goto fail;
333
334 /* Extract the chosen symmetric cipher. */
335 if ((p = key_getattr(kf, ky, "cipher")) == 0)
336 k->cc = &rijndael_counter;
337 else if ((k->cc = gcipher_byname(p)) == 0) {
338 complain(LOG_ERR, "unknown cipher `%s' in key %s", p, d.buf);
339 goto fail;
340 }
341
342 /* And the chosen hash function. */
343 if ((p = key_getattr(kf, ky, "hash")) == 0)
344 k->hc = &sha256;
345 else if ((k->hc = ghash_byname(p)) == 0) {
346 complain(LOG_ERR, "unknown hash `%s' in key %s", p, d.buf);
347 goto fail;
348 }
349
350 /* And finally a MAC. This is more fiddly because we must handle (a)
351 * truncation and (b) defaulting based on the hash.
352 */
353 if ((p = key_getattr(kf, ky, "mac")) == 0)
354 dstr_putf(&dd, "%s-hmac", k->hc->name);
355 else
356 dstr_puts(&dd, p);
357 if ((q = strchr(dd.buf, '/')) != 0) *q++ = 0;
358 else q = 0;
359 if ((k->mc = gmac_byname(dd.buf)) == 0) {
360 complain(LOG_ERR, "unknown mac `%s' in key %s", dd.buf, d.buf);
361 goto fail;
362 }
363 if (!q)
364 k->tagsz = k->mc->hashsz/2;
365 else {
366 tsz = atoi(q);
367 if (tsz <= 0 || tsz%8 || tsz/8 > k->mc->hashsz) {
46716e8f 368 complain(LOG_ERR, "bad tag size `%s' for mac `%s' in key %s",
247f344a
MW
369 q, k->mc->name, d.buf);
370 goto fail;
371 }
372 k->tagsz = tsz/8;
373 }
374
375 /* Done. */
376 rc = 0;
377 goto done;
378
379fail:
380 rc = -1;
381done:
382 dstr_destroy(&d);
383 dstr_destroy(&dd);
384 return (rc);
385}
386
387static void keymoan(const char *file, int line, const char *err, void *p)
388 { complain(LOG_ERR, "%s:%d: %s", file, line, err); }
389
390/* Update the keyring `kf' if the file has been changed since we last looked.
391 */
392static void kfupdate(void)
393{
394 key_file *kfnew;
395
396 if (!fwatch_update(&kfwatch, kfname)) return;
397 kfnew = CREATE(key_file);
398 if (key_open(kfnew, kfname, KOPEN_READ, keymoan, 0)) {
399 DESTROY(kfnew);
400 return;
401 }
402 key_close(kf);
403 DESTROY(kf);
404 kf = kfnew;
405}
406
407/*----- Low-level crypto operations ---------------------------------------*/
408
409/* Derive a key, writing its address to *KK and size to *N. The size is
410 * compatible with the keysz rules KSZ. It is generated for the purpose of
411 * keying a WHAT (used for key separation and in error messages), and NAME is
412 * the name of the specific instance (e.g., `twofish-counter') from the class
413 * name. The kinfo structure K tells us which algorithms to use for the
414 * derivation. The group elements U and Z are the cryptographic inputs
415 * for the derivation.
416 *
de14f3b0 417 * Basically all we do is compute H(what || U || V || Z).
247f344a 418 */
de14f3b0 419static int derive(struct kinfo *k, ge *U, ge *V, ge *Z,
247f344a
MW
420 const char *what, const char *name, const octet *ksz,
421 octet **kk, size_t *n)
422{
423 buf b;
424 ghash *h;
425 octet *p;
426
427 /* Find a suitable key size. */
428 if ((*n = keysz(k->hc->hashsz, ksz)) == 0) {
429 complain(LOG_ERR,
430 "failed to find suitable key size for %s `%s' and hash `%s'",
431 what, name, k->hc->name);
432 return (-1);
433 }
434
435 /* Build the hash preimage. */
436 buf_init(&b, obuf, sizeof(obuf));
437 buf_put(&b, "udpkey-", 7);
438 buf_putstrz(&b, what);
de14f3b0
MW
439 if (U) G_TORAW(k->g, &b, U);
440 if (V) G_TORAW(k->g, &b, V);
247f344a
MW
441 G_TORAW(k->g, &b, Z);
442 if (BBAD(&b)) {
443 complain(LOG_ERR, "overflow while deriving key (prepare preimage)!");
444 return (-1);
445 }
446
447 /* Derive the output key. */
448 h = GH_INIT(k->hc);
449 GH_HASH(h, BBASE(&b), BLEN(&b));
450 buf_init(&b, obuf, sizeof(obuf));
451 if ((p = buf_get(&b, h->ops->c->hashsz)) == 0) {
452 complain(LOG_ERR, "overflow while deriving key (output hash)!");
453 GH_DESTROY(h);
454 return (-1);
455 }
456 GH_DONE(h, p);
457 GH_DESTROY(h);
458 *kk = p;
459 return (0);
460}
461
462#ifdef DEBUG
463static void debug_mp(const char *what, mp *x)
464 { fprintf(stderr, "%s: *** ", QUIS); MP_EPRINT(what, x); }
465static void debug_ge(const char *what, group *g, ge *X)
466{
467 fprintf(stderr, "%s: *** %s = ", QUIS, what);
468 group_writefile(g, X, stderr);
469 fputc('\n', stderr);
470}
471#endif
472
de14f3b0
MW
473/* Derive the symmetric keys for Diffie--Hellman-based symmetric crypto,
474 * given (optional) sender public key U, (optional) recipient public key V,
475 * and secret Z, constructing cipher and mac objects for the actual work.
476 *
477 * Your protocol must be consistent about whether it sends U and/or V: the
478 * formatting is ambiguous if you sometimes use one and sometimes the other.
479 */
480static void dh_derive_keys(struct kinfo *k, ge *U, ge *V, ge *Z,
481 gcipher **cc, gmac **mm)
482{
483 octet *kk;
484 size_t ksz;
485
486 derive(k, U, V, Z, "cipher", k->cc->name, k->cc->keysz, &kk, &ksz);
487 *cc = GC_INIT(k->cc, kk, ksz);
488 derive(k, U, V, Z, "mac", k->mc->name, k->mc->keysz, &kk, &ksz);
489 *mm = GM_KEY(k->mc, kk, ksz);
490}
491
492/* Prepare for an IES encryption. Given a public key X, prepare a clue R and
493 * secret Z for later.
494 */
495static void ies_enc_prepare(struct kinfo *k, ge *X, ge *R, ge *Z)
496{
497 mp *r = mprand_range(MP_NEW, k->g->r, &rand_global, 0);
498 G_EXP(k->g, R, k->g->g, r);
499 G_EXP(k->g, Z, X, r);
500 D( debug_mp("r", r); debug_ge("R", k.g, R); )
501 MP_DROP(r);
502}
503
504/* Actually perform an IES encryption. Given a prepared clue R and secret Z,
505 * and an SZ-byte plaintext message P, write the ciphertext to B. Note that
506 * the clue itself is /not/ written to B: you must do that yourself.
507 */
508static int ies_enc_perform(struct kinfo *k, buf *b, ge *R, ge *Z,
509 const void *p, size_t sz)
510{
511 octet *t, *tt, *ct;
512 gcipher *c;
513 gmac *m;
514 ghash *h;
515
516 if ((t = buf_get(b, k->tagsz)) == 0 ||
517 (ct = buf_get(b, sz)) == 0) {
518 complain(LOG_ERR, "overflow while writing ciphertext");
519 return (-1);
520 }
521
522 dh_derive_keys(k, R, 0, Z, &c, &m);
523 GC_ENCRYPT(c, p, ct, sz);
524 h = GM_INIT(m);
525 GH_HASH(h, ct, sz);
526 tt = GH_DONE(h, 0);
527 memcpy(t, tt, k->tagsz);
528
529 GC_DESTROY(c);
530 GM_DESTROY(m);
531 GH_DESTROY(h);
532}
533
7f5ea7d3 534/*----- Protocol summary --------------------------------------------------*
36fb0983
MW
535 *
536 * There are two protocol versions. The original version works as follows.
7f5ea7d3
MW
537 *
538 * * Request
539 * memz KEYTAG tag of wanted secret
540 * ge U public vector
541 *
542 * * Response
543 * ge V public vector: V = v P
de14f3b0
MW
544 * ge W masked IES clue: W = R - Y = r P - v U
545 * iesct[*](H(R, r X))
546 * mem[*] S secret
36fb0983
MW
547 *
548 * The new version provides forward secrecy, which involves additional flows.
549 *
de14f3b0 550 * * Request
36fb0983
MW
551 * u8 0 marker byte for new protocol
552 * u8 1 packet type
553 * mem8 KEYTAG wanted secret tag
de14f3b0 554 * ge U public vector: U = u P
36fb0983
MW
555 *
556 * * Challenge
557 * u8 17 packet type
de14f3b0
MW
558 * ge R IES clue
559 * iesct[*](H(R, r X))
560 * ge U client's public vector (confirms receipt)
561 * ge V public vector: V = v P
562 * mem[*] a nonce
36fb0983
MW
563 *
564 * * Response
565 * u8 0 marker byte for new protocol
566 * u8 2 packet type
de14f3b0 567 * mem[*] a server's nonce (confirm receipt of V)
36fb0983 568 *
de14f3b0 569 * * Answer
36fb0983 570 * u8 18 packet type
de14f3b0
MW
571 * iesct[*](H(U, V, Z))
572 * mem[*] S secret
7f5ea7d3
MW
573 */
574
de14f3b0
MW
575#define FWS_REQ 0x01
576#define FWS_CHAL 0x11
36fb0983 577#define FWS_RESP 0x02
de14f3b0 578#define FWS_ANS 0x12
36fb0983 579
247f344a
MW
580/*----- Listening for requests --------------------------------------------*/
581
582/* Rate limiting parameters.
583 *
584 * There's a probabilistic rate-limiting mechanism. A counter starts at 0.
c33ded25 585 * Every time we process a request, we increment the counter. The counter
247f344a
MW
586 * drops by RATE_REFILL every second. If the counter is below RATE_CREDIT
587 * then the request is processed; otherwise it is processed with probability
588 * 1/(counter - RATE_CREDIT).
589 */
590#define RATE_REFILL 10 /* Credits per second. */
591#define RATE_CREDIT 1000 /* Initial credit. */
592
7f5ea7d3
MW
593static time_t now;
594
0057c20e
MW
595/* Secrets table.
596 *
597 * The server doesn't want to maintain state for each client. Instead, we
598 * generate a global secret, and derive per-client secrets from it. A secret
599 * needs to have an expiry time (at which point we won't use it for new
600 * requests) and a deletion time (at which point we just forget that it ever
601 * existed). This lets us roll over to a new secret without leaving existing
602 * clients completely in the lurch.
603 *
604 * Secrets are kept in a linked list, ordered by expiry time. At any given
605 * time there is at most one unexpired secret (because we only make a new one
606 * when the old one expires).
de14f3b0
MW
607 *
608 * The nonce has the form ...
0057c20e
MW
609 */
610
611struct secret {
612 struct secret *next;
613 uint32 seq;
614 time_t t_exp, t_del;
615 octet x[32];
616};
617static struct secret *secrets = 0, *live_secret = 0;
618static uint32 next_secret_seq = 0;
619#define T_SECEXP 30
620#define T_SECDEL 45
621
622static void kill_dead_secrets(void)
623{
624 struct secret *s = secrets, *ss;
625
626 for (s = secrets; s && s->t_del <= now; s = ss) {
627 ss = s->next;
628 DESTROY(s);
629 }
630 secrets = 0;
631 if (!s) live_secret = 0;
632}
633
634static struct secret *find_secret(uint32 seq)
635{
636 struct secret *s;
637
638 kill_dead_secrets();
639 for (s = secrets; s; s = s->next)
640 if (s->seq == seq) return (s);
641 return (0);
642}
643
644static struct secret *fresh_secret(void)
645{
646 struct secret *s;
647
648 if (live_secret && live_secret->t_exp > now) return (live_secret);
649 kill_dead_secrets();
650
651 s = CREATE(struct secret);
652 s->seq = next_secret_seq++;
653 s->next = 0;
654 rand_get(RAND_GLOBAL, s->x, sizeof(s->x));
655 s->t_exp = now + T_SECEXP; s->t_del = now + T_SECDEL;
656 if (live_secret) live_secret->next = s;
657 else secrets = s;
658 live_secret = s;
659 return (s);
660}
661
7f5ea7d3
MW
662static int fetch_key(const char *tag, struct sockaddr_in *sin,
663 key **ky, struct kinfo *k)
664{
665 dstr d = DSTR_INIT, dd = DSTR_INIT;
666 key_data **kkd;
667 char *p, *q;
668 const char *pp;
669 struct in_addr in;
670 int ch, mlen, rc = -1;
671
672 /* Find the key. */
673 kfupdate();
674 if (key_qtag(kf, tag, &d, ky, &kkd)) {
675 complain(LOG_WARNING, "unknown key tag `%s' from %s:%d",
676 tag, inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
677 goto done;
678 }
679
680 /* And make sure that it has the right shape. */
681 if (((*ky)->k->e & KF_ENCMASK) != KENC_BINARY) {
682 complain(LOG_ERR, "key %s is not plain binary data", d.buf);
683 goto done;
684 }
685
686 /* Find the list of clients, and look up the caller's address in the
687 * list. Entries have the form ADDRESS[/LEN][=TAG] and are separated by
688 * `;'.
689 */
690 if ((pp = key_getattr(kf, *ky, "clients")) == 0) {
691 complain(LOG_WARNING,
692 "key %s requested from %s:%d has no `clients' attribute",
693 d.buf, inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
694 goto done;
695 }
696 dstr_puts(&dd, pp);
697 p = dd.buf;
698 while (*p) {
699 q = p;
700 while (isdigit((unsigned char)*q) || *q == '.') q++;
701 ch = *q; *q++ = 0;
702 if (!inet_aton(p, &in)) goto skip;
703 if (ch != '/')
704 mlen = 32;
705 else {
706 p = q;
707 while (isdigit((unsigned char)*q)) q++;
708 ch = *q; *q++ = 0;
709 mlen = atoi(p);
710 }
711 if (((sin->sin_addr.s_addr ^ in.s_addr) &
712 htonl(0xffffffff << (32 - mlen))) == 0)
713 goto match;
714 skip:
715 if (!ch) break;
716 p = q;
717 while (*p && *p != ';') p++;
718 if (*p) p++;
719 }
720 complain(LOG_WARNING, "access to key %s denied to %s:%d",
721 d.buf, inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
722 goto done;
723
724match:
725 /* Build a tag name for the caller's KEM key, either from the client
726 * match or the source address.
727 */
728 if (ch != '=') {
729 DRESET(&dd);
730 dstr_puts(&dd, "client-");
731 dstr_puts(&dd, inet_ntoa(sin->sin_addr));
732 p = dd.buf;
733 } else {
734 p = q;
735 while (*q && *q != ';') q++;
736 if (*q == ';') *q++ = 0;
737 }
738
739 /* Report the match. */
740 complain(LOG_NOTICE, "client %s:%d (`%s') requests key %s",
741 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), p, d.buf);
742
743 /* Load the KEM key. */
744 if (loadkey(p, k, 0)) goto done;
745 D( debug_ge("X", k.g, k.X); )
746
747 /* All complete. */
748 rc = 0;
749
750done:
751 /* Clean everything up. */
752 dstr_destroy(&d);
753 dstr_destroy(&dd);
754 if (rc) k_free(k);
755 return (rc);
756}
757
758static int respond_v0(buf *bin, buf *bout, struct sockaddr_in *sin)
759{
760 ge *R = 0, *U = 0, *V = 0, *W = 0, *Y = 0, *Z = 0;
de14f3b0
MW
761 mp *v = MP_NEW;
762 struct kinfo k;
7f5ea7d3
MW
763 char *p;
764 size_t sz;
7f5ea7d3 765 key *ky;
7f5ea7d3
MW
766 int rc = -1;
767
768 /* Clear out the key state. */
769 k_init(&k);
770
771 /* Extract the key tag name. */
772 if ((p = buf_getmemz(bin, &sz)) == 0) {
773 complain(LOG_WARNING, "invalid key tag from %s:%d",
774 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
775 goto done;
776 }
777
778 /* Find the client's key and check that it's allowed. */
779 if (fetch_key(p, sin, &ky, &k)) goto done;
780
781 /* Read the caller's ephemeral key. */
782 R = G_CREATE(k.g); W = G_CREATE(k.g);
783 U = G_CREATE(k.g); V = G_CREATE(k.g);
784 Y = G_CREATE(k.g); Z = G_CREATE(k.g);
785 if (G_FROMBUF(k.g, bin, U)) {
786 complain(LOG_WARNING, "failed to read ephemeral vector from %s:%d",
787 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
788 goto done;
789 }
790 D( debug_ge("U", k.g, U); )
791 if (BLEFT(bin)) {
792 complain(LOG_WARNING, "trailing junk in request from %s:%d",
793 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
794 goto done;
795 }
796
797 /* Ephemeral Diffie--Hellman. Choose v in GF(q) at random; compute
798 * V = v P and -Y = (-v) U.
799 */
800 v = mprand_range(v, k.g->r, &rand_global, 0);
801 G_EXP(k.g, V, k.g->g, v);
802 D( debug_mp("v", v); debug_ge("V", k.g, V); )
26b2a043 803 v = mp_sub(v, k.g->r, v);
7f5ea7d3
MW
804 G_EXP(k.g, Y, U, v);
805 D( debug_ge("-Y", k.g, Y); )
806
807 /* DLIES. Choose r in GF(q) at random; compute R = r P and Z = r X. Mask
808 * the clue R as W = R - Y. (Doing the subtraction here makes life easier
809 * at the other end, since we can determine -Y by negating v whereas the
810 * recipient must subtract vectors which may be less efficient.)
811 */
de14f3b0 812 ies_enc_prepare(&k, k.X, R, Z);
7f5ea7d3
MW
813 G_MUL(k.g, W, R, Y);
814 D( debug_ge("Z", k.g, Z); debug_ge("W", k.g, W); )
815
de14f3b0 816 /* Write the ciphertext. */
7f5ea7d3
MW
817 rc = 0;
818 if (G_TOBUF(k.g, bout, V) ||
de14f3b0
MW
819 G_TOBUF(k.g, bout, W) ||
820 ies_enc_perform(&k, bout, R, Z, ky->k->u.k.k, ky->k->u.k.sz))
7f5ea7d3 821 goto done;
7f5ea7d3
MW
822
823done:
824 /* Clear everything up and go home. */
825 if (R) G_DESTROY(k.g, R);
826 if (U) G_DESTROY(k.g, U);
827 if (V) G_DESTROY(k.g, V);
828 if (W) G_DESTROY(k.g, W);
829 if (Y) G_DESTROY(k.g, Y);
830 if (Z) G_DESTROY(k.g, Z);
7f5ea7d3
MW
831 if (v) MP_DROP(v);
832 k_free(&k);
833 return (rc);
834}
835
247f344a
MW
836static int dolisten(int argc, char *argv[])
837{
838 int sk;
7f5ea7d3 839 char *p;
247f344a
MW
840 char *aspec;
841 ssize_t n;
247f344a
MW
842 fd_set fdin;
843 struct sockaddr_in sin;
247f344a
MW
844 socklen_t len;
845 buf bin, bout;
247f344a 846 FILE *fp = 0;
247f344a 847 unsigned bucket = 0, toks;
7f5ea7d3 848 time_t last = 0;
247f344a
MW
849
850 /* Set up the socket address. */
851 sin.sin_family = AF_INET;
852 aspec = xstrdup(argv[0]);
853 if ((p = strchr(aspec, ':')) == 0) {
854 p = aspec;
855 sin.sin_addr.s_addr = INADDR_ANY;
856 } else {
857 *p++ = 0;
858 resolve(aspec, &sin.sin_addr);
859 }
860 sin.sin_port = htons(getport(p));
861
862 /* Create and set up the socket itself. */
863 if ((sk = socket(PF_INET, SOCK_DGRAM, 0)) < 0 ||
864 fdflags(sk, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC) ||
865 bind(sk, (struct sockaddr *)&sin, sizeof(sin)))
866 die(1, "failed to create socket: %s", strerror(errno));
867
868 /* That's enough initialization. If we should fork, then do that. */
869 if (flags & f_daemon) {
870 if (pidfile && (fp = fopen(pidfile, "w")) == 0)
871 die(1, "failed to open pidfile `%s': %s", pidfile, strerror(errno));
872 openlog(QUIS, LOG_PID, LOG_DAEMON);
873 if (daemonize())
874 die(1, "failed to become background process: %s", strerror(errno));
875 if (pidfile) { fprintf(fp, "%ld\n", (long)getpid()); fclose(fp); }
876 flags |= f_syslog;
877 }
878
879 for (;;) {
880
247f344a
MW
881 /* Wait for something to happen. */
882 FD_ZERO(&fdin);
883 FD_SET(sk, &fdin);
884 if (select(sk + 1, &fdin, 0, 0, 0) < 0)
885 die(1, "select failed: %s", strerror(errno));
886 noise_timer(RAND_GLOBAL);
887
888 /* Fetch a packet. */
889 len = sizeof(sin);
890 n = recvfrom(sk, ibuf, sizeof(ibuf), 0, (struct sockaddr *)&sin, &len);
891 if (n < 0) {
892 if (errno != EAGAIN && errno != EINTR)
893 complain(LOG_ERR, "unexpected receive error: %s", strerror(errno));
7f5ea7d3 894 continue;
247f344a
MW
895 }
896
897 /* Refill the bucket, and see whether we should reject this packet. */
898 now = time(0);
899 if (bucket && now != last) {
900 toks = (now - last)*RATE_REFILL;
901 bucket = bucket < toks ? 0 : bucket - toks;
902 }
903 last = now;
904 if (bucket > RATE_CREDIT &&
905 grand_range(&rand_global, bucket - RATE_CREDIT))
7f5ea7d3 906 continue;
247f344a
MW
907 bucket++;
908
909 /* Set up the input buffer for parsing the request. */
910 buf_init(&bin, ibuf, n);
247f344a 911 buf_init(&bout, obuf, sizeof(obuf));
7f5ea7d3
MW
912
913 /* Handle the client's message. */
914 if (respond_v0(&bin, &bout, &sin)) continue;
247f344a
MW
915
916 /* Send the reply packet back to the caller. */
7f5ea7d3 917 if (!BOK(&bout)) goto bad;
247f344a
MW
918 if (sendto(sk, BBASE(&bout), BLEN(&bout), 0,
919 (struct sockaddr *)&sin, len) < 0) {
920 complain(LOG_ERR, "failed to send response to %s:%d: %s",
921 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port),
922 strerror(errno));
7f5ea7d3 923 continue;
247f344a
MW
924 }
925
7f5ea7d3 926 continue;
247f344a
MW
927
928 bad:
929 /* Report a problem building the reply. */
930 complain(LOG_ERR, "failed to construct response to %s:%d",
931 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
247f344a
MW
932 }
933
934 return (-1);
935}
936
937/*----- Sending requests and processing responses -------------------------*/
938
939struct query {
940 struct query *next;
4efa5091 941 const char *tag;
247f344a
MW
942 octet *k;
943 size_t sz;
944 struct server *s;
945};
946
947struct server {
948 struct server *next;
949 struct sockaddr_in sin;
950 struct kinfo k;
4efa5091 951 const struct client_protocol *proto;
247f344a
MW
952 mp *u;
953 ge *U;
954 octet *h;
955};
956
4efa5091
MW
957struct client_protocol {
958 const char *name;
959 int (*setup)(struct query *, struct server *);
960 int (*receive)(struct query *, struct server *, buf *, buf *);
961 int (*retransmit)(struct query *, struct server *, buf *);
962};
963
247f344a
MW
964/* Record a successful fetch of key material for a query Q. The data starts
965 * at K and is SZ bytes long. The data is copied: it's safe to overwrite it.
966 */
4efa5091
MW
967static int donequery(struct query *q, struct server *s,
968 const void *k, size_t sz)
969{
970 octet *tt;
971 ghash *h = 0;
972 int diffp;
973
974 /* If we have a hash, check that the fragment matches it. */
975 if (s && s->h) {
976 h = GH_INIT(s->k.hc);
977 GH_HASH(h, k, sz);
978 tt = GH_DONE(h, 0);
979 diffp = memcmp(tt, s->h, h->ops->c->hashsz);
980 GH_DESTROY(h);
981 if (diffp) {
982 moan("response from %s:%d doesn't match hash",
983 inet_ntoa(s->sin.sin_addr), ntohs(s->sin.sin_port));
984 return (-1);
985 }
986 }
987
988 /* Stash a copy of the key fragment for later. */
989 q->k = xmalloc(sz);
990 memcpy(q->k, k, sz);
991 q->sz = sz; nq--;
992
993 /* All good. */
994 return (0);
995}
996
997static int setup_v0(struct query *q, struct server *s)
998{
999 /* Choose an ephemeral private key u. Let x be our private key. We
1000 * compute U = u P and transmit this.
1001 */
1002 s->u = mprand_range(MP_NEW, s->k.g->r, &rand_global, 0);
1003 s->U = G_CREATE(s->k.g);
1004 G_EXP(s->k.g, s->U, s->k.g->g, s->u);
1005 D( debug_mp("u", s->u); debug_ge("U", s->k.g, s->U); )
1006
1007 return (0);
1008}
1009
1010static int retransmit_v0(struct query *q, struct server *s, buf *bout)
1011{
1012 buf_putstrz(bout, q->tag);
1013 G_TOBUF(s->k.g, bout, s->U);
1014 return (0);
1015}
1016
1017static int receive_v0(struct query *q, struct server *s, buf *bin, buf *bout)
1018{
1019 ge *R, *V = 0, *W = 0, *Y = 0, *Z = 0;
1020 octet *kk, *t, *tt;
1021 gcipher *c = 0;
1022 gmac *m = 0;
1023 ghash *h = 0;
1024 size_t n, ksz;
1025 octet *p;
1026 int rc = -1;
1027
1028 R = G_CREATE(s->k.g);
1029 V = G_CREATE(s->k.g); W = G_CREATE(s->k.g);
1030 Y = G_CREATE(s->k.g); Z = G_CREATE(s->k.g);
1031 if (G_FROMBUF(s->k.g, bin, V)) {
1032 moan("invalid Diffie--Hellman vector from %s:%d",
1033 inet_ntoa(s->sin.sin_addr), ntohs(s->sin.sin_port));
1034 goto done;
1035 }
1036 if (G_FROMBUF(s->k.g, bin, W)) {
1037 moan("invalid clue vector from %s:%d",
1038 inet_ntoa(s->sin.sin_addr), ntohs(s->sin.sin_port));
1039 goto done;
1040 }
1041 D( debug_ge("V", s->k.g, V); debug_ge("W", s->k.g, W); )
1042
1043 /* We have V and W from the server; determine Y = u V, R = W + Y and
1044 * Z = x R, and then derive the symmetric keys.
1045 */
1046 G_EXP(s->k.g, Y, V, s->u);
1047 G_MUL(s->k.g, R, W, Y);
1048 G_EXP(s->k.g, Z, R, s->k.x);
1049 D( debug_ge("R", s->k.g, R);
1050 debug_ge("Y", s->k.g, Y);
1051 debug_ge("Z", s->k.g, Z); )
de14f3b0 1052 derive(&s->k, R, 0, Z, "cipher", s->k.cc->name, s->k.cc->keysz, &kk, &ksz);
4efa5091 1053 c = GC_INIT(s->k.cc, kk, ksz);
de14f3b0 1054 derive(&s->k, R, 0, Z, "mac", s->k.mc->name, s->k.mc->keysz, &kk, &ksz);
4efa5091
MW
1055 m = GM_KEY(s->k.mc, kk, ksz);
1056
1057 /* Find where the MAC tag is. */
1058 if ((t = buf_get(bin, s->k.tagsz)) == 0) {
1059 moan("missing tag from %s:%d",
1060 inet_ntoa(s->sin.sin_addr), ntohs(s->sin.sin_port));
1061 goto done;
1062 }
1063
1064 /* Check the integrity of the ciphertext against the tag. */
1065 p = BCUR(bin); n = BLEFT(bin);
1066 h = GM_INIT(m);
1067 GH_HASH(h, p, n);
1068 tt = GH_DONE(h, 0);
1069 if (!ct_memeq(t, tt, s->k.tagsz)) {
1070 moan("incorrect tag from %s:%d",
1071 inet_ntoa(s->sin.sin_addr), ntohs(s->sin.sin_port));
1072 goto done;
1073 }
1074
1075 /* Decrypt the result and declare this server done. */
1076 GC_DECRYPT(c, p, p, n);
1077 rc = donequery(q, s, p, n);
1078
1079done:
1080 /* Clear up and go home. */
1081 if (R) G_DESTROY(s->k.g, R);
1082 if (V) G_DESTROY(s->k.g, V);
1083 if (W) G_DESTROY(s->k.g, W);
1084 if (Y) G_DESTROY(s->k.g, Y);
1085 if (Z) G_DESTROY(s->k.g, Z);
1086 if (c) GC_DESTROY(c);
1087 if (m) GM_DESTROY(m);
1088 if (h) GH_DESTROY(h);
1089 return (rc);
1090}
1091
1092static const struct client_protocol prototab[] = {
1093 { "v0", setup_v0, receive_v0, retransmit_v0 },
1094 { 0 }
1095};
247f344a
MW
1096
1097/* Initialize a query to a remote server. */
1098static struct query *qinit_net(const char *tag, const char *spec)
1099{
1100 struct query *q;
1101 struct server *s, **stail;
1102 dstr d = DSTR_INIT, dd = DSTR_INIT;
4efa5091 1103 const struct client_protocol *proto;
247f344a
MW
1104 hex_ctx hc;
1105 char *p, *pp, ch;
1106
1107 /* Allocate the query block. */
1108 q = CREATE(struct query);
4efa5091 1109 q->tag = tag;
247f344a
MW
1110 stail = &q->s;
1111
1112 /* Put the spec somewhere we can hack at it. */
1113 dstr_puts(&d, spec);
1114 p = d.buf;
1115
1116 /* Parse the query spec. Entries have the form ADDRESS:PORT[=TAG][#HASH]
1117 * and are separated by `;'.
1118 */
1119 while (*p) {
1120
1121 /* Allocate a new server node. */
1122 s = CREATE(struct server);
1123 s->sin.sin_family = AF_INET;
1124
1125 /* Extract the server address. */
1126 if ((pp = strchr(p, ':')) == 0)
1127 die(1, "invalid syntax: missing `:PORT'");
1128 *pp++ = 0;
1129 resolve(p, &s->sin.sin_addr);
1130
1131 /* Extract the port number. */
1132 p = pp;
1133 while (isdigit((unsigned char)*pp)) pp++;
1134 ch = *pp; *pp++ = 0;
1135 s->sin.sin_port = htons(getport(p));
1136
4efa5091
MW
1137 /* See if there's a protocol name. */
1138 if (ch != '?')
1139 p = "v0";
1140 else {
1141 p = pp;
1142 pp += strcspn(pp, ";#=");
1143 ch = *pp; *pp++ = 0;
1144 }
1145 for (proto = prototab; proto->name; proto++)
1146 if (strcmp(proto->name, p) == 0) goto found_proto;
1147 die(1, "unknown protocol name `%s'", p);
1148 found_proto:
1149 s->proto = proto;
1150
247f344a
MW
1151 /* If there's a key tag then extract that; otherwise use a default. */
1152 if (ch != '=')
1153 p = "udpkey-kem";
1154 else {
1155 p = pp;
1156 pp += strcspn(pp, ";#");
1157 ch = *pp; *pp++ = 0;
1158 }
1159 if (loadkey(p, &s->k, 1)) exit(1);
1160 D( debug_mp("x", s->k.x); debug_ge("X", s->k.g, s->k.X); )
1161
247f344a
MW
1162 /* Link the server on. */
1163 *stail = s; stail = &s->next;
1164
1165 /* If there's a trailing hash then extract it. */
1166 if (ch != '#')
1167 s->h = 0;
1168 else {
1169 p = pp;
1170 while (*pp == '-' || isxdigit((unsigned char)*pp)) pp++;
1171 hex_init(&hc);
1172 DRESET(&dd);
1173 hex_decode(&hc, p, pp - p, &dd);
1174 if (dd.len != s->k.hc->hashsz) die(1, "incorrect hash length");
1175 s->h = xmalloc(dd.len);
1176 memcpy(s->h, dd.buf, dd.len);
1177 ch = *pp++;
1178 }
1179
4efa5091
MW
1180 /* Initialize the protocol. */
1181 if (s->proto->setup(q, s)) die(1, "failed to initialize protocol");
1182
247f344a
MW
1183 /* If there are more servers, then continue parsing. */
1184 if (!ch) break;
1185 else if (ch != ';') die(1, "invalid syntax: expected `;'");
1186 p = pp;
1187 }
1188
1189 /* Terminate the server list and return. */
1190 *stail = 0;
1191 q->k = 0;
1192 dstr_destroy(&d);
1193 dstr_destroy(&dd);
1194 return (q);
1195}
1196
1197/* Handle a `query' to a local file. */
1198static struct query *qinit_file(const char *tag, const char *file)
1199{
1200 struct query *q;
1201 void *k;
1202 size_t sz;
1203
1204 /* Snarf the file. */
1205 q = CREATE(struct query);
1206 if (snarf(file, &k, &sz))
1207 die(1, "failed to read `%s': %s", file, strerror(errno));
1208 q->s = 0;
4efa5091 1209 donequery(q, 0, k, sz);
247f344a
MW
1210 return (q);
1211}
1212
c33ded25 1213/* Retransmission and timeout parameters. */
247f344a
MW
1214#define TO_NEXT(t) (((t) + 2)*4/3) /* Timeout growth function */
1215#define TO_MAX 30 /* When to give up */
1216
1217static int doquery(int argc, char *argv[])
1218{
1219 struct query *q = 0, *qq, **qtail = &qq;
1220 struct server *s = 0;
1221 const char *tag = argv[0];
1222 octet *p;
1223 int i;
1224 int sk;
1225 fd_set fdin;
1226 struct timeval now, when, tv;
1227 struct sockaddr_in sin;
247f344a
MW
1228 socklen_t len;
1229 unsigned next = 0;
1230 buf bin, bout;
4efa5091 1231 size_t n, j;
247f344a
MW
1232 ssize_t nn;
1233
1234 /* Create a socket. We just use the one socket for everything. We don't
1235 * care which port we get allocated.
1236 */
1237 if ((sk = socket(PF_INET, SOCK_DGRAM, 0)) < 0 ||
1238 fdflags(sk, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC))
1239 die(1, "failed to create socket: %s", strerror(errno));
1240
1241 /* Parse the query target specifications. The adjustments of `nq' aren't
1242 * in the right order but that doesn't matter.
1243 */
1244 for (i = 1; i < argc; i++) {
1245 if (*argv[i] == '.' || *argv[i] == '/') q = qinit_file(tag, argv[i]);
1246 else if (strchr(argv[i], ':')) q = qinit_net(tag, argv[i]);
1247 else die(1, "unrecognized query target `%s'", argv[i]);
1248 *qtail = q; qtail = &q->next; nq++;
1249 }
1250 *qtail = 0;
1251
1252 /* Find the current time so we can compute retransmission times properly.
1253 */
1254 gettimeofday(&now, 0);
1255 when = now;
1256
1257 /* Continue retransmitting until we have all the answers. */
1258 while (nq) {
1259
1260 /* Work out when we next want to wake up. */
1261 if (TV_CMP(&now, >=, &when)) {
1262 do {
1263 if (next >= TO_MAX) die(1, "no responses: giving up");
1264 next = TO_NEXT(next);
1265 TV_ADDL(&when, &when, next, 0);
1266 } while (TV_CMP(&when, <=, &now));
1267 for (q = qq; q; q = q->next) {
1268 if (q->k) continue;
1269 for (s = q->s; s; s = s->next) {
1270 buf_init(&bout, obuf, sizeof(obuf));
4efa5091 1271 if (s->proto->retransmit(q, s, &bout)) continue;
247f344a
MW
1272 if (BBAD(&bout)) {
1273 moan("overflow while constructing request!");
1274 continue;
1275 }
1276 sendto(sk, BBASE(&bout), BLEN(&bout), 0,
1277 (struct sockaddr *)&s->sin, sizeof(s->sin));
1278 }
1279 }
1280 }
1281
1282 /* Wait until something interesting happens. */
1283 FD_ZERO(&fdin);
1284 FD_SET(sk, &fdin);
1285 TV_SUB(&tv, &when, &now);
1286 if (select(sk + 1, &fdin, 0, 0, &tv) < 0)
1287 die(1, "select failed: %s", strerror(errno));
1288 gettimeofday(&now, 0);
1289
1290 /* If we have an input event, process incoming packets. */
1291 if (FD_ISSET(sk, &fdin)) {
1292 for (;;) {
1293
1294 /* Read a packet and capture its address. */
1295 len = sizeof(sin);
1296 nn = recvfrom(sk, ibuf, sizeof(ibuf), 0,
1297 (struct sockaddr *)&sin, &len);
1298 if (nn < 0) {
1299 if (errno == EAGAIN) break;
1300 else if (errno == EINTR) continue;
1301 else {
1302 moan("error receiving reply: %s", strerror(errno));
4efa5091 1303 continue;
247f344a
MW
1304 }
1305 }
1306
1f27bade 1307 /* See whether this corresponds to any of our servers. Don't just
c33ded25 1308 * check the active servers, since this may be late a reply caused by
247f344a
MW
1309 * retransmissions or similar.
1310 */
1311 for (q = qq; q; q = q->next) {
1312 for (s = q->s; s; s = s->next) {
1313 if (s->sin.sin_addr.s_addr == sin.sin_addr.s_addr &&
1314 s->sin.sin_port == sin.sin_port)
1315 goto found;
1316 }
1317 }
1318 moan("received reply from unexpected source %s:%d",
1319 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
4efa5091 1320 continue;
247f344a
MW
1321
1322 found:
1323 /* If the query we found has now been satisfied, ignore this packet.
1324 */
4efa5091 1325 if (q->k) continue;
247f344a 1326
4efa5091
MW
1327 /* Parse the reply, and either finish the job or get a message to
1328 * send back to the server.
247f344a 1329 */
4efa5091
MW
1330 buf_init(&bin, ibuf, nn);
1331 buf_init(&bout, obuf, sizeof(obuf));
1332 if (s->proto->receive(q, s, &bin, &bout)) continue;
1333 if (q->k) continue;
1334 if (!BLEN(&bout) && s->proto->retransmit(q, s, &bout)) continue;
1335 if (BBAD(&bout)) {
1336 moan("overflow while constructing request!");
1337 continue;
247f344a 1338 }
4efa5091
MW
1339 sendto(sk, BBASE(&bout), BLEN(&bout), 0,
1340 (struct sockaddr *)&s->sin, sizeof(s->sin));
247f344a
MW
1341 }
1342 }
1343 }
1344
1345 /* Check that all of the responses match up and XOR them together. */
1346 n = qq->sz;
1347 if (n > BUFSZ) die(1, "response too large");
1348 memset(obuf, 0, n);
1349 for (q = qq; q; q = q->next) {
1350 if (!q->k) die(1, "INTERNAL: query not complete");
1351 if (q->sz != n) die(1, "inconsistent response sizes");
1352 for (j = 0; j < n; j++) obuf[j] ^= q->k[j];
1353 }
1354
1355 /* Write out the completed answer. */
1356 p = obuf;
1357 while (n) {
1358 if ((nn = write(STDOUT_FILENO, p, n)) < 0)
1359 die(1, "error writing response: %s", strerror(errno));
1360 p += nn; n -= nn;
1361 }
1362 return (0);
1363}
1364
1365/*----- Main program ------------------------------------------------------*/
1366
1367static void usage(FILE *fp)
1368{
1369 pquis(fp, "Usage: \n\
461b1e7f 1370 $ [-OPTS] LABEL {ADDR:PORT[=TAG][#HASH];... | FILE} ...\n\
247f344a
MW
1371 $ [-OPTS] -l [ADDR:]PORT\n\
1372");
1373}
1374
1375static void version(FILE *fp)
a2fd0b74 1376 { pquis(fp, "$, version " VERSION "\n"); }
247f344a
MW
1377
1378static void help(FILE *fp)
1379{
1380 version(fp);
1381 putc('\n', fp);
1382 usage(fp);
1383 fputs("\n\
1384Options:\n\
1385\n\
1386 -d, --daemon Run in the background while listening.\n\
1387 -k, --keyring=FILE Read keys from FILE. [default = `keyring']\n\
1388 -l, --listen Listen for incoming requests and serve keys.\n\
1389 -p, --pidfile=FILE Write process id to FILE if in daemon mode.\n\
1390 -r, --random=FILE Key random number generator with contents of FILE.\n\
1391", fp);
1392}
1393
1394int main(int argc, char *argv[])
1395{
1396 int argmin, argmax;
1397 void *k;
1398 size_t sz;
1399
1400 ego(argv[0]);
1401 for (;;) {
1402 static const struct option opts[] = {
1403 { "help", 0, 0, 'h' },
1404 { "version", 0, 0, 'v' },
1405 { "usage", 0, 0, 'u' },
1406 { "daemon", 0, 0, 'd' },
1407 { "keyfile", OPTF_ARGREQ, 0, 'k' },
1408 { "listen", 0, 0, 'l' },
1409 { "pidfile", OPTF_ARGREQ, 0, 'p' },
1410 { "random", OPTF_ARGREQ, 0, 'r' },
1411 { 0 }
1412 };
1413
1414 int i = mdwopt(argc, argv, "hvu" "dk:lp:r:", opts, 0, 0, 0);
1415 if (i < 0) break;
1416
1417 switch (i) {
1418 case 'h': help(stdout); exit(0);
1419 case 'v': version(stdout); exit(0);
1420 case 'u': usage(stdout); exit(0);
1421
1422 case 'd': flags |= f_daemon; break;
1423 case 'k': kfname = optarg; break;
1424 case 'l': flags |= f_listen; break;
1425 case 'p': pidfile = optarg; break;
1426 case 'r':
1427 if (snarf(optarg, &k, &sz))
1428 die(1, "failed to read `%s': %s", optarg, strerror(errno));
1429 rand_key(RAND_GLOBAL, k, sz);
1430 break;
1431
1432 default: flags |= f_bogus; break;
1433 }
1434 }
1435
1436 argv += optind; argc -= optind;
1437 if (flags & f_listen) argmin = argmax = 1;
1438 else argmin = 2, argmax = -1;
1439 if ((flags & f_bogus) || argc < argmin || (argmax >= 0 && argc > argmax))
1440 { usage(stderr); exit(1); }
1441
1442 fwatch_init(&kfwatch, kfname);
1443 kf = CREATE(key_file);
1444 if (key_open(kf, kfname, KOPEN_READ, keymoan, 0))
1445 die(1, "failed to open keyring file `%s'", kfname);
1446
1447 rand_noisesrc(RAND_GLOBAL, &noise_source);
1448 rand_seed(RAND_GLOBAL, 512);
1449
1450 if (flags & f_listen) return dolisten(argc, argv);
1451 else return doquery(argc, argv);
1452}
1453
1454/*----- That's all, folks -------------------------------------------------*/