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