chiark / gitweb /
Upgrade licence to GPLv3+.
[tripe] / server / keyexch.c
1 /* -*-c-*-
2  *
3  * Key exchange protocol
4  *
5  * (c) 2001 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Trivial IP Encryption (TrIPE).
11  *
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.
16  *
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.
21  *
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/>.
24  */
25
26 /*----- Header files ------------------------------------------------------*/
27
28 #include "tripe.h"
29
30 /*----- Brief protocol overview -------------------------------------------*
31  *
32  * Let %$G$% be a cyclic group; let %$g$% be a generator of %$G$%, and let
33  * %$q$% be the order of %$G$%; for a key %$K$%, let %$E_K(\cdot)$% denote
34  * application of the symmetric packet protocol to a message; let
35  * %$H(\cdot)$% be the random oracle.  Let $\alpha \inr \{0,\ldots,q - 1\}$%
36  * be Alice's private key; let %$a = g^\alpha$% be her public key; let %$b$%
37  * be Bob's public key.
38  *
39  * At the beginning of the session, Alice chooses
40  *
41  *   %$\rho_A \inr \{0, \ldots q - 1\}$%
42  *
43  * We also have:
44  *
45  * %$r_A = g^{\rho_A}$%                 Alice's challenge
46  * %$c_A = H(\cookie{cookie}, r_A)$%    Alice's cookie
47  * %$v_A = \rho_A \xor H(\cookie{expected-reply}, a, r_A, r_B, b^{\rho_A})$%
48  *                                      Alice's challenge check value
49  * %$r_B^\alpha = a^{\rho_B}$%          Alice's reply
50  * %$K = r_B^{\rho_A} = r_B^{\rho_A} = g^{\rho_A\rho_B}$%
51  *                                      Alice and Bob's shared secret key
52  * %$w_A = H(\cookie{switch-request}, c_A, c_B)$%
53  *                                      Alice's switch request value
54  * %$u_A = H(\cookie{switch-confirm}, c_A, c_B)$%
55  *                                      Alice's switch confirm value
56  *
57  * The messages are then:
58  *
59  * %$\cookie{kx-pre-challenge}, r_A$%
60  *      Initial greeting.  In state @KXS_CHAL@.
61  *
62  * %$\cookie{kx-challenge}, r_A, c_B, v_A$%
63  *      Here's a full challenge for you to answer.
64  *
65  * %$\cookie{kx-reply}, r_A, c_B, v_A, E_K(r_B^\alpha))$%
66  *      Challenge accpeted: here's the answer.  Commit to my challenge.  Move
67  *      to @KXS_COMMIT@.
68  *
69  * %$\cookie{kx-switch-rq}, c_A, c_B, E_K(r_B^\alpha, w_A))$%
70  *      Reply received: here's my reply.  Committed; send data; move to
71  *      @KXS_SWITCH@.
72  *
73  * %$\cookie{kx-switch-ok}, E_K(u_A))$%
74  *      Switch received.  Committed; send data; move to @KXS_SWITCH@.
75  */
76
77 /*----- Static tables -----------------------------------------------------*/
78
79 static const char *const pkname[] = {
80   "pre-challenge", "challenge", "reply", "switch-rq", "switch-ok"
81 };
82
83 /*----- Various utilities -------------------------------------------------*/
84
85 /* --- @VALIDP@ --- *
86  *
87  * Arguments:   @const keyexch *kx@ = key exchange state
88  *              @time_t now@ = current time in seconds
89  *
90  * Returns:     Whether the challenge in the key-exchange state is still
91  *              valid or should be regenerated.
92  */
93
94 #define VALIDP(kx, now) ((now) < (kx)->t_valid)
95
96 /* --- @hashge@ --- *
97  *
98  * Arguments:   @ghash *h@ = pointer to hash context
99  *              @const dhgrp *g@ = pointer to group
100  *              @const dhge *Y@ = pointer to group element
101  *
102  * Returns:     ---
103  *
104  * Use:         Adds the hash of a group element to the context.  Corrupts
105  *              @buf_t@.
106  */
107
108 static void hashge(ghash *h, const dhgrp *g, const dhge *Y)
109 {
110   buf b;
111
112   buf_init(&b, buf_t, sizeof(buf_t));
113   g->ops->stge(g, &b, Y, DHFMT_HASH);
114   assert(BOK(&b));
115   GH_HASH(h, BBASE(&b), BLEN(&b));
116 }
117
118 /* --- @mpmask@ --- *
119  *
120  * Arguments:   @buf *b@ = output buffer
121  *              @const dhgrp *g@ = the group
122  *              @const dhsc *x@ = the plaintext scalar
123  *              @size_t n@ = the expected size of the plaintext
124  *              @gcipher *mgfc@ = mask-generating function to use
125  *              @const octet *k@ = pointer to key material
126  *              @size_t ksz@ = size of the key
127  *
128  * Returns:     ---
129  *
130  * Use:         Masks a scalar: returns %$x \xor H(k)$%, so it's a random
131  *              oracle thing rather than an encryption thing.  Breaks the
132  *              output buffer on error.
133  */
134
135 static void mpmask(buf *b, const dhgrp *g, const dhsc *x, size_t n,
136                    const gccipher *mgfc, const octet *k, size_t ksz)
137 {
138   gcipher *mgf;
139   octet *p;
140
141   if ((p = buf_get(b, n)) == 0) return;
142   mgf = GC_INIT(mgfc, k, ksz);
143   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
144     trace(T_CRYPTO, "crypto: masking scalar = %s", g->ops->scstr(g, x));
145     trace_block(T_CRYPTO, "crypto: masking key", k, ksz);
146   }))
147   if (g->ops->stsc(g, buf_t, n, x)) { buf_break(b); return; }
148   GC_ENCRYPT(mgf, buf_t, p, n);
149   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
150     trace_block(T_CRYPTO, "crypto: scalar plaintext", buf_t, n);
151     trace_block(T_CRYPTO, "crypto: masked ciphertext", p, n);
152   }))
153   GC_DESTROY(mgf);
154 }
155
156 /* --- @mpunmask@ --- *
157  *
158  * Arguments:   @const dhgrp *g@ = the group
159  *              @const octet *p@ = pointer to the ciphertext
160  *              @size_t n@ = the size of the ciphertext
161  *              @gcipher *mgfc@ = mask-generating function to use
162  *              @const octet *k@ = pointer to key material
163  *              @size_t ksz@ = size of the key
164  *
165  * Returns:     The decrypted scalar, or null.
166  *
167  * Use:         Unmasks a scalar.
168  */
169
170 static dhsc *mpunmask(const dhgrp *g, const octet *p, size_t n,
171                       const gccipher *mgfc, const octet *k, size_t ksz)
172 {
173   gcipher *mgf;
174   dhsc *x;
175
176   mgf = GC_INIT(mgfc, k, ksz);
177   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
178     trace_block(T_CRYPTO, "crypto: unmasking key", k, ksz);
179     trace_block(T_CRYPTO, "crypto: masked ciphertext", p, n);
180   }))
181   GC_DECRYPT(mgf, p, buf_t, n);
182   x = g->ops->ldsc(g, buf_t, n);
183   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
184     trace_block(T_CRYPTO, "crypto: scalar plaintext", buf_t, n);
185     trace(T_CRYPTO, "crypto: unmasked scalar = %s",
186           x ? g->ops->scstr(g, x) : "<failed>");
187   }))
188   GC_DESTROY(mgf);
189   return (x);
190 }
191
192 /* --- @hashcheck@ --- *
193  *
194  * Arguments:   @keyexch *kx@ = pointer to key-exchange block
195  *              @const dhge *K@ = sender's public key
196  *              @const dhge *CC@ = receiver's challenge
197  *              @const dhge *C@ = sender's challenge
198  *              @const dhge *Y@ = reply to sender's challenge
199  *
200  * Returns:     Pointer to the hash value (in @buf_t@)
201  *
202  * Use:         Computes the check-value hash, used to mask or unmask
203  *              indices to prove the validity of challenges.  This computes
204  *              the masking key used in challenge check values.  This is
205  *              really the heart of the whole thing, since it ensures that
206  *              the scalar can be recovered from the history of hashing
207  *              queries, which gives us (a) a proof that the authentication
208  *              process is zero-knowledge, and (b) a proof that the whole
209  *              key-exchange is deniable.
210  */
211
212 static const octet *hashcheck(keyexch *kx, const dhge *K,
213                               const dhge *CC, const dhge *C, const dhge *Y)
214 {
215   ghash *h = GH_INIT(kx->kpriv->algs.h);
216   const dhgrp *g = kx->kpriv->grp;
217
218   HASH_STRING(h, "tripe-expected-reply");
219   hashge(h, g, K);
220   hashge(h, g, CC);
221   hashge(h, g, C);
222   hashge(h, g, Y);
223   GH_DONE(h, buf_t);
224   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
225     trace(T_CRYPTO, "crypto: computing challenge check hash");
226     trace(T_CRYPTO, "crypto: public key = %s", g->ops->gestr(g, K));
227     trace(T_CRYPTO, "crypto: receiver challenge = %s", g->ops->gestr(g, CC));
228     trace(T_CRYPTO, "crypto: sender challenge = %s", g->ops->gestr(g, C));
229     trace(T_CRYPTO, "crypto: sender reply = %s", g->ops->gestr(g, Y));
230     trace_block(T_CRYPTO, "crypto: hash output", buf_t, kx->kpriv->algs.hashsz);
231   }))
232   GH_DESTROY(h);
233   return (buf_t);
234 }
235
236 /* --- @sendchallenge@ --- *
237  *
238  * Arguments:   @keyexch *kx@ = pointer to key exchange block
239  *              @buf *b@ = output buffer for challenge
240  *              @const dhge *C@ = peer's actual challenge
241  *              @const octet *hc@ = peer's challenge cookie
242  *
243  * Returns:     ---
244  *
245  * Use:         Writes a full challenge to the message buffer.
246  */
247
248 static void sendchallenge(keyexch *kx, buf *b,
249                           const dhge *C, const octet *hc)
250 {
251   const dhgrp *g = kx->kpriv->grp;
252   g->ops->stge(g, b, kx->C, DHFMT_VAR);
253   buf_put(b, hc, kx->kpriv->algs.hashsz);
254   mpmask(b, g, kx->a, g->scsz, kx->kpriv->algs.mgf,
255          hashcheck(kx, kx->kpriv->K, C, kx->C, kx->RX),
256          kx->kpriv->algs.hashsz);
257 }
258
259 /* --- @timer@ --- *
260  *
261  * Arguments:   @struct timeval *tv@ = the current time
262  *              @void *v@ = pointer to key exchange context
263  *
264  * Returns:     ---
265  *
266  * Use:         Acts when the key exchange timer goes off.
267  */
268
269 static void timer(struct timeval *tv, void *v)
270 {
271   keyexch *kx = v;
272   kx->f &= ~KXF_TIMER;
273   T( trace(T_KEYEXCH, "keyexch: timer has popped"); )
274   kx_start(kx, 0);
275 }
276
277 /* --- @settimer@ --- *
278  *
279  * Arguments:   @keyexch *kx@ = pointer to key exchange context
280  *              @struct timeval *tv@ = when to set the timer for
281  *
282  * Returns:     ---
283  *
284  * Use:         Sets the timer for the next key exchange attempt.
285  */
286
287 static void settimer(keyexch *kx, struct timeval *tv)
288 {
289   if (kx->f & KXF_TIMER) sel_rmtimer(&kx->t);
290   sel_addtimer(&sel, &kx->t, tv, timer, kx);
291   kx->f |= KXF_TIMER;
292 }
293
294 /* --- @f2tv@ --- *
295  *
296  * Arguments:   @struct timeval *tv@ = where to write the timeval
297  *              @double t@ = a time as a floating point number
298  *
299  * Returns:     ---
300  *
301  * Use:         Converts a floating-point time into a timeval.
302  */
303
304 static void f2tv(struct timeval *tv, double t)
305 {
306   tv->tv_sec = t;
307   tv->tv_usec = (t - tv->tv_sec)*MILLION;
308 }
309
310 /* --- @wobble@ --- *
311  *
312  * Arguments:   @double t@ = a time interval
313  *
314  * Returns:     The same time interval, with a random error applied.
315  */
316
317 static double wobble(double t)
318 {
319   uint32 r = rand_global.ops->word(&rand_global);
320   double w = (r/F_2P32) - 0.5;
321   return (t + t*w*T_WOBBLE);
322 }
323
324 /* --- @rs_time@ --- *
325  *
326  * Arguments:   @retry *rs@ = current retry state
327  *              @struct timeval *tv@ = where to write the result
328  *              @const struct timeval *now@ = current time, or null
329  *
330  * Returns:     ---
331  *
332  * Use:         Computes a time at which to retry sending a key-exchange
333  *              packet.  This algorithm is subject to change, but it's
334  *              currently a capped exponential backoff, slightly randomized
335  *              to try to keep clients from hammering a server that's only
336  *              just woken up.
337  *
338  *              If @now@ is null then the function works out the time for
339  *              itself.
340  */
341
342 static void rs_time(retry *rs, struct timeval *tv, const struct timeval *now)
343 {
344   double t;
345   struct timeval rtv;
346
347   if (!rs->t)
348     t = SEC(2);
349   else {
350     t = (rs->t * 5)/4;
351     if (t > MIN(5)) t = MIN(5);
352   }
353   rs->t = t;
354
355   if (!now) {
356     now = tv;
357     gettimeofday(tv, 0);
358   }
359   f2tv(&rtv, wobble(t));
360   TV_ADD(tv, now, &rtv);
361 }
362
363 /* --- @retry_reset@ --- *
364  *
365  * Arguments:   @retry *rs@ = retry state
366  *
367  * Returns:     --
368  *
369  * Use:         Resets a retry state to indicate that progress has been
370  *              made.  Also useful for initializing the state in the first
371  *              place.
372  */
373
374 static void rs_reset(retry *rs) { rs->t = 0; }
375
376 /*----- Challenge management ----------------------------------------------*/
377
378 /* --- Notes on challenge management --- *
379  *
380  * We may get multiple different replies to our key exchange; some will be
381  * correct, some inserted by attackers.  Up until @KX_THRESH@, all challenges
382  * received will be added to the table and given a full response.  After
383  * @KX_THRESH@ distinct challenges are received, we return only a `cookie':
384  * our existing challenge, followed by a hash of the sender's challenge.  We
385  * do %%\emph{not}%% give a bare challenge a reply slot at this stage.  All
386  * properly-formed cookies are assigned a table slot: if none is spare, a
387  * used slot is randomly selected and destroyed.  A cookie always receives a
388  * full reply.
389  */
390
391 /* --- @kxc_destroy@ --- *
392  *
393  * Arguments:   @kxchal *kxc@ = pointer to the challenge block
394  *
395  * Returns:     ---
396  *
397  * Use:         Disposes of a challenge block.
398  */
399
400 static void kxc_destroy(kxchal *kxc)
401 {
402   const dhgrp *g = kxc->kx->kpriv->grp;
403   if (kxc->f & KXF_TIMER)
404     sel_rmtimer(&kxc->t);
405   g->ops->freege(g, kxc->C);
406   g->ops->freege(g, kxc->R);
407   ks_drop(kxc->ks);
408   DESTROY(kxc);
409 }
410
411 /* --- @kxc_stoptimer@ --- *
412  *
413  * Arguments:   @kxchal *kxc@ = pointer to the challenge block
414  *
415  * Returns:     ---
416  *
417  * Use:         Stops the challenge's retry timer from sending messages.
418  *              Useful when the state machine is in the endgame of the
419  *              exchange.
420  */
421
422 static void kxc_stoptimer(kxchal *kxc)
423 {
424   if (kxc->f & KXF_TIMER)
425     sel_rmtimer(&kxc->t);
426   kxc->f &= ~KXF_TIMER;
427 }
428
429 /* --- @kxc_new@ --- *
430  *
431  * Arguments:   @keyexch *kx@ = pointer to key exchange block
432  *
433  * Returns:     A pointer to the challenge block.
434  *
435  * Use:         Returns a pointer to a new challenge block to fill in.
436  *              In particular, the @c@ and @r@ members are left
437  *              uninitialized.
438  */
439
440 static kxchal *kxc_new(keyexch *kx)
441 {
442   kxchal *kxc;
443   unsigned i;
444
445   /* --- If we're over reply threshold, discard one at random --- */
446
447   if (kx->nr < KX_NCHAL)
448     i = kx->nr++;
449   else {
450     i = rand_global.ops->range(&rand_global, KX_NCHAL);
451     kxc_destroy(kx->r[i]);
452   }
453
454   /* --- Fill in the new structure --- */
455
456   kxc = CREATE(kxchal);
457   kxc->ks = 0;
458   kxc->kx = kx;
459   kxc->f = 0;
460   kx->r[i] = kxc;
461   rs_reset(&kxc->rs);
462   return (kxc);
463 }
464
465 /* --- @kxc_bychal@ --- *
466  *
467  * Arguments:   @keyexch *kx@ = pointer to key exchange block
468  *              @const dhge *C@ = challenge from remote host
469  *
470  * Returns:     Pointer to the challenge block, or null.
471  *
472  * Use:         Finds a challenge block, given its challenge.
473  */
474
475 static kxchal *kxc_bychal(keyexch *kx, const dhge *C)
476 {
477   const dhgrp *g = kx->kpriv->grp;
478   unsigned i;
479
480   for (i = 0; i < kx->nr; i++) {
481     if (g->ops->eq(g, C, kx->r[i]->C))
482       return (kx->r[i]);
483   }
484   return (0);
485 }
486
487 /* --- @kxc_byhc@ --- *
488  *
489  * Arguments:   @keyexch *kx@ = pointer to key exchange block
490  *              @const octet *hc@ = challenge hash from remote host
491  *
492  * Returns:     Pointer to the challenge block, or null.
493  *
494  * Use:         Finds a challenge block, given a hash of its challenge.
495  */
496
497 static kxchal *kxc_byhc(keyexch *kx, const octet *hc)
498 {
499   unsigned i;
500
501   for (i = 0; i < kx->nr; i++) {
502     if (memcmp(hc, kx->r[i]->hc, kx->kpriv->algs.hashsz) == 0)
503       return (kx->r[i]);
504   }
505   return (0);
506 }
507
508 /* --- @kxc_answer@ --- *
509  *
510  * Arguments:   @keyexch *kx@ = pointer to key exchange block
511  *              @kxchal *kxc@ = pointer to challenge block
512  *
513  * Returns:     ---
514  *
515  * Use:         Sends a reply to the remote host, according to the data in
516  *              this challenge block.
517  */
518
519 static void kxc_answer(keyexch *kx, kxchal *kxc);
520
521 static void kxc_timer(struct timeval *tv, void *v)
522 {
523   kxchal *kxc = v;
524   kxc->f &= ~KXF_TIMER;
525   kxc_answer(kxc->kx, kxc);
526 }
527
528 static void kxc_answer(keyexch *kx, kxchal *kxc)
529 {
530   stats *st = p_stats(kx->p);
531   buf *b = p_txstart(kx->p, MSG_KEYEXCH | KX_REPLY);
532   const dhgrp *g = kx->kpriv->grp;
533   struct timeval tv;
534   buf bb;
535
536   /* --- Build the reply packet --- */
537
538   T( trace(T_KEYEXCH, "keyexch: sending reply to `%s'", p_name(kx->p)); )
539   sendchallenge(kx, b, kxc->C, kxc->hc);
540   buf_init(&bb, buf_i, sizeof(buf_i));
541   g->ops->stge(g, &bb, kxc->R, DHFMT_STD);
542   buf_flip(&bb);
543   ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_REPLY, &bb, b);
544
545   /* --- Update the statistics --- */
546
547   if (BOK(b)) {
548     st->n_kxout++;
549     st->sz_kxout += BLEN(b);
550     p_txend(kx->p);
551   }
552
553   /* --- Schedule another resend --- */
554
555   if (kxc->f & KXF_TIMER)
556     sel_rmtimer(&kxc->t);
557   gettimeofday(&tv, 0);
558   rs_time(&kxc->rs, &tv, &tv);
559   sel_addtimer(&sel, &kxc->t, &tv, kxc_timer, kxc);
560   kxc->f |= KXF_TIMER;
561 }
562
563 /*----- Individual message handlers ---------------------------------------*/
564
565 /* --- @doprechallenge@ --- *
566  *
567  * Arguments:   @keyexch *kx@ = pointer to key exchange block
568  *              @buf *b@ = buffer containing the packet
569  *
570  * Returns:     Zero if OK, nonzero of the packet was rejected.
571  *
572  * Use:         Processes a pre-challenge message.
573  */
574
575 static int doprechallenge(keyexch *kx, buf *b)
576 {
577   stats *st = p_stats(kx->p);
578   const dhgrp *g = kx->kpriv->grp;
579   dhge *C = 0;
580   ghash *h;
581
582   /* --- Ensure that we're in a sensible state --- */
583
584   if (kx->s != KXS_CHAL) {
585     a_warn("KX", "?PEER", kx->p, "unexpected", "pre-challenge", A_END);
586     goto bad;
587   }
588
589   /* --- Unpack the packet --- */
590
591   if ((C = g->ops->ldge(g, b, DHFMT_VAR)) == 0 || BLEFT(b))
592     goto bad;
593
594   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
595     trace(T_CRYPTO, "crypto: challenge = %s", g->ops->gestr(g, C));
596   }))
597
598   /* --- Send out a full challenge by return --- */
599
600   b = p_txstart(kx->p, MSG_KEYEXCH | KX_CHAL);
601   h = GH_INIT(kx->kpriv->algs.h);
602   HASH_STRING(h, "tripe-cookie");
603   hashge(h, g, C);
604   sendchallenge(kx, b, C, GH_DONE(h, 0));
605   GH_DESTROY(h);
606   st->n_kxout++;
607   st->sz_kxout += BLEN(b);
608   p_txend(kx->p);
609
610   /* --- Done --- */
611
612   g->ops->freege(g, C);
613   return (0);
614
615 bad:
616   if (C) g->ops->freege(g, C);
617   return (-1);
618 }
619
620 /* --- @respond@ --- *
621  *
622  * Arguments:   @keyexch *kx@ = pointer to key exchange block
623  *              @unsigned msg@ = message code for this packet
624  *              @buf *b@ = buffer containing the packet
625  *
626  * Returns:     Key-exchange challenge block, or null.
627  *
628  * Use:         Computes a response for the given challenge, entering it into
629  *              a challenge block and so on.
630  */
631
632 static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
633 {
634   const dhgrp *g = kx->kpriv->grp;
635   const algswitch *algs = &kx->kpriv->algs;
636   size_t ixsz = g->scsz;
637   dhge *C = 0;
638   dhge *R = 0;
639   dhge *CC = 0;
640   const octet *hc, *ck;
641   size_t x, y, z;
642   dhsc *c = 0;
643   kxchal *kxc;
644   ghash *h = 0;
645   buf bb;
646   int ok;
647
648   /* --- Unpack the packet --- */
649
650   if ((C = g->ops->ldge(g, b, DHFMT_VAR)) == 0 ||
651       (hc = buf_get(b, algs->hashsz)) == 0 ||
652       (ck = buf_get(b, ixsz)) == 0) {
653     a_warn("KX", "?PEER", kx->p, "invalid", "%s", pkname[msg], A_END);
654     goto bad;
655   }
656   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
657     trace(T_CRYPTO, "crypto: challenge = %s", g->ops->gestr(g, C));
658     trace_block(T_CRYPTO, "crypto: cookie", hc, algs->hashsz);
659     trace_block(T_CRYPTO, "crypto: check-value", ck, ixsz);
660   }))
661
662   /* --- Discard a packet with an invalid cookie --- */
663
664   if (hc && memcmp(hc, kx->hc, algs->hashsz) != 0) {
665     a_warn("KX", "?PEER", kx->p, "incorrect", "cookie", A_END);
666     goto bad;
667   }
668
669   /* --- Recover the check value and verify it --- *
670    *
671    * To avoid recomputation on replays, we store a hash of the `right'
672    * value.  The `correct' value is unique, so this is right.
673    *
674    * This will also find a challenge block and, if necessary, populate it.
675    */
676
677   if ((kxc = kxc_bychal(kx, C)) != 0) {
678     h = GH_INIT(algs->h);
679     HASH_STRING(h, "tripe-check-hash");
680     GH_HASH(h, ck, ixsz);
681     ok = !memcmp(kxc->ck, GH_DONE(h, 0), algs->hashsz);
682     GH_DESTROY(h);
683     if (!ok) goto badcheck;
684   } else {
685
686     /* --- Compute the reply, and check the magic --- */
687
688     R = g->ops->mul(g, kx->kpriv->k, C);
689     if ((c = mpunmask(g, ck, ixsz, algs->mgf,
690                       hashcheck(kx, kx->kpub->K, kx->C, C, R),
691                       algs->hashsz)) == 0)
692       goto badcheck;
693     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
694       trace(T_CRYPTO, "crypto: computed reply = %s", g->ops->gestr(g, R));
695       trace(T_CRYPTO, "crypto: recovered log = %s", g->ops->scstr(g, c));
696     }))
697     CC = g->ops->mul(g, c, 0);
698     if (!g->ops->eq(g, CC, C)) goto badcheck;
699
700     /* --- Fill in a new challenge block --- */
701
702     kxc = kxc_new(kx);
703     kxc->C = C; C = 0;
704     kxc->R = R; R = 0;
705
706     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-check-hash");
707     GH_HASH(h, ck, ixsz);
708     GH_DONE(h, kxc->ck); GH_DESTROY(h);
709
710     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-cookie");
711     hashge(h, g, kxc->C);
712     GH_DONE(h, kxc->hc); GH_DESTROY(h);
713
714     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
715       trace_block(T_CRYPTO, "crypto: computed cookie",
716                   kxc->hc, algs->hashsz);
717     }))
718
719     /* --- Work out the shared key --- */
720
721     R = g->ops->mul(g, kx->a, kxc->C);
722     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
723       trace(T_CRYPTO, "crypto: shared secret = %s", g->ops->gestr(g, R));
724     }))
725
726     /* --- Compute the switch messages --- */
727
728     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-request");
729     hashge(h, g, kx->C); hashge(h, g, kxc->C);
730     GH_DONE(h, kxc->hswrq_out); GH_DESTROY(h);
731     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-confirm");
732     hashge(h, g, kx->C); hashge(h, g, kxc->C);
733     GH_DONE(h, kxc->hswok_out); GH_DESTROY(h);
734
735     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-request");
736     hashge(h, g, kxc->C); hashge(h, g, kx->C);
737     GH_DONE(h, kxc->hswrq_in); GH_DESTROY(h);
738     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-confirm");
739     hashge(h, g, kxc->C); hashge(h, g, kx->C);
740     GH_DONE(h, kxc->hswok_in); GH_DESTROY(h);
741
742     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
743       trace_block(T_CRYPTO, "crypto: outbound switch request",
744                   kxc->hswrq_out, algs->hashsz);
745       trace_block(T_CRYPTO, "crypto: outbound switch confirm",
746                   kxc->hswok_out, algs->hashsz);
747       trace_block(T_CRYPTO, "crypto: inbound switch request",
748                   kxc->hswrq_in, algs->hashsz);
749       trace_block(T_CRYPTO, "crypto: inbound switch confirm",
750                   kxc->hswok_in, algs->hashsz);
751     }))
752
753     /* --- Create a new symmetric keyset --- */
754
755     buf_init(&bb, buf_o, sizeof(buf_o));
756     g->ops->stge(g, &bb, kx->C, DHFMT_HASH); x = BLEN(&bb);
757     g->ops->stge(g, &bb, kxc->C, DHFMT_HASH); y = BLEN(&bb);
758     g->ops->stge(g, &bb, R, DHFMT_HASH); z = BLEN(&bb);
759     assert(BOK(&bb));
760
761     kxc->ks = ks_gen(BBASE(&bb), x, y, z, kx->p);
762   }
763
764   if (C) g->ops->freege(g, C);
765   if (CC) g->ops->freege(g, CC);
766   if (R) g->ops->freege(g, R);
767   if (c) g->ops->freesc(g, c);
768   return (kxc);
769
770 badcheck:
771   a_warn("KX", "?PEER", kx->p, "bad-expected-reply-log", A_END);
772   goto bad;
773 bad:
774   if (C) g->ops->freege(g, C);
775   if (CC) g->ops->freege(g, CC);
776   if (R) g->ops->freege(g, R);
777   if (c) g->ops->freesc(g, c);
778   return (0);
779 }
780
781 /* --- @dochallenge@ --- *
782  *
783  * Arguments:   @keyexch *kx@ = pointer to key exchange block
784  *              @unsigned msg@ = message code for the packet
785  *              @buf *b@ = buffer containing the packet
786  *
787  * Returns:     Zero if OK, nonzero if the packet was rejected.
788  *
789  * Use:         Processes a packet containing a challenge.
790  */
791
792 static int dochallenge(keyexch *kx, buf *b)
793 {
794   kxchal *kxc;
795
796   if (kx->s != KXS_CHAL) {
797     a_warn("KX", "?PEER", kx->p, "unexpected", "challenge", A_END);
798     goto bad;
799   }
800   if ((kxc = respond(kx, KX_CHAL, b)) == 0)
801     goto bad;
802   if (BLEFT(b)) {
803     a_warn("KX", "?PEER", kx->p, "invalid", "challenge", A_END);
804     goto bad;
805   }
806   kxc_answer(kx, kxc);
807   return (0);
808
809 bad:
810   return (-1);
811 }
812
813 /* --- @resend@ --- *
814  *
815  * Arguments:   @keyexch *kx@ = pointer to key exchange context
816  *
817  * Returns:     ---
818  *
819  * Use:         Sends the next message for a key exchange.
820  */
821
822 static void resend(keyexch *kx)
823 {
824   kxchal *kxc;
825   buf bb;
826   stats *st = p_stats(kx->p);
827   struct timeval tv;
828   const dhgrp *g = kx->kpriv->grp;
829   buf *b;
830
831   switch (kx->s) {
832     case KXS_CHAL:
833       T( trace(T_KEYEXCH, "keyexch: sending prechallenge to `%s'",
834                p_name(kx->p)); )
835       b = p_txstart(kx->p, MSG_KEYEXCH | KX_PRECHAL);
836       g->ops->stge(g, b, kx->C, DHFMT_VAR);
837       break;
838     case KXS_COMMIT:
839       T( trace(T_KEYEXCH, "keyexch: sending switch request to `%s'",
840                p_name(kx->p)); )
841       kxc = kx->r[0];
842       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCH);
843       buf_put(b, kx->hc, kx->kpriv->algs.hashsz);
844       buf_put(b, kxc->hc, kx->kpriv->algs.hashsz);
845       buf_init(&bb, buf_i, sizeof(buf_i));
846       g->ops->stge(g, &bb, kxc->R, DHFMT_STD);
847       buf_put(&bb, kxc->hswrq_out, kx->kpriv->algs.hashsz);
848       buf_flip(&bb);
849       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b);
850       break;
851     case KXS_SWITCH:
852       T( trace(T_KEYEXCH, "keyexch: sending switch confirmation to `%s'",
853                p_name(kx->p)); )
854       kxc = kx->r[0];
855       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCHOK);
856       buf_init(&bb, buf_i, sizeof(buf_i));
857       buf_put(&bb, kxc->hswok_out, kx->kpriv->algs.hashsz);
858       buf_flip(&bb);
859       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, &bb, b);
860       break;
861     default:
862       abort();
863   }
864
865   if (BOK(b)) {
866     st->n_kxout++;
867     st->sz_kxout += BLEN(b);
868     p_txend(kx->p);
869   }
870
871   if (kx->s < KXS_SWITCH) {
872     rs_time(&kx->rs, &tv, 0);
873     settimer(kx, &tv);
874   }
875 }
876
877 /* --- @decryptrest@ --- *
878  *
879  * Arguments:   @keyexch *kx@ = pointer to key exchange context
880  *              @kxchal *kxc@ = pointer to challenge block
881  *              @unsigned msg@ = type of incoming message
882  *              @buf *b@ = encrypted remainder of the packet
883  *
884  * Returns:     Zero if OK, nonzero on some kind of error.
885  *
886  * Use:         Decrypts the remainder of the packet, and points @b@ at the
887  *              recovered plaintext.
888  */
889
890 static int decryptrest(keyexch *kx, kxchal *kxc, unsigned msg, buf *b)
891 {
892   buf bb;
893
894   buf_init(&bb, buf_o, sizeof(buf_o));
895   if (ks_decrypt(kxc->ks, MSG_KEYEXCH | msg, b, &bb)) {
896     a_warn("KX", "?PEER", kx->p, "decrypt-failed", "%s", pkname[msg], A_END);
897     return (-1);
898   }
899   if (!BOK(&bb)) return (-1);
900   buf_init(b, BBASE(&bb), BLEN(&bb));
901   return (0);
902 }
903
904 /* --- @checkresponse@ --- *
905  *
906  * Arguments:   @keyexch *kx@ = pointer to key exchange context
907  *              @unsigned msg@ = type of incoming message
908  *              @buf *b@ = decrypted remainder of the packet
909  *
910  * Returns:     Zero if OK, nonzero on some kind of error.
911  *
912  * Use:         Checks a reply or switch packet, ensuring that its response
913  *              is correct.
914  */
915
916 static int checkresponse(keyexch *kx, unsigned msg, buf *b)
917 {
918   const dhgrp *g = kx->kpriv->grp;
919   dhge *R;
920
921   if ((R = g->ops->ldge(g, b, DHFMT_STD)) == 0) {
922     a_warn("KX", "?PEER", kx->p, "invalid", "%s", pkname[msg], A_END);
923     goto bad;
924   }
925   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
926     trace(T_CRYPTO, "crypto: reply = %s", g->ops->gestr(g, R));
927   }))
928   if (!g->ops->eq(g, R, kx->RX)) {
929     a_warn("KX", "?PEER", kx->p, "incorrect", "response", A_END);
930     goto bad;
931   }
932
933   g->ops->freege(g, R);
934   return (0);
935
936 bad:
937   if (R) g->ops->freege(g, R);
938   return (-1);
939 }
940
941 /* --- @commit@ --- *
942  *
943  * Arguments:   @keyexch *kx@ = pointer to key exchange context
944  *              @kxchal *kxc@ = pointer to challenge to commit to
945  *
946  * Returns:     ---
947  *
948  * Use:         Commits to a particular challenge as being the `right' one,
949  *              since a reply has arrived for it.
950  */
951
952 static void commit(keyexch *kx, kxchal *kxc)
953 {
954   unsigned i;
955
956   for (i = 0; i < kx->nr; i++) {
957     if (kx->r[i] != kxc)
958       kxc_destroy(kx->r[i]);
959   }
960   kx->r[0] = kxc;
961   kx->nr = 1;
962   kxc_stoptimer(kxc);
963   ksl_link(kx->ks, kxc->ks);
964 }
965
966 /* --- @doreply@ --- *
967  *
968  * Arguments:   @keyexch *kx@ = pointer to key exchange context
969  *              @buf *b@ = buffer containing packet
970  *
971  * Returns:     Zero if OK, nonzero if the packet was rejected.
972  *
973  * Use:         Handles a reply packet.  This doesn't handle the various
974  *              switch packets: they're rather too different.
975  */
976
977 static int doreply(keyexch *kx, buf *b)
978 {
979   kxchal *kxc;
980
981   if (kx->s != KXS_CHAL && kx->s != KXS_COMMIT) {
982     a_warn("KX", "?PEER", kx->p, "unexpected", "reply", A_END);
983     goto bad;
984   }
985   if ((kxc = respond(kx, KX_REPLY, b)) == 0 ||
986       decryptrest(kx, kxc, KX_REPLY, b) ||
987       checkresponse(kx, KX_REPLY, b))
988     goto bad;
989   if (BLEFT(b)) {
990     a_warn("KX", "?PEER", kx->p, "invalid", "reply", A_END);
991     goto bad;
992   }
993   if (kx->s == KXS_CHAL) {
994     commit(kx, kxc);
995     kx->s = KXS_COMMIT;
996   }
997   resend(kx);
998   return (0);
999
1000 bad:
1001   return (-1);
1002 }
1003
1004 /* --- @kxfinish@ --- *
1005  *
1006  * Arguments:   @keyexch *kx@ = pointer to key exchange block
1007  *
1008  * Returns:     ---
1009  *
1010  * Use:         Sets everything up following a successful key exchange.
1011  */
1012
1013 static void kxfinish(keyexch *kx)
1014 {
1015   kxchal *kxc = kx->r[0];
1016   struct timeval now, tv;
1017
1018   ks_activate(kxc->ks);
1019   gettimeofday(&now, 0);
1020   f2tv(&tv, wobble(T_REGEN));
1021   TV_ADD(&tv, &now, &tv);
1022   settimer(kx, &tv);
1023   kx->s = KXS_SWITCH;
1024   a_notify("KXDONE", "?PEER", kx->p, A_END);
1025   p_stats(kx->p)->t_kx = time(0);
1026 }
1027
1028 /* --- @doswitch@ --- *
1029  *
1030  * Arguments:   @keyexch *kx@ = pointer to key exchange block
1031  *              @buf *b@ = pointer to buffer containing packet
1032  *
1033  * Returns:     Zero if OK, nonzero if the packet was rejected.
1034  *
1035  * Use:         Handles a reply with a switch request bolted onto it.
1036  */
1037
1038 static int doswitch(keyexch *kx, buf *b)
1039 {
1040   size_t hsz = kx->kpriv->algs.hashsz;
1041   const octet *hc_in, *hc_out, *hswrq;
1042   kxchal *kxc;
1043
1044   if ((hc_in = buf_get(b, hsz)) == 0 ||
1045       (hc_out = buf_get(b, hsz)) == 0) {
1046     a_warn("KX", "?PEER", kx->p, "invalid", "switch-rq", A_END);
1047     goto bad;
1048   }
1049   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
1050     trace_block(T_CRYPTO, "crypto: challenge", hc_in, hsz);
1051     trace_block(T_CRYPTO, "crypto: cookie", hc_out, hsz);
1052   }))
1053   if ((kxc = kxc_byhc(kx, hc_in)) == 0 ||
1054       memcmp(hc_out, kx->hc, hsz) != 0) {
1055     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-rq", A_END);
1056     goto bad;
1057   }
1058   if (decryptrest(kx, kxc, KX_SWITCH, b) ||
1059       checkresponse(kx, KX_SWITCH, b))
1060     goto bad;
1061   if ((hswrq = buf_get(b, hsz)) == 0 || BLEFT(b)) {
1062     a_warn("KX", "?PEER", kx->p, "invalid", "switch-rq", A_END);
1063     goto bad;
1064   }
1065   IF_TRACING(T_KEYEXCH, {
1066     trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, hsz);
1067   })
1068   if (memcmp(hswrq, kxc->hswrq_in, hsz) != 0) {
1069     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-rq", A_END);
1070     goto bad;
1071   }
1072   if (kx->s == KXS_CHAL)
1073     commit(kx, kxc);
1074   if (kx->s < KXS_SWITCH)
1075     kxfinish(kx);
1076   resend(kx);
1077   return (0);
1078
1079 bad:
1080   return (-1);
1081 }
1082
1083 /* --- @doswitchok@ --- *
1084  *
1085  * Arguments:   @keyexch *kx@ = pointer to key exchange block
1086  *              @buf *b@ = pointer to buffer containing packet
1087  *
1088  * Returns:     Zero if OK, nonzero if the packet was rejected.
1089  *
1090  * Use:         Handles a reply with a switch request bolted onto it.
1091  */
1092
1093 static int doswitchok(keyexch *kx, buf *b)
1094 {
1095   size_t hsz = kx->kpriv->algs.hashsz;
1096   const octet *hswok;
1097   kxchal *kxc;
1098   buf bb;
1099
1100   if (kx->s < KXS_COMMIT) {
1101     a_warn("KX", "?PEER", kx->p, "unexpected", "switch-ok", A_END);
1102     goto bad;
1103   }
1104   kxc = kx->r[0];
1105   buf_init(&bb, buf_o, sizeof(buf_o));
1106   if (decryptrest(kx, kxc, KX_SWITCHOK, b))
1107     goto bad;
1108   if ((hswok = buf_get(b, hsz)) == 0 || BLEFT(b)) {
1109     a_warn("KX", "?PEER", kx->p, "invalid", "switch-ok", A_END);
1110     goto bad;
1111   }
1112   IF_TRACING(T_KEYEXCH, {
1113     trace_block(T_CRYPTO, "crypto: switch confirmation hash",
1114                 hswok, hsz);
1115   })
1116   if (memcmp(hswok, kxc->hswok_in, hsz) != 0) {
1117     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-ok", A_END);
1118     goto bad;
1119   }
1120   if (kx->s < KXS_SWITCH)
1121     kxfinish(kx);
1122   return (0);
1123
1124 bad:
1125   return (-1);
1126 }
1127
1128 /*----- Main code ---------------------------------------------------------*/
1129
1130 /* --- @stop@ --- *
1131  *
1132  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1133  *
1134  * Returns:     ---
1135  *
1136  * Use:         Stops a key exchange dead in its tracks.  Throws away all of
1137  *              the context information.  The context is left in an
1138  *              inconsistent state.  The only functions which understand this
1139  *              state are @kx_free@ and @kx_init@ (which cause it internally
1140  *              it), and @start@ (which expects it to be the prevailing
1141  *              state).
1142  */
1143
1144 static void stop(keyexch *kx)
1145 {
1146   const dhgrp *g = kx->kpriv->grp;
1147   unsigned i;
1148
1149   if (kx->f & KXF_DEAD)
1150     return;
1151
1152   if (kx->f & KXF_TIMER)
1153     sel_rmtimer(&kx->t);
1154   for (i = 0; i < kx->nr; i++)
1155     kxc_destroy(kx->r[i]);
1156   g->ops->freesc(g, kx->a);
1157   g->ops->freege(g, kx->C);
1158   g->ops->freege(g, kx->RX);
1159   kx->t_valid = 0;
1160   kx->f |= KXF_DEAD;
1161   kx->f &= ~KXF_TIMER;
1162 }
1163
1164 /* --- @start@ --- *
1165  *
1166  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1167  *              @time_t now@ = the current time
1168  *
1169  * Returns:     ---
1170  *
1171  * Use:         Starts a new key exchange with the peer.  The context must be
1172  *              in the bizarre state left by @stop@ or @kx_init@.
1173  */
1174
1175 static void start(keyexch *kx, time_t now)
1176 {
1177   algswitch *algs = &kx->kpriv->algs;
1178   const dhgrp *g = kx->kpriv->grp;
1179   ghash *h;
1180
1181   assert(kx->f & KXF_DEAD);
1182
1183   kx->f &= ~(KXF_DEAD | KXF_CORK);
1184   kx->nr = 0;
1185   kx->a = g->ops->randsc(g);
1186   kx->C = g->ops->mul(g, kx->a, 0);
1187   kx->RX = g->ops->mul(g, kx->a, kx->kpub->K);
1188   kx->s = KXS_CHAL;
1189   kx->t_valid = now + T_VALID;
1190
1191   h = GH_INIT(algs->h);
1192   HASH_STRING(h, "tripe-cookie");
1193   hashge(h, g, kx->C);
1194   GH_DONE(h, kx->hc);
1195   GH_DESTROY(h);
1196
1197   IF_TRACING(T_KEYEXCH, {
1198     trace(T_KEYEXCH, "keyexch: creating new challenge");
1199     IF_TRACING(T_CRYPTO, {
1200       trace(T_CRYPTO, "crypto: secret = %s", g->ops->scstr(g, kx->a));
1201       trace(T_CRYPTO, "crypto: challenge = %s", g->ops->gestr(g, kx->C));
1202       trace(T_CRYPTO, "crypto: expected response = %s",
1203             g->ops->gestr(g, kx->RX));
1204       trace_block(T_CRYPTO, "crypto: challenge cookie",
1205                   kx->hc, algs->hashsz);
1206     })
1207   })
1208 }
1209
1210 /* --- @checkpub@ --- *
1211  *
1212  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1213  *
1214  * Returns:     Zero if OK, nonzero if the peer's public key has expired.
1215  *
1216  * Use:         Deactivates the key-exchange until the peer acquires a new
1217  *              public key.
1218  */
1219
1220 static int checkpub(keyexch *kx)
1221 {
1222   time_t now;
1223   unsigned f = 0;
1224
1225   if (kx->f & KXF_DEAD)
1226     return (-1);
1227   now = time(0);
1228   if (KEY_EXPIRED(now, kx->kpriv->t_exp)) f |= 1;
1229   if (KEY_EXPIRED(now, kx->kpub->t_exp)) f |= 2;
1230   if (f) {
1231     stop(kx);
1232     if (f & 1) a_warn("KX", "?PEER", kx->p, "private-key-expired", A_END);
1233     if (f & 2) a_warn("KX", "?PEER", kx->p, "public-key-expired", A_END);
1234     kx->f &= ~KXF_PUBKEY;
1235     return (-1);
1236   }
1237   return (0);
1238 }
1239
1240 /* --- @kx_start@ --- *
1241  *
1242  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1243  *              @int forcep@ = nonzero to ignore the quiet timer
1244  *
1245  * Returns:     ---
1246  *
1247  * Use:         Stimulates a key exchange.  If a key exchage is in progress,
1248  *              a new challenge is sent (unless the quiet timer forbids
1249  *              this); if no exchange is in progress, one is commenced.
1250  */
1251
1252 void kx_start(keyexch *kx, int forcep)
1253 {
1254   time_t now = time(0);
1255
1256   if (checkpub(kx))
1257     return;
1258   if (forcep || !VALIDP(kx, now)) {
1259     stop(kx);
1260     start(kx, now);
1261     a_notify("KXSTART", "?PEER", kx->p, A_END);
1262   }
1263   resend(kx);
1264 }
1265
1266 /* --- @kx_message@ --- *
1267  *
1268  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1269  *              @unsigned msg@ = the message code
1270  *              @buf *b@ = pointer to buffer containing the packet
1271  *
1272  * Returns:     ---
1273  *
1274  * Use:         Reads a packet containing key exchange messages and handles
1275  *              it.
1276  */
1277
1278 void kx_message(keyexch *kx, unsigned msg, buf *b)
1279 {
1280   struct timeval now, tv;
1281   stats *st = p_stats(kx->p);
1282   size_t sz = BSZ(b);
1283   int rc;
1284
1285   gettimeofday(&now, 0);
1286   rs_reset(&kx->rs);
1287   if (kx->f & KXF_CORK) {
1288     start(kx, now.tv_sec);
1289     rs_time(&kx->rs, &tv, &now);
1290     settimer(kx, &tv);
1291     a_notify("KXSTART", "?PEER", kx->p, A_END);
1292   }
1293
1294   if (checkpub(kx))
1295     return;
1296
1297   if (!VALIDP(kx, now.tv_sec)) {
1298     stop(kx);
1299     start(kx, now.tv_sec);
1300   }
1301   T( trace(T_KEYEXCH, "keyexch: processing %s packet from `%s'",
1302            msg < KX_NMSG ? pkname[msg] : "unknown", p_name(kx->p)); )
1303
1304   switch (msg) {
1305     case KX_PRECHAL:
1306       rc = doprechallenge(kx, b);
1307       break;
1308     case KX_CHAL:
1309       rc = dochallenge(kx, b);
1310       break;
1311     case KX_REPLY:
1312       rc = doreply(kx, b);
1313       break;
1314     case KX_SWITCH:
1315       rc = doswitch(kx, b);
1316       break;
1317     case KX_SWITCHOK:
1318       rc = doswitchok(kx, b);
1319       break;
1320     default:
1321       a_warn("KX", "?PEER", kx->p, "unknown-message", "0x%02x", msg, A_END);
1322       rc = -1;
1323       break;
1324   }
1325
1326   if (rc)
1327     st->n_reject++;
1328   else {
1329     st->n_kxin++;
1330     st->sz_kxin += sz;
1331   }
1332 }
1333
1334 /* --- @kx_free@ --- *
1335  *
1336  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1337  *
1338  * Returns:     ---
1339  *
1340  * Use:         Frees everything in a key exchange context.
1341  */
1342
1343 void kx_free(keyexch *kx)
1344 {
1345   stop(kx);
1346   km_unref(kx->kpub);
1347   km_unref(kx->kpriv);
1348 }
1349
1350 /* --- @kx_newkeys@ --- *
1351  *
1352  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1353  *
1354  * Returns:     ---
1355  *
1356  * Use:         Informs the key exchange module that its keys may have
1357  *              changed.  If fetching the new keys fails, the peer will be
1358  *              destroyed, we log messages and struggle along with the old
1359  *              keys.
1360  */
1361
1362 void kx_newkeys(keyexch *kx)
1363 {
1364   kdata *kpriv, *kpub;
1365   unsigned i;
1366   int switchp;
1367   time_t now = time(0);
1368
1369   T( trace(T_KEYEXCH, "keyexch: checking new keys for `%s'",
1370            p_name(kx->p)); )
1371
1372   /* --- Find out whether we can use new keys --- *
1373    *
1374    * Try each available combination of new and old, public and private,
1375    * except both old (which is status quo anyway).  The selection is encoded
1376    * in @i@, with bit 0 for the private key and bit 1 for public key; a set
1377    * bit means to use the old value, and a clear bit means to use the new
1378    * one.
1379    *
1380    * This means that we currently prefer `old private and new public' over
1381    * `new private and old public'.  I'm not sure which way round this should
1382    * actually be.
1383    */
1384
1385   for (i = 0; i < 3; i++) {
1386
1387     /* --- Select the keys we're going to examine --- *
1388      *
1389      * If we're meant to have a new key and don't, then skip this
1390      * combination.
1391      */
1392
1393     T( trace(T_KEYEXCH, "keyexch: checking %s private, %s public",
1394              i & 1 ? "old" : "new", i & 2 ? "old" : "new"); )
1395
1396     if (i & 1) kpriv = kx->kpriv;
1397     else if (kx->kpriv->kn->kd != kx->kpriv) kpriv = kx->kpriv->kn->kd;
1398     else {
1399       T( trace(T_KEYEXCH, "keyexch: private key unchanged, skipping"); )
1400       continue;
1401     }
1402
1403     if (i & 2) kpub = kx->kpub;
1404     else if (kx->kpub->kn->kd != kx->kpub) kpub = kx->kpub->kn->kd;
1405     else {
1406       T( trace(T_KEYEXCH, "keyexch: public key unchanged, skipping"); )
1407       continue;
1408     }
1409
1410     /* --- Skip if either key is expired --- *
1411      *
1412      * We're not going to get far with expired keys, and this simplifies the
1413      * logic below.
1414      */
1415
1416     if (KEY_EXPIRED(now, kx->kpriv->t_exp) ||
1417         KEY_EXPIRED(now, kx->kpub->t_exp)) {
1418       T( trace(T_KEYEXCH, "keyexch: %s expired, skipping",
1419                !KEY_EXPIRED(now, kx->kpriv->t_exp) ? "public key" :
1420                !KEY_EXPIRED(now, kx->kpub->t_exp) ? "private key" :
1421                "both keys"); )
1422       continue;
1423     }
1424
1425     /* --- If the groups don't match then we can't use this pair --- */
1426
1427     if (!km_samealgsp(kpriv, kpub)) {
1428       T( trace(T_KEYEXCH, "keyexch: peer `%s' group mismatch; "
1429                "%s priv `%s' and %s pub `%s'", p_name(kx->p),
1430                i & 1 ? "old" : "new", km_tag(kx->kpriv),
1431                i & 2 ? "old" : "new", km_tag(kx->kpub)); )
1432       continue;
1433     }
1434     goto newkeys;
1435   }
1436   T( trace(T_KEYEXCH, "keyexch: peer `%s' continuing with old keys",
1437            p_name(kx->p)); )
1438   return;
1439
1440   /* --- We've chosen new keys --- *
1441    *
1442    * Switch the new ones into place.  Neither of the keys we're switching to
1443    * is expired (we checked that above), so we should just crank everything
1444    * up.
1445    *
1446    * A complication arises: we don't really want to force a new key exchange
1447    * unless we have to.  If the group is unchanged, and we're currently
1448    * running OK, then we should just let things lie.
1449    */
1450
1451 newkeys:
1452   switchp = ((kx->f & KXF_DEAD) ||
1453              kx->s != KXS_SWITCH ||
1454              kpriv->grp->ops != kx->kpriv->grp->ops ||
1455              !kpriv->grp->ops->samegrpp(kpriv->grp, kx->kpriv->grp));
1456
1457   T( trace(T_KEYEXCH, "keyexch: peer `%s' adopting "
1458            "%s priv `%s' and %s pub `%s'; %sforcing exchange", p_name(kx->p),
1459            i & 1 ? "old" : "new", km_tag(kx->kpriv),
1460            i & 2 ? "old" : "new", km_tag(kx->kpub),
1461            switchp ? "" : "not "); )
1462
1463   if (switchp) stop(kx);
1464   km_ref(kpriv); km_unref(kx->kpriv); kx->kpriv = kpriv;
1465   km_ref(kpub);  km_unref(kx->kpub);  kx->kpub  = kpub;
1466   kx->f |= KXF_PUBKEY;
1467   if (switchp) {
1468     T( trace(T_KEYEXCH, "keyexch: restarting key negotiation with `%s'",
1469              p_name(kx->p)); )
1470     start(kx, time(0));
1471     resend(kx);
1472   }
1473 }
1474
1475 /* --- @kx_init@ --- *
1476  *
1477  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1478  *              @peer *p@ = pointer to peer context
1479  *              @keyset **ks@ = pointer to keyset list
1480  *              @unsigned f@ = various useful flags
1481  *
1482  * Returns:     Zero if OK, nonzero if it failed.
1483  *
1484  * Use:         Initializes a key exchange module.  The module currently
1485  *              contains no keys, and will attempt to initiate a key
1486  *              exchange.
1487  */
1488
1489 int kx_init(keyexch *kx, peer *p, keyset **ks, unsigned f)
1490 {
1491   if ((kx->kpriv = km_findpriv(p_privtag(p))) == 0) goto fail_0;
1492   if ((kx->kpub = km_findpub(p_tag(p))) == 0) goto fail_1;
1493   if (!km_samealgsp(kx->kpriv, kx->kpub)) {
1494     a_warn("KX", "?PEER", p, "group-mismatch",
1495            "local-private-key", "%s", p_privtag(p),
1496            "peer-public-key", "%s", p_tag(p),
1497            A_END);
1498     goto fail_2;
1499   }
1500
1501   kx->ks = ks;
1502   kx->p = p;
1503   kx->f = KXF_DEAD | KXF_PUBKEY | f;
1504   rs_reset(&kx->rs);
1505   if (!(kx->f & KXF_CORK)) {
1506     start(kx, time(0));
1507     resend(kx);
1508     /* Don't notify here: the ADD message hasn't gone out yet. */
1509   }
1510   return (0);
1511
1512 fail_2:
1513   km_unref(kx->kpub);
1514 fail_1:
1515   km_unref(kx->kpriv);
1516 fail_0:
1517   return (-1);
1518 }
1519
1520 /*----- That's all, folks -------------------------------------------------*/