chiark / gitweb /
6b771224810656df29ca686e10b24b9acc8063a5
[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 /* --- @notice_message@ --- *
377  *
378  * Arguments:   @keyexch *kx@ = pointer to key-exchange block
379  *
380  * Returns:     Zero if OK; @-1@ if the public key is in a bad state.
381  *
382  * Use:         Updates the key-exchange state following a received message.
383  *              Specifically, if there's no currently active key-exchange in
384  *              progress, and we're not in the cooling-off period, then
385  *              commence a new one; reset the retry timers; and if we're
386  *              corked then pop the cork so that we can reply.
387  */
388
389 static int checkpub(keyexch *kx);
390 static void stop(keyexch *kx);
391 static void start(keyexch *kx, time_t now);
392
393 static int notice_message(keyexch *kx)
394 {
395   struct timeval now, tv;
396
397   gettimeofday(&now, 0);
398   rs_reset(&kx->rs);
399   if (kx->f & KXF_CORK) {
400     start(kx, now.tv_sec);
401     rs_time(&kx->rs, &tv, &now);
402     settimer(kx, &tv);
403     a_notify("KXSTART", "?PEER", kx->p, A_END);
404   }
405   if (checkpub(kx)) return (-1);
406   if (!VALIDP(kx, now.tv_sec)) {
407     stop(kx);
408     start(kx, now.tv_sec);
409   }
410   return (0);
411 }
412
413 /* --- @update_stats_tx@, @update_stats_rx@ --- *
414  *
415  * Arguments:   @keyexch *kx@ = pointer to key-exchange block
416  *              @int ok@ = nonzero if the message was valid (for @rx@)
417  *              @size_t sz@ = size of sent message
418  *
419  * Returns:     ---
420  *
421  * Use:         Records that a key-exchange message was sent to, or received
422  *              from, the peer.
423  */
424
425 static void update_stats_tx(keyexch *kx, size_t sz)
426   { stats *st = p_stats(kx->p); st->n_kxout++; st->sz_kxout += sz; }
427
428 static void update_stats_rx(keyexch *kx, int ok, size_t sz)
429 {
430   stats *st = p_stats(kx->p);
431
432   if (!ok) st->n_reject++;
433   else { st->n_kxin++; st->sz_kxin += sz; }
434 }
435
436 /*----- Challenge management ----------------------------------------------*/
437
438 /* --- Notes on challenge management --- *
439  *
440  * We may get multiple different replies to our key exchange; some will be
441  * correct, some inserted by attackers.  Up until @KX_THRESH@, all challenges
442  * received will be added to the table and given a full response.  After
443  * @KX_THRESH@ distinct challenges are received, we return only a `cookie':
444  * our existing challenge, followed by a hash of the sender's challenge.  We
445  * do %%\emph{not}%% give a bare challenge a reply slot at this stage.  All
446  * properly-formed cookies are assigned a table slot: if none is spare, a
447  * used slot is randomly selected and destroyed.  A cookie always receives a
448  * full reply.
449  */
450
451 /* --- @kxc_destroy@ --- *
452  *
453  * Arguments:   @kxchal *kxc@ = pointer to the challenge block
454  *
455  * Returns:     ---
456  *
457  * Use:         Disposes of a challenge block.
458  */
459
460 static void kxc_destroy(kxchal *kxc)
461 {
462   const dhgrp *g = kxc->kx->kpriv->grp;
463   if (kxc->f & KXF_TIMER)
464     sel_rmtimer(&kxc->t);
465   g->ops->freege(g, kxc->C);
466   g->ops->freege(g, kxc->R);
467   ks_drop(kxc->ks);
468   DESTROY(kxc);
469 }
470
471 /* --- @kxc_stoptimer@ --- *
472  *
473  * Arguments:   @kxchal *kxc@ = pointer to the challenge block
474  *
475  * Returns:     ---
476  *
477  * Use:         Stops the challenge's retry timer from sending messages.
478  *              Useful when the state machine is in the endgame of the
479  *              exchange.
480  */
481
482 static void kxc_stoptimer(kxchal *kxc)
483 {
484   if (kxc->f & KXF_TIMER)
485     sel_rmtimer(&kxc->t);
486   kxc->f &= ~KXF_TIMER;
487 }
488
489 /* --- @kxc_new@ --- *
490  *
491  * Arguments:   @keyexch *kx@ = pointer to key exchange block
492  *
493  * Returns:     A pointer to the challenge block.
494  *
495  * Use:         Returns a pointer to a new challenge block to fill in.
496  *              In particular, the @c@ and @r@ members are left
497  *              uninitialized.
498  */
499
500 static kxchal *kxc_new(keyexch *kx)
501 {
502   kxchal *kxc;
503   unsigned i;
504
505   /* --- If we're over reply threshold, discard one at random --- */
506
507   if (kx->nr < KX_NCHAL)
508     i = kx->nr++;
509   else {
510     i = rand_global.ops->range(&rand_global, KX_NCHAL);
511     kxc_destroy(kx->r[i]);
512   }
513
514   /* --- Fill in the new structure --- */
515
516   kxc = CREATE(kxchal);
517   kxc->ks = 0;
518   kxc->kx = kx;
519   kxc->f = 0;
520   kx->r[i] = kxc;
521   rs_reset(&kxc->rs);
522   return (kxc);
523 }
524
525 /* --- @kxc_bychal@ --- *
526  *
527  * Arguments:   @keyexch *kx@ = pointer to key exchange block
528  *              @const dhge *C@ = challenge from remote host
529  *
530  * Returns:     Pointer to the challenge block, or null.
531  *
532  * Use:         Finds a challenge block, given its challenge.
533  */
534
535 static kxchal *kxc_bychal(keyexch *kx, const dhge *C)
536 {
537   const dhgrp *g = kx->kpriv->grp;
538   unsigned i;
539
540   for (i = 0; i < kx->nr; i++) {
541     if (g->ops->eq(g, C, kx->r[i]->C))
542       return (kx->r[i]);
543   }
544   return (0);
545 }
546
547 /* --- @kxc_byhc@ --- *
548  *
549  * Arguments:   @keyexch *kx@ = pointer to key exchange block
550  *              @const octet *hc@ = challenge hash from remote host
551  *
552  * Returns:     Pointer to the challenge block, or null.
553  *
554  * Use:         Finds a challenge block, given a hash of its challenge.
555  */
556
557 static kxchal *kxc_byhc(keyexch *kx, const octet *hc)
558 {
559   unsigned i;
560
561   for (i = 0; i < kx->nr; i++) {
562     if (memcmp(hc, kx->r[i]->hc, kx->kpriv->algs.hashsz) == 0)
563       return (kx->r[i]);
564   }
565   return (0);
566 }
567
568 /* --- @kxc_answer@ --- *
569  *
570  * Arguments:   @keyexch *kx@ = pointer to key exchange block
571  *              @kxchal *kxc@ = pointer to challenge block
572  *
573  * Returns:     ---
574  *
575  * Use:         Sends a reply to the remote host, according to the data in
576  *              this challenge block.
577  */
578
579 static void kxc_answer(keyexch *kx, kxchal *kxc);
580
581 static void kxc_timer(struct timeval *tv, void *v)
582 {
583   kxchal *kxc = v;
584   kxc->f &= ~KXF_TIMER;
585   kxc_answer(kxc->kx, kxc);
586 }
587
588 static void kxc_answer(keyexch *kx, kxchal *kxc)
589 {
590   buf *b = p_txstart(kx->p, MSG_KEYEXCH | KX_REPLY);
591   const dhgrp *g = kx->kpriv->grp;
592   struct timeval tv;
593   buf bb;
594
595   /* --- Build the reply packet --- */
596
597   T( trace(T_KEYEXCH, "keyexch: sending reply to `%s'", p_name(kx->p)); )
598   sendchallenge(kx, b, kxc->C, kxc->hc);
599   buf_init(&bb, buf_i, sizeof(buf_i));
600   g->ops->stge(g, &bb, kxc->R, DHFMT_STD);
601   buf_flip(&bb);
602   ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_REPLY, &bb, b);
603
604   /* --- Update the statistics --- */
605
606   if (BOK(b)) {
607     update_stats_tx(kx, BLEN(b));
608     p_txend(kx->p);
609   }
610
611   /* --- Schedule another resend --- */
612
613   if (kxc->f & KXF_TIMER)
614     sel_rmtimer(&kxc->t);
615   gettimeofday(&tv, 0);
616   rs_time(&kxc->rs, &tv, &tv);
617   sel_addtimer(&sel, &kxc->t, &tv, kxc_timer, kxc);
618   kxc->f |= KXF_TIMER;
619 }
620
621 /*----- Individual message handlers ---------------------------------------*/
622
623 /* --- @doprechallenge@ --- *
624  *
625  * Arguments:   @keyexch *kx@ = pointer to key exchange block
626  *              @buf *b@ = buffer containing the packet
627  *
628  * Returns:     Zero if OK, nonzero of the packet was rejected.
629  *
630  * Use:         Processes a pre-challenge message.
631  */
632
633 static int doprechallenge(keyexch *kx, buf *b)
634 {
635   const dhgrp *g = kx->kpriv->grp;
636   dhge *C = 0;
637   ghash *h;
638
639   /* --- Ensure that we're in a sensible state --- */
640
641   if (kx->s != KXS_CHAL) {
642     a_warn("KX", "?PEER", kx->p, "unexpected", "pre-challenge", A_END);
643     goto bad;
644   }
645
646   /* --- Unpack the packet --- */
647
648   if ((C = g->ops->ldge(g, b, DHFMT_VAR)) == 0 || BLEFT(b))
649     goto bad;
650
651   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
652     trace(T_CRYPTO, "crypto: challenge = %s", g->ops->gestr(g, C));
653   }))
654
655   /* --- Send out a full challenge by return --- */
656
657   b = p_txstart(kx->p, MSG_KEYEXCH | KX_CHAL);
658   h = GH_INIT(kx->kpriv->algs.h);
659   HASH_STRING(h, "tripe-cookie");
660   hashge(h, g, C);
661   sendchallenge(kx, b, C, GH_DONE(h, 0));
662   GH_DESTROY(h);
663   update_stats_tx(kx, BLEN(b));
664   p_txend(kx->p);
665
666   /* --- Done --- */
667
668   g->ops->freege(g, C);
669   return (0);
670
671 bad:
672   if (C) g->ops->freege(g, C);
673   return (-1);
674 }
675
676 /* --- @respond@ --- *
677  *
678  * Arguments:   @keyexch *kx@ = pointer to key exchange block
679  *              @unsigned msg@ = message code for this packet
680  *              @buf *b@ = buffer containing the packet
681  *
682  * Returns:     Key-exchange challenge block, or null.
683  *
684  * Use:         Computes a response for the given challenge, entering it into
685  *              a challenge block and so on.
686  */
687
688 static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
689 {
690   const dhgrp *g = kx->kpriv->grp;
691   const algswitch *algs = &kx->kpriv->algs;
692   size_t ixsz = g->scsz;
693   dhge *C = 0;
694   dhge *R = 0;
695   dhge *CC = 0;
696   deriveargs a;
697   const octet *hc, *ck;
698   dhsc *c = 0;
699   kxchal *kxc;
700   ghash *h = 0;
701   buf bb;
702   int ok;
703
704   /* --- Unpack the packet --- */
705
706   if ((C = g->ops->ldge(g, b, DHFMT_VAR)) == 0 ||
707       (hc = buf_get(b, algs->hashsz)) == 0 ||
708       (ck = buf_get(b, ixsz)) == 0) {
709     a_warn("KX", "?PEER", kx->p, "invalid", "%s", pkname[msg], A_END);
710     goto bad;
711   }
712   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
713     trace(T_CRYPTO, "crypto: challenge = %s", g->ops->gestr(g, C));
714     trace_block(T_CRYPTO, "crypto: cookie", hc, algs->hashsz);
715     trace_block(T_CRYPTO, "crypto: check-value", ck, ixsz);
716   }))
717
718   /* --- Discard a packet with an invalid cookie --- */
719
720   if (hc && memcmp(hc, kx->hc, algs->hashsz) != 0) {
721     a_warn("KX", "?PEER", kx->p, "incorrect", "cookie", A_END);
722     goto bad;
723   }
724
725   /* --- Recover the check value and verify it --- *
726    *
727    * To avoid recomputation on replays, we store a hash of the `right'
728    * value.  The `correct' value is unique, so this is right.
729    *
730    * This will also find a challenge block and, if necessary, populate it.
731    */
732
733   if ((kxc = kxc_bychal(kx, C)) != 0) {
734     h = GH_INIT(algs->h);
735     HASH_STRING(h, "tripe-check-hash");
736     GH_HASH(h, ck, ixsz);
737     ok = !memcmp(kxc->ck, GH_DONE(h, 0), algs->hashsz);
738     GH_DESTROY(h);
739     if (!ok) goto badcheck;
740   } else {
741
742     /* --- Compute the reply, and check the magic --- */
743
744     R = g->ops->mul(g, kx->kpriv->k, C);
745     if ((c = mpunmask(g, ck, ixsz, algs->mgf,
746                       hashcheck(kx, kx->kpub->K, kx->C, C, R),
747                       algs->hashsz)) == 0)
748       goto badcheck;
749     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
750       trace(T_CRYPTO, "crypto: computed reply = %s", g->ops->gestr(g, R));
751       trace(T_CRYPTO, "crypto: recovered log = %s", g->ops->scstr(g, c));
752     }))
753     CC = g->ops->mul(g, c, 0);
754     if (!g->ops->eq(g, CC, C)) goto badcheck;
755
756     /* --- Fill in a new challenge block --- */
757
758     kxc = kxc_new(kx);
759     kxc->C = C; C = 0;
760     kxc->R = R; R = 0;
761
762     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-check-hash");
763     GH_HASH(h, ck, ixsz);
764     GH_DONE(h, kxc->ck); GH_DESTROY(h);
765
766     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-cookie");
767     hashge(h, g, kxc->C);
768     GH_DONE(h, kxc->hc); GH_DESTROY(h);
769
770     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
771       trace_block(T_CRYPTO, "crypto: computed cookie",
772                   kxc->hc, algs->hashsz);
773     }))
774
775     /* --- Work out the shared key --- */
776
777     R = g->ops->mul(g, kx->a, kxc->C);
778     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
779       trace(T_CRYPTO, "crypto: shared secret = %s", g->ops->gestr(g, R));
780     }))
781
782     /* --- Compute the switch messages --- */
783
784     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-request");
785     hashge(h, g, kx->C); hashge(h, g, kxc->C);
786     GH_DONE(h, kxc->hswrq_out); GH_DESTROY(h);
787     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-confirm");
788     hashge(h, g, kx->C); hashge(h, g, kxc->C);
789     GH_DONE(h, kxc->hswok_out); GH_DESTROY(h);
790
791     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-request");
792     hashge(h, g, kxc->C); hashge(h, g, kx->C);
793     GH_DONE(h, kxc->hswrq_in); GH_DESTROY(h);
794     h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-confirm");
795     hashge(h, g, kxc->C); hashge(h, g, kx->C);
796     GH_DONE(h, kxc->hswok_in); GH_DESTROY(h);
797
798     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
799       trace_block(T_CRYPTO, "crypto: outbound switch request",
800                   kxc->hswrq_out, algs->hashsz);
801       trace_block(T_CRYPTO, "crypto: outbound switch confirm",
802                   kxc->hswok_out, algs->hashsz);
803       trace_block(T_CRYPTO, "crypto: inbound switch request",
804                   kxc->hswrq_in, algs->hashsz);
805       trace_block(T_CRYPTO, "crypto: inbound switch confirm",
806                   kxc->hswok_in, algs->hashsz);
807     }))
808
809     /* --- Create a new symmetric keyset --- */
810
811     buf_init(&bb, buf_o, sizeof(buf_o)); a.k = BBASE(&bb);
812     g->ops->stge(g, &bb, kx->C, DHFMT_HASH); a.x = BLEN(&bb);
813     g->ops->stge(g, &bb, kxc->C, DHFMT_HASH); a.y = BLEN(&bb);
814     g->ops->stge(g, &bb, R, DHFMT_HASH); a.z = BLEN(&bb);
815     assert(BOK(&bb));
816
817     kxc->ks = ks_gen(&a, kx->p);
818   }
819
820   if (C) g->ops->freege(g, C);
821   if (CC) g->ops->freege(g, CC);
822   if (R) g->ops->freege(g, R);
823   if (c) g->ops->freesc(g, c);
824   return (kxc);
825
826 badcheck:
827   a_warn("KX", "?PEER", kx->p, "bad-expected-reply-log", A_END);
828   goto bad;
829 bad:
830   if (C) g->ops->freege(g, C);
831   if (CC) g->ops->freege(g, CC);
832   if (R) g->ops->freege(g, R);
833   if (c) g->ops->freesc(g, c);
834   return (0);
835 }
836
837 /* --- @dochallenge@ --- *
838  *
839  * Arguments:   @keyexch *kx@ = pointer to key exchange block
840  *              @unsigned msg@ = message code for the packet
841  *              @buf *b@ = buffer containing the packet
842  *
843  * Returns:     Zero if OK, nonzero if the packet was rejected.
844  *
845  * Use:         Processes a packet containing a challenge.
846  */
847
848 static int dochallenge(keyexch *kx, buf *b)
849 {
850   kxchal *kxc;
851
852   if (kx->s != KXS_CHAL) {
853     a_warn("KX", "?PEER", kx->p, "unexpected", "challenge", A_END);
854     goto bad;
855   }
856   if ((kxc = respond(kx, KX_CHAL, b)) == 0)
857     goto bad;
858   if (BLEFT(b)) {
859     a_warn("KX", "?PEER", kx->p, "invalid", "challenge", A_END);
860     goto bad;
861   }
862   kxc_answer(kx, kxc);
863   return (0);
864
865 bad:
866   return (-1);
867 }
868
869 /* --- @resend@ --- *
870  *
871  * Arguments:   @keyexch *kx@ = pointer to key exchange context
872  *
873  * Returns:     ---
874  *
875  * Use:         Sends the next message for a key exchange.
876  */
877
878 static void resend(keyexch *kx)
879 {
880   kxchal *kxc;
881   buf bb;
882   struct timeval tv;
883   const dhgrp *g = kx->kpriv->grp;
884   buf *b;
885
886   switch (kx->s) {
887     case KXS_CHAL:
888       T( trace(T_KEYEXCH, "keyexch: sending prechallenge to `%s'",
889                p_name(kx->p)); )
890       b = p_txstart(kx->p, MSG_KEYEXCH | KX_PRECHAL);
891       g->ops->stge(g, b, kx->C, DHFMT_VAR);
892       break;
893     case KXS_COMMIT:
894       T( trace(T_KEYEXCH, "keyexch: sending switch request to `%s'",
895                p_name(kx->p)); )
896       kxc = kx->r[0];
897       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCH);
898       buf_put(b, kx->hc, kx->kpriv->algs.hashsz);
899       buf_put(b, kxc->hc, kx->kpriv->algs.hashsz);
900       buf_init(&bb, buf_i, sizeof(buf_i));
901       g->ops->stge(g, &bb, kxc->R, DHFMT_STD);
902       buf_put(&bb, kxc->hswrq_out, kx->kpriv->algs.hashsz);
903       buf_flip(&bb);
904       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b);
905       break;
906     case KXS_SWITCH:
907       T( trace(T_KEYEXCH, "keyexch: sending switch confirmation to `%s'",
908                p_name(kx->p)); )
909       kxc = kx->r[0];
910       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCHOK);
911       buf_init(&bb, buf_i, sizeof(buf_i));
912       buf_put(&bb, kxc->hswok_out, kx->kpriv->algs.hashsz);
913       buf_flip(&bb);
914       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, &bb, b);
915       break;
916     default:
917       abort();
918   }
919
920   if (BOK(b)) {
921     update_stats_tx(kx, BLEN(b));
922     p_txend(kx->p);
923   }
924
925   if (kx->s < KXS_SWITCH) {
926     rs_time(&kx->rs, &tv, 0);
927     settimer(kx, &tv);
928   }
929 }
930
931 /* --- @decryptrest@ --- *
932  *
933  * Arguments:   @keyexch *kx@ = pointer to key exchange context
934  *              @kxchal *kxc@ = pointer to challenge block
935  *              @unsigned msg@ = type of incoming message
936  *              @buf *b@ = encrypted remainder of the packet
937  *
938  * Returns:     Zero if OK, nonzero on some kind of error.
939  *
940  * Use:         Decrypts the remainder of the packet, and points @b@ at the
941  *              recovered plaintext.
942  */
943
944 static int decryptrest(keyexch *kx, kxchal *kxc, unsigned msg, buf *b)
945 {
946   buf bb;
947
948   buf_init(&bb, buf_o, sizeof(buf_o));
949   if (ks_decrypt(kxc->ks, MSG_KEYEXCH | msg, b, &bb)) {
950     a_warn("KX", "?PEER", kx->p, "decrypt-failed", "%s", pkname[msg], A_END);
951     return (-1);
952   }
953   if (!BOK(&bb)) return (-1);
954   buf_init(b, BBASE(&bb), BLEN(&bb));
955   return (0);
956 }
957
958 /* --- @checkresponse@ --- *
959  *
960  * Arguments:   @keyexch *kx@ = pointer to key exchange context
961  *              @unsigned msg@ = type of incoming message
962  *              @buf *b@ = decrypted remainder of the packet
963  *
964  * Returns:     Zero if OK, nonzero on some kind of error.
965  *
966  * Use:         Checks a reply or switch packet, ensuring that its response
967  *              is correct.
968  */
969
970 static int checkresponse(keyexch *kx, unsigned msg, buf *b)
971 {
972   const dhgrp *g = kx->kpriv->grp;
973   dhge *R;
974
975   if ((R = g->ops->ldge(g, b, DHFMT_STD)) == 0) {
976     a_warn("KX", "?PEER", kx->p, "invalid", "%s", pkname[msg], A_END);
977     goto bad;
978   }
979   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
980     trace(T_CRYPTO, "crypto: reply = %s", g->ops->gestr(g, R));
981   }))
982   if (!g->ops->eq(g, R, kx->RX)) {
983     a_warn("KX", "?PEER", kx->p, "incorrect", "response", A_END);
984     goto bad;
985   }
986
987   g->ops->freege(g, R);
988   return (0);
989
990 bad:
991   if (R) g->ops->freege(g, R);
992   return (-1);
993 }
994
995 /* --- @commit@ --- *
996  *
997  * Arguments:   @keyexch *kx@ = pointer to key exchange context
998  *              @kxchal *kxc@ = pointer to challenge to commit to
999  *
1000  * Returns:     ---
1001  *
1002  * Use:         Commits to a particular challenge as being the `right' one,
1003  *              since a reply has arrived for it.
1004  */
1005
1006 static void commit(keyexch *kx, kxchal *kxc)
1007 {
1008   unsigned i;
1009
1010   for (i = 0; i < kx->nr; i++) {
1011     if (kx->r[i] != kxc)
1012       kxc_destroy(kx->r[i]);
1013   }
1014   kx->r[0] = kxc;
1015   kx->nr = 1;
1016   kxc_stoptimer(kxc);
1017   ksl_link(kx->ks, kxc->ks);
1018 }
1019
1020 /* --- @doreply@ --- *
1021  *
1022  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1023  *              @buf *b@ = buffer containing packet
1024  *
1025  * Returns:     Zero if OK, nonzero if the packet was rejected.
1026  *
1027  * Use:         Handles a reply packet.  This doesn't handle the various
1028  *              switch packets: they're rather too different.
1029  */
1030
1031 static int doreply(keyexch *kx, buf *b)
1032 {
1033   kxchal *kxc;
1034
1035   if (kx->s != KXS_CHAL && kx->s != KXS_COMMIT) {
1036     a_warn("KX", "?PEER", kx->p, "unexpected", "reply", A_END);
1037     goto bad;
1038   }
1039   if ((kxc = respond(kx, KX_REPLY, b)) == 0 ||
1040       decryptrest(kx, kxc, KX_REPLY, b) ||
1041       checkresponse(kx, KX_REPLY, b))
1042     goto bad;
1043   if (BLEFT(b)) {
1044     a_warn("KX", "?PEER", kx->p, "invalid", "reply", A_END);
1045     goto bad;
1046   }
1047   if (kx->s == KXS_CHAL) {
1048     commit(kx, kxc);
1049     kx->s = KXS_COMMIT;
1050   }
1051   resend(kx);
1052   return (0);
1053
1054 bad:
1055   return (-1);
1056 }
1057
1058 /* --- @kxfinish@ --- *
1059  *
1060  * Arguments:   @keyexch *kx@ = pointer to key exchange block
1061  *
1062  * Returns:     ---
1063  *
1064  * Use:         Sets everything up following a successful key exchange.
1065  */
1066
1067 static void kxfinish(keyexch *kx)
1068 {
1069   kxchal *kxc = kx->r[0];
1070   struct timeval now, tv;
1071
1072   ks_activate(kxc->ks);
1073   gettimeofday(&now, 0);
1074   f2tv(&tv, wobble(T_REGEN));
1075   TV_ADD(&tv, &now, &tv);
1076   settimer(kx, &tv);
1077   kx->s = KXS_SWITCH;
1078   a_notify("KXDONE", "?PEER", kx->p, A_END);
1079   p_stats(kx->p)->t_kx = time(0);
1080 }
1081
1082 /* --- @doswitch@ --- *
1083  *
1084  * Arguments:   @keyexch *kx@ = pointer to key exchange block
1085  *              @buf *b@ = pointer to buffer containing packet
1086  *
1087  * Returns:     Zero if OK, nonzero if the packet was rejected.
1088  *
1089  * Use:         Handles a reply with a switch request bolted onto it.
1090  */
1091
1092 static int doswitch(keyexch *kx, buf *b)
1093 {
1094   size_t hsz = kx->kpriv->algs.hashsz;
1095   const octet *hc_in, *hc_out, *hswrq;
1096   kxchal *kxc;
1097
1098   if ((hc_in = buf_get(b, hsz)) == 0 ||
1099       (hc_out = buf_get(b, hsz)) == 0) {
1100     a_warn("KX", "?PEER", kx->p, "invalid", "switch-rq", A_END);
1101     goto bad;
1102   }
1103   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
1104     trace_block(T_CRYPTO, "crypto: challenge", hc_in, hsz);
1105     trace_block(T_CRYPTO, "crypto: cookie", hc_out, hsz);
1106   }))
1107   if ((kxc = kxc_byhc(kx, hc_in)) == 0 ||
1108       memcmp(hc_out, kx->hc, hsz) != 0) {
1109     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-rq", A_END);
1110     goto bad;
1111   }
1112   if (decryptrest(kx, kxc, KX_SWITCH, b) ||
1113       checkresponse(kx, KX_SWITCH, b))
1114     goto bad;
1115   if ((hswrq = buf_get(b, hsz)) == 0 || BLEFT(b)) {
1116     a_warn("KX", "?PEER", kx->p, "invalid", "switch-rq", A_END);
1117     goto bad;
1118   }
1119   IF_TRACING(T_KEYEXCH, {
1120     trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, hsz);
1121   })
1122   if (memcmp(hswrq, kxc->hswrq_in, hsz) != 0) {
1123     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-rq", A_END);
1124     goto bad;
1125   }
1126   if (kx->s == KXS_CHAL)
1127     commit(kx, kxc);
1128   if (kx->s < KXS_SWITCH)
1129     kxfinish(kx);
1130   resend(kx);
1131   return (0);
1132
1133 bad:
1134   return (-1);
1135 }
1136
1137 /* --- @doswitchok@ --- *
1138  *
1139  * Arguments:   @keyexch *kx@ = pointer to key exchange block
1140  *              @buf *b@ = pointer to buffer containing packet
1141  *
1142  * Returns:     Zero if OK, nonzero if the packet was rejected.
1143  *
1144  * Use:         Handles a reply with a switch request bolted onto it.
1145  */
1146
1147 static int doswitchok(keyexch *kx, buf *b)
1148 {
1149   size_t hsz = kx->kpriv->algs.hashsz;
1150   const octet *hswok;
1151   kxchal *kxc;
1152   buf bb;
1153
1154   if (kx->s < KXS_COMMIT) {
1155     a_warn("KX", "?PEER", kx->p, "unexpected", "switch-ok", A_END);
1156     goto bad;
1157   }
1158   kxc = kx->r[0];
1159   buf_init(&bb, buf_o, sizeof(buf_o));
1160   if (decryptrest(kx, kxc, KX_SWITCHOK, b))
1161     goto bad;
1162   if ((hswok = buf_get(b, hsz)) == 0 || BLEFT(b)) {
1163     a_warn("KX", "?PEER", kx->p, "invalid", "switch-ok", A_END);
1164     goto bad;
1165   }
1166   IF_TRACING(T_KEYEXCH, {
1167     trace_block(T_CRYPTO, "crypto: switch confirmation hash",
1168                 hswok, hsz);
1169   })
1170   if (memcmp(hswok, kxc->hswok_in, hsz) != 0) {
1171     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-ok", A_END);
1172     goto bad;
1173   }
1174   if (kx->s < KXS_SWITCH)
1175     kxfinish(kx);
1176   return (0);
1177
1178 bad:
1179   return (-1);
1180 }
1181
1182 /*----- Main code ---------------------------------------------------------*/
1183
1184 /* --- @stop@ --- *
1185  *
1186  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1187  *
1188  * Returns:     ---
1189  *
1190  * Use:         Stops a key exchange dead in its tracks.  Throws away all of
1191  *              the context information.  The context is left in an
1192  *              inconsistent state.  The only functions which understand this
1193  *              state are @kx_free@ and @kx_init@ (which cause it internally
1194  *              it), and @start@ (which expects it to be the prevailing
1195  *              state).
1196  */
1197
1198 static void stop(keyexch *kx)
1199 {
1200   const dhgrp *g = kx->kpriv->grp;
1201   unsigned i;
1202
1203   if (kx->f & KXF_DEAD)
1204     return;
1205
1206   if (kx->f & KXF_TIMER)
1207     sel_rmtimer(&kx->t);
1208   for (i = 0; i < kx->nr; i++)
1209     kxc_destroy(kx->r[i]);
1210   g->ops->freesc(g, kx->a);
1211   g->ops->freege(g, kx->C);
1212   g->ops->freege(g, kx->RX);
1213   kx->t_valid = 0;
1214   kx->f |= KXF_DEAD;
1215   kx->f &= ~KXF_TIMER;
1216 }
1217
1218 /* --- @start@ --- *
1219  *
1220  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1221  *              @time_t now@ = the current time
1222  *
1223  * Returns:     ---
1224  *
1225  * Use:         Starts a new key exchange with the peer.  The context must be
1226  *              in the bizarre state left by @stop@ or @kx_init@.
1227  */
1228
1229 static void start(keyexch *kx, time_t now)
1230 {
1231   algswitch *algs = &kx->kpriv->algs;
1232   const dhgrp *g = kx->kpriv->grp;
1233   ghash *h;
1234
1235   assert(kx->f & KXF_DEAD);
1236
1237   kx->f &= ~(KXF_DEAD | KXF_CORK);
1238   kx->nr = 0;
1239   kx->a = g->ops->randsc(g);
1240   kx->C = g->ops->mul(g, kx->a, 0);
1241   kx->RX = g->ops->mul(g, kx->a, kx->kpub->K);
1242   kx->s = KXS_CHAL;
1243   kx->t_valid = now + T_VALID;
1244
1245   h = GH_INIT(algs->h);
1246   HASH_STRING(h, "tripe-cookie");
1247   hashge(h, g, kx->C);
1248   GH_DONE(h, kx->hc);
1249   GH_DESTROY(h);
1250
1251   IF_TRACING(T_KEYEXCH, {
1252     trace(T_KEYEXCH, "keyexch: creating new challenge");
1253     IF_TRACING(T_CRYPTO, {
1254       trace(T_CRYPTO, "crypto: secret = %s", g->ops->scstr(g, kx->a));
1255       trace(T_CRYPTO, "crypto: challenge = %s", g->ops->gestr(g, kx->C));
1256       trace(T_CRYPTO, "crypto: expected response = %s",
1257             g->ops->gestr(g, kx->RX));
1258       trace_block(T_CRYPTO, "crypto: challenge cookie",
1259                   kx->hc, algs->hashsz);
1260     })
1261   })
1262 }
1263
1264 /* --- @checkpub@ --- *
1265  *
1266  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1267  *
1268  * Returns:     Zero if OK, nonzero if the peer's public key has expired.
1269  *
1270  * Use:         Deactivates the key-exchange until the peer acquires a new
1271  *              public key.
1272  */
1273
1274 static int checkpub(keyexch *kx)
1275 {
1276   time_t now;
1277   unsigned f = 0;
1278
1279   if (kx->f & KXF_DEAD)
1280     return (-1);
1281   now = time(0);
1282   if (KEY_EXPIRED(now, kx->kpriv->t_exp)) f |= 1;
1283   if (KEY_EXPIRED(now, kx->kpub->t_exp)) f |= 2;
1284   if (f) {
1285     stop(kx);
1286     if (f & 1) a_warn("KX", "?PEER", kx->p, "private-key-expired", A_END);
1287     if (f & 2) a_warn("KX", "?PEER", kx->p, "public-key-expired", A_END);
1288     kx->f &= ~KXF_PUBKEY;
1289     return (-1);
1290   }
1291   return (0);
1292 }
1293
1294 /* --- @kx_start@ --- *
1295  *
1296  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1297  *              @int forcep@ = nonzero to ignore the quiet timer
1298  *
1299  * Returns:     ---
1300  *
1301  * Use:         Stimulates a key exchange.  If a key exchage is in progress,
1302  *              a new challenge is sent (unless the quiet timer forbids
1303  *              this); if no exchange is in progress, one is commenced.
1304  */
1305
1306 void kx_start(keyexch *kx, int forcep)
1307 {
1308   time_t now = time(0);
1309
1310   if (checkpub(kx))
1311     return;
1312   if (forcep || !VALIDP(kx, now)) {
1313     stop(kx);
1314     start(kx, now);
1315     a_notify("KXSTART", "?PEER", kx->p, A_END);
1316   }
1317   resend(kx);
1318 }
1319
1320 /* --- @kx_message@ --- *
1321  *
1322  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1323  *              @unsigned msg@ = the message code
1324  *              @buf *b@ = pointer to buffer containing the packet
1325  *
1326  * Returns:     ---
1327  *
1328  * Use:         Reads a packet containing key exchange messages and handles
1329  *              it.
1330  */
1331
1332 void kx_message(keyexch *kx, unsigned msg, buf *b)
1333 {
1334   size_t sz = BSZ(b);
1335   int rc;
1336
1337   if (notice_message(kx)) return;
1338
1339   T( trace(T_KEYEXCH, "keyexch: processing %s packet from `%s'",
1340            msg < KX_NMSG ? pkname[msg] : "unknown", p_name(kx->p)); )
1341
1342   switch (msg) {
1343     case KX_PRECHAL:
1344       rc = doprechallenge(kx, b);
1345       break;
1346     case KX_CHAL:
1347       rc = dochallenge(kx, b);
1348       break;
1349     case KX_REPLY:
1350       rc = doreply(kx, b);
1351       break;
1352     case KX_SWITCH:
1353       rc = doswitch(kx, b);
1354       break;
1355     case KX_SWITCHOK:
1356       rc = doswitchok(kx, b);
1357       break;
1358     default:
1359       a_warn("KX", "?PEER", kx->p, "unknown-message", "0x%02x", msg, A_END);
1360       rc = -1;
1361       break;
1362   }
1363
1364   update_stats_rx(kx, !rc, sz);
1365 }
1366
1367 /* --- @kx_free@ --- *
1368  *
1369  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1370  *
1371  * Returns:     ---
1372  *
1373  * Use:         Frees everything in a key exchange context.
1374  */
1375
1376 void kx_free(keyexch *kx)
1377 {
1378   stop(kx);
1379   km_unref(kx->kpub);
1380   km_unref(kx->kpriv);
1381 }
1382
1383 /* --- @kx_newkeys@ --- *
1384  *
1385  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1386  *
1387  * Returns:     ---
1388  *
1389  * Use:         Informs the key exchange module that its keys may have
1390  *              changed.  If fetching the new keys fails, the peer will be
1391  *              destroyed, we log messages and struggle along with the old
1392  *              keys.
1393  */
1394
1395 void kx_newkeys(keyexch *kx)
1396 {
1397   kdata *kpriv, *kpub;
1398   unsigned i;
1399   int switchp;
1400   time_t now = time(0);
1401
1402   T( trace(T_KEYEXCH, "keyexch: checking new keys for `%s'",
1403            p_name(kx->p)); )
1404
1405   /* --- Find out whether we can use new keys --- *
1406    *
1407    * Try each available combination of new and old, public and private,
1408    * except both old (which is status quo anyway).  The selection is encoded
1409    * in @i@, with bit 0 for the private key and bit 1 for public key; a set
1410    * bit means to use the old value, and a clear bit means to use the new
1411    * one.
1412    *
1413    * This means that we currently prefer `old private and new public' over
1414    * `new private and old public'.  I'm not sure which way round this should
1415    * actually be.
1416    */
1417
1418   for (i = 0; i < 3; i++) {
1419
1420     /* --- Select the keys we're going to examine --- *
1421      *
1422      * If we're meant to have a new key and don't, then skip this
1423      * combination.
1424      */
1425
1426     T( trace(T_KEYEXCH, "keyexch: checking %s private, %s public",
1427              i & 1 ? "old" : "new", i & 2 ? "old" : "new"); )
1428
1429     if (i & 1) kpriv = kx->kpriv;
1430     else if (kx->kpriv->kn->kd != kx->kpriv) kpriv = kx->kpriv->kn->kd;
1431     else {
1432       T( trace(T_KEYEXCH, "keyexch: private key unchanged, skipping"); )
1433       continue;
1434     }
1435
1436     if (i & 2) kpub = kx->kpub;
1437     else if (kx->kpub->kn->kd != kx->kpub) kpub = kx->kpub->kn->kd;
1438     else {
1439       T( trace(T_KEYEXCH, "keyexch: public key unchanged, skipping"); )
1440       continue;
1441     }
1442
1443     /* --- Skip if either key is expired --- *
1444      *
1445      * We're not going to get far with expired keys, and this simplifies the
1446      * logic below.
1447      */
1448
1449     if (KEY_EXPIRED(now, kx->kpriv->t_exp) ||
1450         KEY_EXPIRED(now, kx->kpub->t_exp)) {
1451       T( trace(T_KEYEXCH, "keyexch: %s expired, skipping",
1452                !KEY_EXPIRED(now, kx->kpriv->t_exp) ? "public key" :
1453                !KEY_EXPIRED(now, kx->kpub->t_exp) ? "private key" :
1454                "both keys"); )
1455       continue;
1456     }
1457
1458     /* --- If the groups don't match then we can't use this pair --- */
1459
1460     if (!km_samealgsp(kpriv, kpub)) {
1461       T( trace(T_KEYEXCH, "keyexch: peer `%s' group mismatch; "
1462                "%s priv `%s' and %s pub `%s'", p_name(kx->p),
1463                i & 1 ? "old" : "new", km_tag(kx->kpriv),
1464                i & 2 ? "old" : "new", km_tag(kx->kpub)); )
1465       continue;
1466     }
1467     goto newkeys;
1468   }
1469   T( trace(T_KEYEXCH, "keyexch: peer `%s' continuing with old keys",
1470            p_name(kx->p)); )
1471   return;
1472
1473   /* --- We've chosen new keys --- *
1474    *
1475    * Switch the new ones into place.  Neither of the keys we're switching to
1476    * is expired (we checked that above), so we should just crank everything
1477    * up.
1478    *
1479    * A complication arises: we don't really want to force a new key exchange
1480    * unless we have to.  If the group is unchanged, and we're currently
1481    * running OK, then we should just let things lie.
1482    */
1483
1484 newkeys:
1485   switchp = ((kx->f & KXF_DEAD) ||
1486              kx->s != KXS_SWITCH ||
1487              kpriv->grp->ops != kx->kpriv->grp->ops ||
1488              !kpriv->grp->ops->samegrpp(kpriv->grp, kx->kpriv->grp));
1489
1490   T( trace(T_KEYEXCH, "keyexch: peer `%s' adopting "
1491            "%s priv `%s' and %s pub `%s'; %sforcing exchange", p_name(kx->p),
1492            i & 1 ? "old" : "new", km_tag(kx->kpriv),
1493            i & 2 ? "old" : "new", km_tag(kx->kpub),
1494            switchp ? "" : "not "); )
1495
1496   if (switchp) stop(kx);
1497   km_ref(kpriv); km_unref(kx->kpriv); kx->kpriv = kpriv;
1498   km_ref(kpub);  km_unref(kx->kpub);  kx->kpub  = kpub;
1499   kx->f |= KXF_PUBKEY;
1500   if (switchp) {
1501     T( trace(T_KEYEXCH, "keyexch: restarting key negotiation with `%s'",
1502              p_name(kx->p)); )
1503     start(kx, time(0));
1504     resend(kx);
1505   }
1506 }
1507
1508 /* --- @kx_setup@ --- *
1509  *
1510  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1511  *              @peer *p@ = pointer to peer context
1512  *              @keyset **ks@ = pointer to keyset list
1513  *              @unsigned f@ = various useful flags
1514  *
1515  * Returns:     Zero if OK, nonzero if it failed.
1516  *
1517  * Use:         Initializes a key exchange module.  The module currently
1518  *              contains no keys, and will attempt to initiate a key
1519  *              exchange.
1520  */
1521
1522 int kx_setup(keyexch *kx, peer *p, keyset **ks, unsigned f)
1523 {
1524   if ((kx->kpriv = km_findpriv(p_privtag(p))) == 0) goto fail_0;
1525   if ((kx->kpub = km_findpub(p_tag(p))) == 0) goto fail_1;
1526   if (!km_samealgsp(kx->kpriv, kx->kpub)) {
1527     a_warn("KX", "?PEER", p, "group-mismatch",
1528            "local-private-key", "%s", p_privtag(p),
1529            "peer-public-key", "%s", p_tag(p),
1530            A_END);
1531     goto fail_2;
1532   }
1533
1534   kx->ks = ks;
1535   kx->p = p;
1536   kx->f = KXF_DEAD | KXF_PUBKEY | f;
1537   rs_reset(&kx->rs);
1538   if (!(kx->f & KXF_CORK)) {
1539     start(kx, time(0));
1540     resend(kx);
1541     /* Don't notify here: the ADD message hasn't gone out yet. */
1542   }
1543   return (0);
1544
1545 fail_2:
1546   km_unref(kx->kpub);
1547 fail_1:
1548   km_unref(kx->kpriv);
1549 fail_0:
1550   return (-1);
1551 }
1552
1553 /*----- That's all, folks -------------------------------------------------*/