chiark / gitweb /
keyexch, keymgmt: Include the peer's public key in the check hash.
[tripe] / keyexch.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Key exchange protocol
6  *
7  * (c) 2001 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Trivial IP Encryption (TrIPE).
13  *
14  * TrIPE is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * TrIPE is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with TrIPE; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include "tripe.h"
32
33 /*----- Brief protocol overview -------------------------------------------*
34  *
35  * Let %$G$% be a cyclic group; let %$g$% be a generator of %$G$%, and let
36  * %$q$% be the order of %$G$%; for a key %$K$%, let %$E_K(\cdot)$% denote
37  * application of the symmetric packet protocol to a message; let
38  * %$H(\cdot)$% be the random oracle.  Let $\alpha \inr \{0,\ldots,q - 1\}$%
39  * be Alice's private key; let %$a = g^\alpha$% be her public key; let %$b$%
40  * be Bob's public key.
41  *
42  * At the beginning of the session, Alice chooses
43  *
44  *   %$\rho_A \inr \{0, \ldots q - 1\}$%
45  *
46  * We also have:
47  *
48  * %$r_A = g^{\rho_A}$%                 Alice's challenge
49  * %$c_A = H(\cookie{cookie}, r_A)$%    Alice's cookie
50  * %$v_A = \rho_A \xor H(\cookie{expected-reply}, a, r_A, r_B, b^{\rho_A})$%
51  *                                      Alice's challenge check value
52  * %$r_B^\alpha = a^{\rho_B}$%          Alice's reply
53  * %$K = r_B^{\rho_A} = r_B^{\rho_A} = g^{\rho_A\rho_B}$%
54  *                                      Alice and Bob's shared secret key
55  * %$w_A = H(\cookie{switch-request}, c_A, c_B)$%
56  *                                      Alice's switch request value
57  * %$u_A = H(\cookie{switch-confirm}, c_A, c_B)$%
58  *                                      Alice's switch confirm value
59  *
60  * The messages are then:
61  *
62  * %$\cookie{kx-pre-challenge}, r_A$%
63  *      Initial greeting.  In state @KXS_CHAL@.
64  *
65  * %$\cookie{kx-cookie}, r_A, c_B$%
66  *      My table is full but I got your message.
67  *
68  * %$\cookie{kx-challenge}, r_A, c_B, v_A$%
69  *      Here's a full challenge for you to answer.
70  *
71  * %$\cookie{kx-reply}, c_A, c_B, v_A, E_K(r_B^\alpha))$%
72  *      Challenge accpeted: here's the answer.  Commit to my challenge.  Move
73  *      to @KXS_COMMIT@.
74  *
75  * %$\cookie{kx-switch-rq}, c_A, c_B, E_K(r_B^\alpha, w_A))$%
76  *      Reply received: here's my reply.  Committed; send data; move to
77  *      @KXS_SWITCH@.
78  *
79  * %$\cookie{kx-switch-ok}, E_K(u_A))$%
80  *      Switch received.  Committed; send data; move to @KXS_SWITCH@.
81  */ 
82
83 /*----- Tunable parameters ------------------------------------------------*/
84
85 #define T_VALID MIN(2)                  /* Challenge validity period */
86 #define T_RETRY SEC(10)                 /* Challenge retransmit interval */
87
88 #define VALIDP(kx, now) ((now) < (kx)->t_valid)
89
90 /*----- Static tables -----------------------------------------------------*/
91
92 static const char *const pkname[] = {
93   "pre-challenge", "cookie", "challenge",
94   "reply", "switch-rq", "switch-ok"
95 };
96
97 /*----- Various utilities -------------------------------------------------*/
98
99 /* --- @hashge@ --- *
100  *
101  * Arguments:   @ghash *h@ = pointer to hash context
102  *              @ge *x@ = pointer to group element
103  *
104  * Returns:     ---
105  *
106  * Use:         Adds the hash of a group element to the context.  Corrupts
107  *              @buf_t@.
108  */
109
110 static void hashge(ghash *h, ge *x)
111 {
112   buf b;
113   buf_init(&b, buf_t, sizeof(buf_t));
114   G_TOBUF(gg, &b, x);
115   assert(BOK(&b));
116   GH_HASH(h, BBASE(&b), BLEN(&b));
117 }
118
119 /* --- @mpencrypt@, @mpdecrypt@ --- *
120  *
121  * Arguments:   @mp *d@ = the destination integer
122  *              @mp *x@ = the plaintext/ciphertext integer
123  *              @size_t sz@ = the expected size of the plaintext
124  *              @const octet *k@ = pointer to key material
125  *
126  * Returns:     The encrypted/decrypted integer.
127  *
128  * Use:         Encrypts (or decrypts) a multiprecision integer.  In fact,
129  *              the title is a bit of a misnomer: we actually compute
130  *              %$x \xor H(k)$%, so it's a random oracle thing rather than an
131  *              encryption thing.
132  */
133
134 static mp *mpencrypt(mp *d, mp *x, size_t sz, const octet *k)
135 {
136   gcipher *mgf;
137
138   mgf = GC_INIT(algs.mgf, k, algs.hashsz);
139   mp_storeb(x, buf_t, sz);
140   GC_ENCRYPT(mgf, buf_t, buf_t, sz);
141   GC_DESTROY(mgf);
142   return (mp_loadb(d, buf_t, sz));
143 }
144
145 static mp *mpdecrypt(mp *d, mp *x, size_t sz, const octet *k)
146 {
147   gcipher *mgf;
148
149   mgf = GC_INIT(algs.mgf, k, algs.hashsz);
150   mp_storeb(x, buf_t, sz);
151   GC_DECRYPT(mgf, buf_t, buf_t, sz);
152   GC_DESTROY(mgf);
153   return (mp_loadb(d, buf_t, sz));
154 }
155
156 /* --- @timer@ --- *
157  *
158  * Arguments:   @struct timeval *tv@ = the current time
159  *              @void *v@ = pointer to key exchange context
160  *
161  * Returns:     ---
162  *
163  * Use:         Acts when the key exchange timer goes off.
164  */
165
166 static void timer(struct timeval *tv, void *v)
167 {
168   keyexch *kx = v;
169   kx->f &= ~KXF_TIMER;
170   T( trace(T_KEYEXCH, "keyexch: timer has popped"); )
171   kx_start(kx, 0);
172 }
173
174 /* --- @settimer@ --- *
175  *
176  * Arguments:   @keyexch *kx@ = pointer to key exchange context
177  *              @time_t t@ = when to set the timer for
178  *
179  * Returns:     ---
180  *
181  * Use:         Sets the timer for the next key exchange attempt.
182  */
183
184 static void settimer(keyexch *kx, time_t t)
185 {
186   struct timeval tv;
187   if (kx->f & KXF_TIMER)
188     sel_rmtimer(&kx->t);
189   tv.tv_sec = t;
190   tv.tv_usec = 0;
191   sel_addtimer(&sel, &kx->t, &tv, timer, kx);
192   kx->f |= KXF_TIMER;
193 }
194
195 /*----- Challenge management ----------------------------------------------*/
196
197 /* --- Notes on challenge management --- *
198  *
199  * We may get multiple different replies to our key exchange; some will be
200  * correct, some inserted by attackers.  Up until @KX_THRESH@, all challenges
201  * received will be added to the table and given a full response.  After
202  * @KX_THRESH@ distinct challenges are received, we return only a `cookie':
203  * our existing challenge, followed by a hash of the sender's challenge.  We
204  * do %%\emph{not}%% give a bare challenge a reply slot at this stage.  All
205  * properly-formed cookies are assigned a table slot: if none is spare, a
206  * used slot is randomly selected and destroyed.  A cookie always receives a
207  * full reply.
208  */
209
210 /* --- @kxc_destroy@ --- *
211  *
212  * Arguments:   @kxchal *kxc@ = pointer to the challenge block
213  *
214  * Returns:     ---
215  *
216  * Use:         Disposes of a challenge block.
217  */
218
219 static void kxc_destroy(kxchal *kxc)
220 {
221   if (kxc->f & KXF_TIMER)
222     sel_rmtimer(&kxc->t);
223   G_DESTROY(gg, kxc->c);
224   if (kxc->r) G_DESTROY(gg, kxc->r);
225   mp_drop(kxc->ck);
226   ks_drop(kxc->ks);
227   DESTROY(kxc);
228 }
229
230 /* --- @kxc_stoptimer@ --- *
231  *
232  * Arguments:   @kxchal *kxc@ = pointer to the challenge block
233  *
234  * Returns:     ---
235  *
236  * Use:         Stops the challenge's retry timer from sending messages.
237  *              Useful when the state machine is in the endgame of the
238  *              exchange.
239  */
240
241 static void kxc_stoptimer(kxchal *kxc)
242 {
243   if (kxc->f & KXF_TIMER)
244     sel_rmtimer(&kxc->t);
245   kxc->f &= ~KXF_TIMER;
246 }
247
248 /* --- @kxc_new@ --- *
249  *
250  * Arguments:   @keyexch *kx@ = pointer to key exchange block
251  *
252  * Returns:     A pointer to the challenge block.
253  *
254  * Use:         Returns a pointer to a new challenge block to fill in.
255  */
256
257 static kxchal *kxc_new(keyexch *kx)
258 {
259   kxchal *kxc;
260   unsigned i;
261
262   /* --- If we're over reply threshold, discard one at random --- */
263
264   if (kx->nr < KX_NCHAL)
265     i = kx->nr++;
266   else {
267     i = rand_global.ops->range(&rand_global, KX_NCHAL);
268     kxc_destroy(kx->r[i]);
269   }
270
271   /* --- Fill in the new structure --- */
272
273   kxc = CREATE(kxchal);
274   kxc->c = G_CREATE(gg);
275   kxc->r = 0;
276   kxc->ck = MP_NEW;
277   kxc->ks = 0;
278   kxc->kx = kx;
279   kxc->f = 0;
280   kx->r[i] = kxc;
281   return (kxc);
282 }
283
284 /* --- @kxc_bychal@ --- *
285  *
286  * Arguments:   @keyexch *kx@ = pointer to key exchange block
287  *              @ge *c@ = challenge from remote host
288  *
289  * Returns:     Pointer to the challenge block, or null.
290  *
291  * Use:         Finds a challenge block, given its challenge.
292  */
293
294 static kxchal *kxc_bychal(keyexch *kx, ge *c)
295 {
296   unsigned i;
297
298   for (i = 0; i < kx->nr; i++) {
299     if (G_EQ(gg, c, kx->r[i]->c))
300       return (kx->r[i]);
301   }
302   return (0);
303 }
304
305 /* --- @kxc_byhc@ --- *
306  *
307  * Arguments:   @keyexch *kx@ = pointer to key exchange block
308  *              @const octet *hc@ = challenge hash from remote host
309  *
310  * Returns:     Pointer to the challenge block, or null.
311  *
312  * Use:         Finds a challenge block, given a hash of its challenge.
313  */
314
315 static kxchal *kxc_byhc(keyexch *kx, const octet *hc)
316 {
317   unsigned i;
318
319   for (i = 0; i < kx->nr; i++) {
320     if (memcmp(hc, kx->r[i]->hc, algs.hashsz) == 0)
321       return (kx->r[i]);
322   }
323   return (0);
324 }
325
326 /* --- @kxc_answer@ --- *
327  *
328  * Arguments:   @keyexch *kx@ = pointer to key exchange block
329  *              @kxchal *kxc@ = pointer to challenge block
330  *
331  * Returns:     ---
332  *
333  * Use:         Sends a reply to the remote host, according to the data in
334  *              this challenge block.
335  */
336
337 static void kxc_answer(keyexch *kx, kxchal *kxc);
338
339 static void kxc_timer(struct timeval *tv, void *v)
340 {
341   kxchal *kxc = v;
342   kxc->f &= ~KXF_TIMER;
343   kxc_answer(kxc->kx, kxc);
344 }
345
346 static void kxc_answer(keyexch *kx, kxchal *kxc)
347 {
348   stats *st = p_stats(kx->p);
349   buf *b = p_txstart(kx->p, MSG_KEYEXCH | (kxc->r ? KX_REPLY : KX_CHAL));
350   struct timeval tv;
351   buf bb;
352
353   /* --- Build the reply packet --- */
354
355   if (!kxc->r)
356     G_TOBUF(gg, b, kx->c);
357   else
358     buf_put(b, kx->hc, algs.hashsz);
359   buf_put(b, kxc->hc, algs.hashsz);
360   buf_putmp(b, kxc->ck);
361
362   /* --- Maybe send an actual reply, if we have one --- */
363
364   if (!kxc->r) {
365     T( trace(T_KEYEXCH, "keyexch: resending challenge to `%s'",
366              p_name(kx->p)); )
367   } else {
368     T( trace(T_KEYEXCH, "keyexch: sending reply to `%s'", p_name(kx->p)); )
369     buf_init(&bb, buf_i, sizeof(buf_i));
370     G_TORAW(gg, &bb, kxc->r);
371     buf_flip(&bb);
372     ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_REPLY, &bb, b);
373   }
374
375   /* --- Update the statistics --- */
376
377   if (BOK(b)) {
378     st->n_kxout++;
379     st->sz_kxout += BLEN(b);
380     p_txend(kx->p);
381   }
382
383   /* --- Schedule another resend --- */
384
385   if (kxc->f & KXF_TIMER)
386     sel_rmtimer(&kxc->t);
387   gettimeofday(&tv, 0);
388   tv.tv_sec += T_RETRY;
389   sel_addtimer(&sel, &kxc->t, &tv, kxc_timer, kxc);
390   kxc->f |= KXF_TIMER;
391 }
392
393 /*----- Individual message handlers ---------------------------------------*/
394
395 /* --- @getreply@ --- *
396  *
397  * Arguments:   @keyexch *kx@ = pointer to key exchange context
398  *              @ge *c@ = a challenge
399  *              @mp *ck@ = the supplied expected-reply check value
400  *
401  * Returns:     A pointer to the reply, or null if the reply-hash was wrong.
402  *
403  * Use:         Computes replies to challenges.
404  */
405
406 static ge *getreply(keyexch *kx, ge *c, mp *ck)
407 {
408   ge *r = G_CREATE(gg);
409   ge *y = G_CREATE(gg);
410   mp *a = MP_NEW;
411   ghash *h;
412   const octet *hh;
413   int ok;
414
415   G_EXP(gg, r, c, kpriv);
416   h = GH_INIT(algs.h);
417   HASH_STRING(h, "tripe-expected-reply");
418   hashge(h, kx->kpub);
419   hashge(h, c);
420   hashge(h, kx->c);
421   hashge(h, r);
422   hh = GH_DONE(h, 0);
423
424   a = mpdecrypt(MP_NEW, ck, mp_octets(gg->r), hh);
425   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
426     trace(T_CRYPTO, "crypto: computed reply = %s", gestr(gg, r));
427     trace_block(T_CRYPTO, "crypto: computed reply hash", hh, algs.hashsz);
428     trace(T_CRYPTO, "crypto: recovered log = %s", mpstr(a));
429   }))
430   GH_DESTROY(h);
431   if (MP_CMP(a, >=, gg->r))
432     ok = 0;
433   else{
434     G_EXP(gg, y, gg->g, a);
435     ok = G_EQ(gg, y, c);
436   }
437   if (!ok) {
438     a_warn("KX", "?PEER", kx->p, "bad-expected-reply-log", A_END);
439     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
440       trace(T_CRYPTO, "crypto: computed challenge = %s", gestr(gg, y));
441     }))
442     G_DESTROY(gg, r);
443     r = 0;
444   }
445   mp_drop(a);
446   G_DESTROY(gg, y);
447   return (r);
448 }
449
450 /* --- @dochallenge@ --- *
451  *
452  * Arguments:   @keyexch *kx@ = pointer to key exchange block
453  *              @unsigned msg@ = message code for the packet
454  *              @buf *b@ = buffer containing the packet
455  *
456  * Returns:     Zero if OK, nonzero if the packet was rejected.
457  *
458  * Use:         Processes a packet containing a challenge.
459  */
460
461 static int dochallenge(keyexch *kx, unsigned msg, buf *b)
462 {
463   ge *c = G_CREATE(gg);
464   mp *ck = MP_NEW;
465   const octet *hc = 0;
466   kxchal *kxc;
467   ghash *h;
468
469   /* --- Ensure that we're in a sensible state --- */
470
471   if (kx->s != KXS_CHAL) {
472     a_warn("KX", "?PEER", kx->p, "unexpected", "%s", pkname[msg], A_END);
473     goto bad;
474   }
475
476   /* --- Unpack the packet --- */
477
478   if (G_FROMBUF(gg, b, c) ||
479       (msg >= KX_COOKIE && (hc = buf_get(b, algs.hashsz)) == 0) ||
480       (msg >= KX_CHAL && (ck = buf_getmp(b)) == 0) ||
481       BLEFT(b)) {
482     a_warn("KX", "?PEER", kx->p, "invalid", "%s", pkname[msg], A_END);
483     goto bad;
484   }
485
486   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
487     trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, c));
488     if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, algs.hashsz);
489     if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck));
490   }))
491
492   /* --- First, handle a bare challenge --- *
493    *
494    * If the table is heavily loaded, just emit a cookie and return.
495    */
496
497   if (!hc && kx->nr >= KX_THRESH) {
498     T( trace(T_KEYEXCH, "keyexch: too many challenges -- sending cookie"); )
499     a_warn("KX", "?PEER", p_name, "sending-cookie", A_END);
500     b = p_txstart(kx->p, MSG_KEYEXCH | KX_COOKIE);
501     G_TOBUF(gg, b, kx->c);
502     h = GH_INIT(algs.h);
503     HASH_STRING(h, "tripe-cookie");
504     hashge(h, c);
505     GH_DONE(h, buf_get(b, algs.hashsz));
506     GH_DESTROY(h);
507     p_txend(kx->p);
508     goto tidy;
509   }
510
511   /* --- Discard a packet with an invalid cookie --- */
512
513   if (hc && memcmp(hc, kx->hc, algs.hashsz) != 0) {
514     a_warn("KX", "?PEER", "incorrect", "cookie", A_END);
515     goto bad;
516   }
517
518   /* --- Find a challenge block for this packet --- *
519    *
520    * If there isn't one already, create a new one.
521    */
522
523   if ((kxc = kxc_bychal(kx, c)) == 0) {
524     size_t x, y, z;
525     ge *r;
526
527     /* --- Be careful here --- *
528      *
529      * If this is a full challenge, and it's the first time I've seen it, I
530      * want to be able to throw it away before committing a table entry to
531      * it.
532      */
533
534     if (!ck)
535       kxc = kxc_new(kx);        
536     else {
537       if ((r = getreply(kx, c, ck)) == 0)
538         goto bad;
539       kxc = kxc_new(kx);
540       kxc->r = r;
541     }
542     kxc->c = G_CREATE(gg);
543     G_COPY(gg, kxc->c, c);
544
545     /* --- Work out the cookie for this challenge --- */
546
547     h = GH_INIT(algs.h);
548     HASH_STRING(h, "tripe-cookie");
549     hashge(h, kxc->c);
550     GH_DONE(h, kxc->hc);
551     GH_DESTROY(h);
552
553     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
554       trace_block(T_CRYPTO, "crypto: computed cookie", kxc->hc, algs.hashsz);
555     }))
556
557     /* --- Compute the expected-reply hash --- */
558
559     h = GH_INIT(algs.h);
560     HASH_STRING(h, "tripe-expected-reply");
561     hashge(h, kpub);
562     hashge(h, kx->c);
563     hashge(h, kxc->c);
564     hashge(h, kx->rx);
565     hc = GH_DONE(h, 0);
566     kxc->ck = mpencrypt(MP_NEW, kx->alpha, mp_octets(gg->r), hc);
567     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
568       trace_block(T_CRYPTO, "crypto: expected-reply hash", hc, algs.hashsz);
569       trace(T_CRYPTO, "crypto: my reply check = %s", mpstr(kxc->ck));
570     }))
571     GH_DESTROY(h);
572
573     /* --- Work out the shared key --- */
574
575     r = G_CREATE(gg);
576     G_EXP(gg, r, c, kx->alpha);
577     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
578       trace(T_CRYPTO, "crypto: shared secret = %s", gestr(gg, r));
579     }))
580
581     /* --- Compute the switch messages --- */
582
583     h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-request");
584     hashge(h, kx->c); hashge(h, kxc->c);
585     GH_DONE(h, kxc->hswrq_out); GH_DESTROY(h);
586     h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-confirm");
587     hashge(h, kx->c); hashge(h, kxc->c);
588     GH_DONE(h, kxc->hswok_out); GH_DESTROY(h);
589
590     h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-request");
591     hashge(h, kxc->c); hashge(h, kx->c);
592     GH_DONE(h, kxc->hswrq_in); GH_DESTROY(h);
593     h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-confirm");
594     hashge(h, kxc->c); hashge(h, kx->c);
595     GH_DONE(h, kxc->hswok_in); GH_DESTROY(h);
596
597     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
598       trace_block(T_CRYPTO, "crypto: outbound switch request",
599                   kxc->hswrq_out, algs.hashsz);
600       trace_block(T_CRYPTO, "crypto: outbound switch confirm",
601                   kxc->hswok_out, algs.hashsz);
602       trace_block(T_CRYPTO, "crypto: inbound switch request",
603                   kxc->hswrq_in, algs.hashsz);
604       trace_block(T_CRYPTO, "crypto: inbound switch confirm",
605                   kxc->hswok_in, algs.hashsz);
606     }))
607
608     /* --- Create a new symmetric keyset --- */
609
610     buf_init(b, buf_o, sizeof(buf_o));
611     G_TOBUF(gg, b, kx->c); x = BLEN(b);
612     G_TOBUF(gg, b, kxc->c); y = BLEN(b);
613     G_TOBUF(gg, b, r); z = BLEN(b);
614     assert(BOK(b));
615
616     kxc->ks = ks_gen(BBASE(b), x, y, z, kx->p);
617     G_DESTROY(gg, r);
618   }
619
620   /* --- Answer the challenge if we need to --- */
621
622   if (ck && !kxc->r) {
623     ge *r;
624     if ((r = getreply(kx, c, ck)) == 0)
625       goto bad;
626     kxc->r = r;
627   }
628
629   kxc_answer(kx, kxc);
630
631   /* --- Tidy up and go home --- */
632
633 tidy:
634   G_DESTROY(gg, c);
635   mp_drop(ck);
636   return (0);
637
638 bad:
639   G_DESTROY(gg, c);
640   mp_drop(ck);
641   return (-1);
642 }
643
644 /* --- @resend@ --- *
645  *
646  * Arguments:   @keyexch *kx@ = pointer to key exchange context
647  *
648  * Returns:     ---
649  *
650  * Use:         Sends the next message for a key exchange.
651  */
652
653 static void resend(keyexch *kx)
654 {
655   kxchal *kxc;
656   buf bb;
657   stats *st = p_stats(kx->p);
658   buf *b;
659
660   switch (kx->s) {
661     case KXS_CHAL:
662       T( trace(T_KEYEXCH, "keyexch: sending prechallenge to `%s'",
663                p_name(kx->p)); )
664       b = p_txstart(kx->p, MSG_KEYEXCH | KX_PRECHAL);
665       G_TOBUF(gg, b, kx->c);
666       break;
667     case KXS_COMMIT:
668       T( trace(T_KEYEXCH, "keyexch: sending switch request to `%s'",
669                p_name(kx->p)); )
670       kxc = kx->r[0];
671       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCH);
672       buf_put(b, kx->hc, algs.hashsz);
673       buf_put(b, kxc->hc, algs.hashsz);
674       buf_init(&bb, buf_i, sizeof(buf_i));
675       G_TOBUF(gg, &bb, kxc->r);
676       buf_put(&bb, kxc->hswrq_out, algs.hashsz);
677       buf_flip(&bb);
678       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b);
679       break;
680     case KXS_SWITCH:
681       T( trace(T_KEYEXCH, "keyexch: sending switch confirmation to `%s'",
682                p_name(kx->p)); )
683       kxc = kx->r[0];
684       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCHOK);
685       buf_init(&bb, buf_i, sizeof(buf_i));
686       buf_put(&bb, kxc->hswok_out, algs.hashsz);
687       buf_flip(&bb);
688       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, &bb, b);
689       break;
690     default:
691       abort();
692   }
693
694   if (BOK(b)) {
695     st->n_kxout++;
696     st->sz_kxout += BLEN(b);
697     p_txend(kx->p);
698   }
699
700   if (kx->s < KXS_SWITCH)
701     settimer(kx, time(0) + T_RETRY);
702 }
703
704 /* --- @matchreply@ --- *
705  *
706  * Arguments:   @keyexch *kx@ = pointer to key exchange context
707  *              @unsigned ty@ = type of incoming message
708  *              @const octet *hc_in@ = a hash of his challenge
709  *              @const octet *hc_out@ = a hash of my challenge (cookie)
710  *              @mp *ck@ = his expected-reply hash (optional)
711  *              @buf *b@ = encrypted remainder of the packet
712  *
713  * Returns:     A pointer to the challenge block if OK, or null on failure.
714  *
715  * Use:         Checks a reply or switch packet, ensuring that its contents
716  *              are sensible and correct.  If they are, @*b@ is set to point
717  *              to the remainder of the encrypted data, and the correct
718  *              challenge is returned.
719  */
720
721 static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in,
722                           const octet *hc_out, mp *ck, buf *b)
723 {
724   kxchal *kxc;
725   buf bb;
726   ge *r = 0;
727
728   /* --- Check the plaintext portions of the data --- */
729
730   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
731     trace_block(T_CRYPTO, "crypto: challenge", hc_in, algs.hashsz);
732     trace_block(T_CRYPTO, "crypto: cookie", hc_out, algs.hashsz);
733     if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck));
734   }))
735   if (memcmp(hc_out, kx->hc, algs.hashsz) != 0) {
736     a_warn("KX", "?PEER", kx->p, "incorrect", "cookie", A_END);
737     goto bad;
738   }
739   if ((kxc = kxc_byhc(kx, hc_in)) == 0) {
740     a_warn("KX", "?PEER", kx->p, "unknown-challenge", A_END);
741     goto bad;
742   }
743
744   /* --- Maybe compute a reply for the challenge --- */
745
746   if (!kxc->r) {
747     if (!ck) {
748       a_warn("KX", "?PEER", kx->p, "unexpected", "switch-rq", A_END);
749       goto bad;
750     }
751     if ((r = getreply(kx, kxc->c, ck)) == 0)
752       goto bad;
753     kxc->r = r;
754     r = 0;
755   }
756
757   /* --- Decrypt the rest of the packet --- */
758
759   buf_init(&bb, buf_o, sizeof(buf_o));
760   if (ks_decrypt(kxc->ks, ty, b, &bb)) {
761     a_warn("KX", "?PEER", kx->p, "decrypt-failed", "reply", A_END);
762     goto bad;
763   }
764   buf_init(b, BBASE(&bb), BLEN(&bb));
765   r = G_CREATE(gg);
766   if (G_FROMRAW(gg, b, r)) {
767     a_warn("KX", "?PEER", kx->p, "invalid", "reply", A_END);
768     goto bad;
769   }
770   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
771     trace(T_CRYPTO, "crypto: reply = %s", gestr(gg, r));
772   }))
773   if (!G_EQ(gg, r, kx->rx)) {
774     a_warn("KX", "?PEER", kx->p, "incorrect", "reply", A_END);
775     goto bad;
776   }
777
778   /* --- Done --- */
779
780   G_DESTROY(gg, r);
781   return (kxc);
782
783 bad:
784   if (r) G_DESTROY(gg, r);
785   return (0);
786 }
787
788 /* --- @commit@ --- *
789  *
790  * Arguments:   @keyexch *kx@ = pointer to key exchange context
791  *              @kxchal *kxc@ = pointer to challenge to commit to
792  *
793  * Returns:     ---
794  *
795  * Use:         Commits to a particular challenge as being the `right' one,
796  *              since a reply has arrived for it.
797  */
798
799 static void commit(keyexch *kx, kxchal *kxc)
800 {
801   unsigned i;
802
803   for (i = 0; i < kx->nr; i++) {
804     if (kx->r[i] != kxc)
805       kxc_destroy(kx->r[i]);
806   }
807   kx->r[0] = kxc;
808   kx->nr = 1;
809   kxc_stoptimer(kxc);
810   ksl_link(kx->ks, kxc->ks);  
811 }
812
813 /* --- @doreply@ --- *
814  *
815  * Arguments:   @keyexch *kx@ = pointer to key exchange context
816  *              @buf *b@ = buffer containing packet
817  *
818  * Returns:     Zero if OK, nonzero if the packet was rejected.
819  *
820  * Use:         Handles a reply packet.  This doesn't handle the various
821  *              switch packets: they're rather too different.
822  */
823
824 static int doreply(keyexch *kx, buf *b)
825 {
826   const octet *hc_in, *hc_out;
827   mp *ck = 0;
828   kxchal *kxc;
829
830   if (kx->s != KXS_CHAL && kx->s != KXS_COMMIT) {
831     a_warn("KX", "?PEER", kx->p, "unexpected", "reply", A_END);
832     goto bad;
833   }
834   if ((hc_in = buf_get(b, algs.hashsz)) == 0 ||
835       (hc_out = buf_get(b, algs.hashsz)) == 0 ||
836       (ck = buf_getmp(b)) == 0) {
837     a_warn("KX", "?PEER", kx->p, "invalid", "reply", A_END);
838     goto bad;
839   }
840   if ((kxc = matchreply(kx, MSG_KEYEXCH | KX_REPLY,
841                         hc_in, hc_out, ck, b)) == 0)
842     goto bad;
843   if (BLEFT(b)) {
844     a_warn("KX", "?PEER", kx->p, "invalid", "reply", A_END);
845     goto bad;
846   }
847   if (kx->s == KXS_CHAL) {
848     commit(kx, kxc);
849     kx->s = KXS_COMMIT;
850   }
851   resend(kx);
852   return (0);
853
854 bad:
855   mp_drop(ck);
856   return (-1);
857 }
858
859 /* --- @kxfinish@ --- *
860  *
861  * Arguments:   @keyexch *kx@ = pointer to key exchange block
862  *
863  * Returns:     ---
864  *
865  * Use:         Sets everything up following a successful key exchange.
866  */
867
868 static void kxfinish(keyexch *kx)
869 {
870   kxchal *kxc = kx->r[0];
871   ks_activate(kxc->ks);
872   settimer(kx, ks_tregen(kxc->ks));
873   kx->s = KXS_SWITCH;
874   a_notify("KXDONE", "?PEER", kx->p, A_END);
875   p_stats(kx->p)->t_kx = time(0);
876 }
877
878 /* --- @doswitch@ --- *
879  *
880  * Arguments:   @keyexch *kx@ = pointer to key exchange block
881  *              @buf *b@ = pointer to buffer containing packet
882  *
883  * Returns:     Zero if OK, nonzero if the packet was rejected.
884  *
885  * Use:         Handles a reply with a switch request bolted onto it.
886  */
887
888 static int doswitch(keyexch *kx, buf *b)
889 {
890   const octet *hc_in, *hc_out, *hswrq;
891   kxchal *kxc;
892
893   if ((hc_in = buf_get(b, algs.hashsz)) == 0 ||
894       (hc_out = buf_get(b, algs.hashsz)) == 0) {
895     a_warn("KX", "?PEER", kx->p, "invalid", "switch-rq", A_END);
896     goto bad;
897   }
898   if ((kxc = matchreply(kx, MSG_KEYEXCH | KX_SWITCH,
899                         hc_in, hc_out, 0, b)) == 0)
900     goto bad;
901   if ((hswrq = buf_get(b, algs.hashsz)) == 0 || BLEFT(b)) {
902     a_warn("KX", "?PEER", "invalid", "switch-rq", A_END);
903     goto bad;
904   }
905   IF_TRACING(T_KEYEXCH, {
906     trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, algs.hashsz);
907   })
908   if (memcmp(hswrq, kxc->hswrq_in, algs.hashsz) != 0) {
909     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-rq", A_END);
910     goto bad;
911   }
912   switch (kx->s) {
913     case KXS_CHAL:
914       commit(kx, kxc);
915     case KXS_COMMIT:
916       kxfinish(kx);
917       break;
918   }
919   resend(kx);
920   return (0);
921
922 bad:
923   return (-1);
924 }
925
926 /* --- @doswitchok@ --- *
927  *
928  * Arguments:   @keyexch *kx@ = pointer to key exchange block
929  *              @buf *b@ = pointer to buffer containing packet
930  *
931  * Returns:     Zero if OK, nonzero if the packet was rejected.
932  *
933  * Use:         Handles a reply with a switch request bolted onto it.
934  */
935
936 static int doswitchok(keyexch *kx, buf *b)
937 {
938   const octet *hswok;
939   kxchal *kxc;
940   buf bb;
941
942   if (kx->s < KXS_COMMIT) {
943     a_warn("KX", "?PEER", kx->p, "unexpected", "switch-ok", A_END);
944     goto bad;
945   }
946   kxc = kx->r[0];
947   buf_init(&bb, buf_o, sizeof(buf_o));
948   if (ks_decrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, b, &bb)) {
949     a_warn("KX", "?PEER", kx->p, "decrypt-failed", "switch-ok", A_END);
950     goto bad;
951   }
952   buf_init(b, BBASE(&bb), BLEN(&bb));
953   if ((hswok = buf_get(b, algs.hashsz)) == 0 || BLEFT(b)) {
954     a_warn("KX", "?PEER", "invalid", "switch-ok", A_END);
955     goto bad;
956   }
957   IF_TRACING(T_KEYEXCH, {
958     trace_block(T_CRYPTO, "crypto: switch confirmation hash",
959                 hswok, algs.hashsz);
960   })
961   if (memcmp(hswok, kxc->hswok_in, algs.hashsz) != 0) {
962     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-ok", A_END);
963     goto bad;
964   }
965   if (kx->s < KXS_SWITCH)
966     kxfinish(kx);
967   return (0);
968
969 bad:
970   return (-1);  
971 }
972
973 /*----- Main code ---------------------------------------------------------*/
974
975 /* --- @stop@ --- *
976  *
977  * Arguments:   @keyexch *kx@ = pointer to key exchange context
978  *
979  * Returns:     ---
980  *
981  * Use:         Stops a key exchange dead in its tracks.  Throws away all of
982  *              the context information.  The context is left in an
983  *              inconsistent state.  The only functions which understand this
984  *              state are @kx_free@ and @kx_init@ (which cause it internally
985  *              it), and @start@ (which expects it to be the prevailing
986  *              state).
987  */
988
989 static void stop(keyexch *kx)
990 {
991   unsigned i;
992
993   if (kx->f & KXF_DEAD)
994     return;
995
996   if (kx->f & KXF_TIMER)
997     sel_rmtimer(&kx->t);
998   for (i = 0; i < kx->nr; i++)
999     kxc_destroy(kx->r[i]);
1000   mp_drop(kx->alpha);
1001   G_DESTROY(gg, kx->c);
1002   G_DESTROY(gg, kx->rx);
1003   kx->t_valid = 0;
1004   kx->f |= KXF_DEAD;
1005   kx->f &= ~KXF_TIMER;
1006 }
1007
1008 /* --- @start@ --- *
1009  *
1010  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1011  *              @time_t now@ = the current time
1012  *
1013  * Returns:     ---
1014  *
1015  * Use:         Starts a new key exchange with the peer.  The context must be
1016  *              in the bizarre state left by @stop@ or @kx_init@.
1017  */
1018
1019 static void start(keyexch *kx, time_t now)
1020 {
1021   ghash *h;
1022
1023   assert(kx->f & KXF_DEAD);
1024
1025   kx->f &= ~KXF_DEAD;
1026   kx->nr = 0;
1027   kx->alpha = mprand_range(MP_NEW, gg->r, &rand_global, 0);
1028   kx->c = G_CREATE(gg); G_EXP(gg, kx->c, gg->g, kx->alpha);
1029   kx->rx = G_CREATE(gg); G_EXP(gg, kx->rx, kx->kpub, kx->alpha);
1030   kx->s = KXS_CHAL;
1031   kx->t_valid = now + T_VALID;
1032
1033   h = GH_INIT(algs.h);
1034   HASH_STRING(h, "tripe-cookie");
1035   hashge(h, kx->c);
1036   GH_DONE(h, kx->hc);
1037   GH_DESTROY(h);
1038
1039   IF_TRACING(T_KEYEXCH, {
1040     trace(T_KEYEXCH, "keyexch: creating new challenge");
1041     IF_TRACING(T_CRYPTO, {
1042       trace(T_CRYPTO, "crypto: secret = %s", mpstr(kx->alpha));
1043       trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, kx->c));
1044       trace(T_CRYPTO, "crypto: expected response = %s", gestr(gg, kx->rx));
1045       trace_block(T_CRYPTO, "crypto: challenge cookie", kx->hc, algs.hashsz);
1046     })
1047   })
1048 }
1049
1050 /* --- @checkpub@ --- *
1051  *
1052  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1053  *
1054  * Returns:     Zero if OK, nonzero if the peer's public key has expired.
1055  *
1056  * Use:         Deactivates the key-exchange until the peer acquires a new
1057  *              public key.
1058  */
1059
1060 static int checkpub(keyexch *kx)
1061 {
1062   time_t now;
1063   if (kx->f & KXF_DEAD)
1064     return (-1);
1065   now = time(0);
1066   if (KEY_EXPIRED(now, kx->texp_kpub)) {
1067     stop(kx);
1068     a_warn("KX", "?PEER", kx->p, "public-key-expired", A_END);
1069     G_COPY(gg, kx->kpub, gg->i);
1070     kx->f &= ~KXF_PUBKEY;
1071     return (-1);
1072   }
1073   return (0);
1074 }
1075
1076 /* --- @kx_start@ --- *
1077  *
1078  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1079  *              @int forcep@ = nonzero to ignore the quiet timer
1080  *
1081  * Returns:     ---
1082  *
1083  * Use:         Stimulates a key exchange.  If a key exchage is in progress,
1084  *              a new challenge is sent (unless the quiet timer forbids
1085  *              this); if no exchange is in progress, one is commenced.
1086  */
1087
1088 void kx_start(keyexch *kx, int forcep)
1089 {
1090   time_t now = time(0);
1091
1092   if (checkpub(kx))
1093     return;
1094   if (forcep || !VALIDP(kx, now)) {
1095     stop(kx);
1096     start(kx, now);
1097     a_notify("KXSTART", "?PEER", kx->p, A_END);
1098   }
1099   resend(kx);
1100 }
1101
1102 /* --- @kx_message@ --- *
1103  *
1104  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1105  *              @unsigned msg@ = the message code
1106  *              @buf *b@ = pointer to buffer containing the packet
1107  *
1108  * Returns:     ---
1109  *
1110  * Use:         Reads a packet containing key exchange messages and handles
1111  *              it.
1112  */
1113
1114 void kx_message(keyexch *kx, unsigned msg, buf *b)
1115 {
1116   time_t now = time(0);
1117   stats *st = p_stats(kx->p);
1118   size_t sz = BSZ(b);
1119   int rc;
1120
1121   if (checkpub(kx))
1122     return;
1123
1124   if (!VALIDP(kx, now)) {
1125     stop(kx);
1126     start(kx, now);
1127   }
1128
1129   T( trace(T_KEYEXCH, "keyexch: processing %s packet from `%s'",
1130            msg < KX_NMSG ? pkname[msg] : "unknown", p_name(kx->p)); )
1131
1132   switch (msg) {
1133     case KX_PRECHAL:
1134     case KX_COOKIE:
1135     case KX_CHAL:
1136       rc = dochallenge(kx, msg, b);
1137       break;
1138     case KX_REPLY:
1139       rc = doreply(kx, b);
1140       break;
1141     case KX_SWITCH:
1142       rc = doswitch(kx, b);
1143       break;
1144     case KX_SWITCHOK:
1145       rc = doswitchok(kx, b);
1146       break;
1147     default:
1148       a_warn("KX", "?PEER", kx->p, "unknown-message", "0x%02x", msg, A_END);
1149       rc = -1;
1150       break;
1151   }
1152
1153   if (rc)
1154     st->n_reject++;
1155   else {
1156     st->n_kxin++;
1157     st->sz_kxin += sz;
1158   }
1159 }
1160
1161 /* --- @kx_free@ --- *
1162  *
1163  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1164  *
1165  * Returns:     ---
1166  *
1167  * Use:         Frees everything in a key exchange context.
1168  */
1169
1170 void kx_free(keyexch *kx)
1171 {
1172   stop(kx);
1173   G_DESTROY(gg, kx->kpub);
1174 }
1175
1176 /* --- @kx_newkeys@ --- *
1177  *
1178  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1179  *
1180  * Returns:     ---
1181  *
1182  * Use:         Informs the key exchange module that its keys may have
1183  *              changed.  If fetching the new keys fails, the peer will be
1184  *              destroyed, we log messages and struggle along with the old
1185  *              keys.
1186  */
1187
1188 void kx_newkeys(keyexch *kx)
1189 {
1190   if (km_getpubkey(p_name(kx->p), kx->kpub, &kx->texp_kpub))
1191     return;
1192   kx->f |= KXF_PUBKEY;
1193   if ((kx->f & KXF_DEAD) || kx->s != KXS_SWITCH) {
1194     T( trace(T_KEYEXCH, "keyexch: restarting key negotiation with `%s'",
1195              p_name(kx->p)); )
1196     stop(kx);
1197     start(kx, time(0));
1198     resend(kx);
1199   }
1200 }
1201
1202 /* --- @kx_init@ --- *
1203  *
1204  * Arguments:   @keyexch *kx@ = pointer to key exchange context
1205  *              @peer *p@ = pointer to peer context
1206  *              @keyset **ks@ = pointer to keyset list
1207  *
1208  * Returns:     Zero if OK, nonzero if it failed.
1209  *
1210  * Use:         Initializes a key exchange module.  The module currently
1211  *              contains no keys, and will attempt to initiate a key
1212  *              exchange.
1213  */
1214
1215 int kx_init(keyexch *kx, peer *p, keyset **ks)
1216 {
1217   kx->ks = ks;
1218   kx->p = p;
1219   kx->kpub = G_CREATE(gg);
1220   if (km_getpubkey(p_name(p), kx->kpub, &kx->texp_kpub)) {
1221     G_DESTROY(gg, kx->kpub);
1222     return (-1);
1223   }
1224   kx->f = KXF_DEAD | KXF_PUBKEY;
1225   start(kx, time(0));
1226   resend(kx);
1227   /* Don't notify here: the ADD message hasn't gone out yet. */
1228   return (0);
1229 }
1230
1231 /*----- That's all, folks -------------------------------------------------*/