X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/9466fafab433d568f41a01951c5ef2c04b1746d5..38c3bc8753411a533e2a36af1e9efee69dcba3f3:/keyexch.c diff --git a/keyexch.c b/keyexch.c index 80503b47..f4125da2 100644 --- a/keyexch.c +++ b/keyexch.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keyexch.c,v 1.6 2003/04/06 10:26:35 mdw Exp $ + * $Id: keyexch.c,v 1.9 2003/07/13 11:53:14 mdw Exp $ * * Key exchange protocol * @@ -29,6 +29,17 @@ /*----- Revision history --------------------------------------------------* * * $Log: keyexch.c,v $ + * Revision 1.9 2003/07/13 11:53:14 mdw + * Add protocol commentary. + * + * Revision 1.8 2003/07/13 11:19:49 mdw + * Incopatible protocol fix! Include message type code under MAC tag to prevent + * cut-and-paste from key-exchange messages to general packet transport. + * + * Revision 1.7 2003/05/17 11:01:28 mdw + * Handle flags on challenge timers correctly to prevent confusing the event + * list. + * * Revision 1.6 2003/04/06 10:26:35 mdw * Report peer name on decrypt errors. * @@ -54,10 +65,60 @@ #include "tripe.h" +/*----- Brief protocol overview -------------------------------------------* + * + * Let %$G$% be a cyclic group; let %$g$% be a generator of %$G$%, and let + * %$q$% be the order of %$G$%; for a key %$K$%, let %$E_K(\cdot)$% denote + * application of the symmetric packet protocol to a message; let + * %$H(\cdot)$% be the random oracle. Let $\alpha \inr \{0,\ldots,q - 1\}$% + * be Alice's private key; let %$a = g^\alpha$% be her public key; let %$b$% + * be Bob's public key. + * + * At the beginning of the session, Alice chooses + * + * %$\rho_A \inr \{0, \ldots q - 1\}$% + * + * We also have: + * + * %$r_A = g^{\rho_A}$% Alice's challenge + * %$c_A = H(\cookie{cookie}, r_A)$% Alice's cookie + * %$v_A = \rho_A \xor H(\cookie{expected-reply}, r_A, r_B, b^{\rho_A})$% + * Alice's challenge check value + * %$r_B^\alpha = a^{\rho_B}$% Alice's reply + * %$K = r_B^{\rho_A} = r_B^{\rho_A} = g^{\rho_A\rho_B}$% + * Alice and Bob's shared secret key + * %$w_A = H(\cookie{switch-request}, c_A, c_B)$% + * Alice's switch request value + * %$u_A = H(\cookie{switch-confirm}, c_A, c_B)$% + * Alice's switch confirm value + * + * The messages are then: + * + * %$\cookie{kx-pre-challenge}, r_A$% + * Initial greeting. In state @KXS_CHAL@. + * + * %$\cookie{kx-cookie}, r_A, c_B$% + * My table is full but I got your message. + * + * %$\cookie{kx-challenge}, r_A, c_B, v_A$% + * Here's a full challenge for you to answer. + * + * %$\cookie{kx-reply}, c_A, c_B, v_A, E_K(r_B^\alpha))$% + * Challenge accpeted: here's the answer. Commit to my challenge. Move + * to @KXS_COMMIT@. + * + * %$\cookie{kx-switch}, c_A, c_B, E_K(r_B^\alpha, w_A))$% + * Reply received: here's my reply. Committed; send data; move to + * @KXS_SWITCH@. + * + * %$\cookie{kx-switch-ok}, E_K(u_A))$% + * Switch received. Committed; send data; move to @KXS_SWITCH@. + */ + /*----- Tunable parameters ------------------------------------------------*/ -#define T_VALID MIN(2) -#define T_RETRY SEC(10) +#define T_VALID MIN(2) /* Challenge validity period */ +#define T_RETRY SEC(10) /* Challenge retransmit interval */ #define ISVALID(kx, now) ((now) < (kx)->t_valid) @@ -197,6 +258,7 @@ static void kxc_stoptimer(kxchal *kxc) { if (kxc->f & KXF_TIMER) sel_rmtimer(&kxc->t); + kxc->f &= ~KXF_TIMER; } /* --- @kxc_new@ --- * @@ -323,7 +385,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) buf_init(&bb, buf_i, sizeof(buf_i)); buf_putmp(&bb, kxc->r); buf_flip(&bb); - ks_encrypt(kxc->ks, &bb, b); + ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_REPLY, &bb, b); } /* --- Update the statistics --- */ @@ -610,7 +672,7 @@ static void resend(keyexch *kx) buf_putmp(&bb, kxc->r); buf_put(&bb, kxc->hswrq_out, HASHSZ); buf_flip(&bb); - ks_encrypt(kxc->ks, &bb, b); + ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b); break; case KXS_SWITCH: T( trace(T_KEYEXCH, "keyexch: sending switch confirmation to `%s'", @@ -620,7 +682,7 @@ static void resend(keyexch *kx) buf_init(&bb, buf_i, sizeof(buf_i)); buf_put(&bb, kxc->hswok_out, HASHSZ); buf_flip(&bb); - ks_encrypt(kxc->ks, &bb, b); + ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, &bb, b); break; default: abort(); @@ -639,6 +701,7 @@ static void resend(keyexch *kx) /* --- @matchreply@ --- * * * Arguments: @keyexch *kx@ = pointer to key exchange context + * @unsigned ty@ = type of incoming message * @const octet *hc_in@ = a hash of his challenge * @const octet *hc_out@ = a hash of my challenge (cookie) * @mp *ck@ = his expected-reply hash (optional) @@ -652,7 +715,7 @@ static void resend(keyexch *kx) * challenge is returned. */ -static kxchal *matchreply(keyexch *kx, const octet *hc_in, +static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in, const octet *hc_out, mp *ck, buf *b) { kxchal *kxc; @@ -691,7 +754,7 @@ static kxchal *matchreply(keyexch *kx, const octet *hc_in, /* --- Decrypt the rest of the packet --- */ buf_init(&bb, buf_o, sizeof(buf_o)); - if (ks_decrypt(kxc->ks, b, &bb)) { + if (ks_decrypt(kxc->ks, ty, b, &bb)) { a_warn("failed to decrypt reply from `%s'", p_name(kx->p)); goto bad; } @@ -770,7 +833,8 @@ static int doreply(keyexch *kx, buf *b) a_warn("invalid reply packet from `%s'", p_name(kx->p)); goto bad; } - if ((kxc = matchreply(kx, hc_in, hc_out, ck, b)) == 0) + if ((kxc = matchreply(kx, MSG_KEYEXCH | KX_REPLY, + hc_in, hc_out, ck, b)) == 0) goto bad; if (BLEFT(b)) { a_warn("invalid reply packet from `%s'", p_name(kx->p)); @@ -808,7 +872,8 @@ static int doswitch(keyexch *kx, buf *b) a_warn("invalid switch request from `%s'", p_name(kx->p)); goto bad; } - if ((kxc = matchreply(kx, hc_in, hc_out, 0, b)) == 0) + if ((kxc = matchreply(kx, MSG_KEYEXCH | KX_SWITCH, + hc_in, hc_out, 0, b)) == 0) goto bad; if ((hswrq = buf_get(b, HASHSZ)) == 0 || BLEFT(b)) { a_warn("invalid switch request from `%s'", p_name(kx->p)); @@ -859,7 +924,7 @@ static int doswitchok(keyexch *kx, buf *b) } kxc = kx->r[0]; buf_init(&bb, buf_o, sizeof(buf_o)); - if (ks_decrypt(kxc->ks, b, &bb)) { + if (ks_decrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, b, &bb)) { a_warn("failed to decrypt switch confirmation from `%s'", p_name(kx->p)); goto bad; }