X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/00e64b67d321bf53224d546dcba58c52834a7b79..b5c45da15703d85b506a1ea1eb38c318c3418ed3:/keyexch.c?ds=sidebyside diff --git a/keyexch.c b/keyexch.c index c17f4009..18594cf3 100644 --- a/keyexch.c +++ b/keyexch.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keyexch.c,v 1.4 2001/06/22 19:40:36 mdw Exp $ + * $Id: keyexch.c,v 1.13 2004/04/18 18:08:11 mdw Exp $ * * Key exchange protocol * @@ -26,54 +26,124 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* +/*----- Header files ------------------------------------------------------*/ + +#include "tripe.h" + +/*----- Brief protocol overview -------------------------------------------* * - * $Log: keyexch.c,v $ - * Revision 1.4 2001/06/22 19:40:36 mdw - * Support expiry of other peers' public keys. + * 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. * - * Revision 1.3 2001/06/19 22:07:09 mdw - * Cosmetic fixes. + * At the beginning of the session, Alice chooses * - * Revision 1.2 2001/02/16 21:24:27 mdw - * Rewrite for new key exchange protocol. + * %$\rho_A \inr \{0, \ldots q - 1\}$% * - * Revision 1.1 2001/02/03 20:26:37 mdw - * Initial checkin. + * We also have: * - */ - -/*----- Header files ------------------------------------------------------*/ - -#include "tripe.h" + * %$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) /*----- Various utilities -------------------------------------------------*/ -/* --- @hashmp@ --- * +/* --- @hashge@ --- * * - * Arguments: @HASH_CTX *r@ = pointer to hash context - * @mp *m@ = pointer to multiprecision integer + * Arguments: @ghash *h@ = pointer to hash context + * @ge *x@ = pointer to group element * * Returns: --- * - * Use: Adds the hash of a multiprecision integer to the context. - * Corrupts @buf_t@. + * Use: Adds the hash of a group element to the context. Corrupts + * @buf_t@. */ -static void hashmp(HASH_CTX *r, mp *m) +static void hashge(ghash *h, ge *x) { buf b; buf_init(&b, buf_t, sizeof(buf_t)); - buf_putmp(&b, m); + G_TOBUF(gg, &b, x); assert(BOK(&b)); - HASH(r, BBASE(&b), BLEN(&b)); + GH_HASH(h, BBASE(&b), BLEN(&b)); +} + +/* --- @mpencrypt@, @mpdecrypt@ --- * + * + * Arguments: @mp *d@ = the destination integer + * @mp *x@ = the plaintext/ciphertext integer + * @size_t sz@ = the expected size of the plaintext + * @const octet *k@ = pointer to key material + * + * Returns: The encrypted/decrypted integer. + * + * Use: Encrypts (or decrypts) a multiprecision integer. In fact, + * the title is a bit of a misnomer: we actually compute + * %$x \xor H(k)$%, so it's a random oracle thing rather than an + * encryption thing. + */ + +static mp *mpencrypt(mp *d, mp *x, size_t sz, const octet *k) +{ + gcipher *mgf; + + mgf = GC_INIT(algs.mgf, k, algs.hashsz); + mp_storeb(x, buf_t, sz); + GC_ENCRYPT(mgf, buf_t, buf_t, sz); + GC_DESTROY(mgf); + return (mp_loadb(d, buf_t, sz)); +} + +static mp *mpdecrypt(mp *d, mp *x, size_t sz, const octet *k) +{ + gcipher *mgf; + + mgf = GC_INIT(algs.mgf, k, algs.hashsz); + mp_storeb(x, buf_t, sz); + GC_DECRYPT(mgf, buf_t, buf_t, sz); + GC_DESTROY(mgf); + return (mp_loadb(d, buf_t, sz)); } /* --- @timer@ --- * @@ -143,8 +213,9 @@ static void kxc_destroy(kxchal *kxc) { if (kxc->f & KXF_TIMER) sel_rmtimer(&kxc->t); - mp_drop(kxc->c); - mp_drop(kxc->r); + G_DESTROY(gg, kxc->c); + if (kxc->r) G_DESTROY(gg, kxc->r); + mp_drop(kxc->ck); ks_drop(kxc->ks); DESTROY(kxc); } @@ -164,6 +235,7 @@ static void kxc_stoptimer(kxchal *kxc) { if (kxc->f & KXF_TIMER) sel_rmtimer(&kxc->t); + kxc->f &= ~KXF_TIMER; } /* --- @kxc_new@ --- * @@ -192,8 +264,9 @@ static kxchal *kxc_new(keyexch *kx) /* --- Fill in the new structure --- */ kxc = CREATE(kxchal); - kxc->c = 0; + kxc->c = G_CREATE(gg); kxc->r = 0; + kxc->ck = MP_NEW; kxc->ks = 0; kxc->kx = kx; kxc->f = 0; @@ -204,19 +277,19 @@ static kxchal *kxc_new(keyexch *kx) /* --- @kxc_bychal@ --- * * * Arguments: @keyexch *kx@ = pointer to key exchange block - * @mp *c@ = challenge from remote host + * @ge *c@ = challenge from remote host * * Returns: Pointer to the challenge block, or null. * * Use: Finds a challenge block, given its challenge. */ -static kxchal *kxc_bychal(keyexch *kx, mp *c) +static kxchal *kxc_bychal(keyexch *kx, ge *c) { unsigned i; for (i = 0; i < kx->nr; i++) { - if (MP_EQ(c, kx->r[i]->c)) + if (G_EQ(gg, c, kx->r[i]->c)) return (kx->r[i]); } return (0); @@ -237,7 +310,7 @@ static kxchal *kxc_byhc(keyexch *kx, const octet *hc) unsigned i; for (i = 0; i < kx->nr; i++) { - if (memcmp(hc, kx->r[i]->hc, HASHSZ) == 0) + if (memcmp(hc, kx->r[i]->hc, algs.hashsz) == 0) return (kx->r[i]); } return (0); @@ -273,11 +346,11 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) /* --- Build the reply packet --- */ if (!kxc->r) - buf_putmp(b, kx->c); + G_TOBUF(gg, b, kx->c); else - buf_put(b, kx->hc, HASHSZ); - buf_put(b, kxc->hc, HASHSZ); - buf_put(b, kxc->hrx, HASHSZ); + buf_put(b, kx->hc, algs.hashsz); + buf_put(b, kxc->hc, algs.hashsz); + buf_putmp(b, kxc->ck); /* --- Maybe send an actual reply, if we have one --- */ @@ -287,9 +360,9 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) } else { T( trace(T_KEYEXCH, "keyexch: sending reply to `%s'", p_name(kx->p)); ) buf_init(&bb, buf_i, sizeof(buf_i)); - buf_putmp(&bb, kxc->r); + G_TOBUF(gg, &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 --- */ @@ -315,35 +388,50 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) /* --- @getreply@ --- * * * Arguments: @keyexch *kx@ = pointer to key exchange context - * @mp *c@ = a challenge - * @const octet *hrx@ = the supplied expected-reply hash + * @ge *c@ = a challenge + * @mp *ck@ = the supplied expected-reply check value * * Returns: A pointer to the reply, or null if the reply-hash was wrong. * * Use: Computes replies to challenges. */ -static mp *getreply(keyexch *kx, mp *c, const octet *hrx) +static ge *getreply(keyexch *kx, ge *c, mp *ck) { - mp *r = mpmont_exp(&mg, MP_NEW, c, kpriv.x); - HASH_CTX h; - octet buf[HASHSZ]; - - HASH_INIT(&h); - HASH_STRING(&h, "tripe-expected-reply"); - hashmp(&h, c); - hashmp(&h, kx->c); - hashmp(&h, r); - HASH_DONE(&h, buf); + ge *r = G_CREATE(gg); + ge *y = G_CREATE(gg); + mp *a = MP_NEW; + ghash *h; + const octet *hh; + int ok; + + G_EXP(gg, r, c, kpriv); + h = GH_INIT(algs.h); + HASH_STRING(h, "tripe-expected-reply"); + hashge(h, c); + hashge(h, kx->c); + hashge(h, r); + hh = GH_DONE(h, 0); + + a = mpdecrypt(MP_NEW, ck, mp_octets(gg->r), hh); IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { - trace(T_CRYPTO, "crypto: computed reply = %s", mpstr(r)); - trace_block(T_CRYPTO, "crypto: computed reply hash", buf, HASHSZ); + trace(T_CRYPTO, "crypto: computed reply = %s", gestr(gg, r)); + trace_block(T_CRYPTO, "crypto: computed reply hash", hh, algs.hashsz); + trace(T_CRYPTO, "crypto: recovered log = %s", mpstr(a)); })) - if (memcmp(buf, hrx, HASHSZ) != 0) { - a_warn("invalid expected-reply hash from `%s'", p_name(kx->p)); - mp_drop(r); - return (0); + GH_DESTROY(h); + G_EXP(gg, y, gg->g, a); + ok = G_EQ(gg, y, c); + if (!ok) { + a_warn("invalid expected-reply check from `%s'", p_name(kx->p)); + IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { + trace(T_CRYPTO, "crypto: computed challenge = %s", gestr(gg, y)); + })) + G_DESTROY(gg, r); + r = 0; } + mp_drop(a); + G_DESTROY(gg, y); return (r); } @@ -360,10 +448,11 @@ static mp *getreply(keyexch *kx, mp *c, const octet *hrx) static int dochallenge(keyexch *kx, unsigned msg, buf *b) { - mp *c = 0; - const octet *hc = 0, *hrx = 0; + ge *c = G_CREATE(gg); + mp *ck = MP_NEW; + const octet *hc = 0; kxchal *kxc; - HASH_CTX h; + ghash *h; /* --- Ensure that we're in a sensible state --- */ @@ -374,18 +463,18 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) /* --- Unpack the packet --- */ - if ((c = buf_getmp(b)) == 0 || - (msg >= KX_COOKIE && (hc = buf_get(b, HASHSZ)) == 0) || - (msg >= KX_CHAL && (hrx = buf_get(b, HASHSZ)) == 0) || + if (G_FROMBUF(gg, b, c) || + (msg >= KX_COOKIE && (hc = buf_get(b, algs.hashsz)) == 0) || + (msg >= KX_CHAL && (ck = buf_getmp(b)) == 0) || BLEFT(b)) { a_warn("malformed packet from `%s'", p_name(kx->p)); goto bad; } IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { - trace(T_CRYPTO, "crypto: challenge = %s", mpstr(c)); - if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, HASHSZ); - if (hrx) trace_block(T_CRYPTO, "crypto: response hash", hrx, HASHSZ); + trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, c)); + if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, algs.hashsz); + if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck)); })) /* --- First, handle a bare challenge --- * @@ -396,18 +485,19 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) if (!hc && kx->nr >= KX_THRESH) { T( trace(T_KEYEXCH, "keyexch: too many challenges -- sending cookie"); ) b = p_txstart(kx->p, MSG_KEYEXCH | KX_COOKIE); - buf_putmp(b, kx->c); - HASH_INIT(&h); - HASH_STRING(&h, "tripe-cookie"); - hashmp(&h, c); - HASH_DONE(&h, buf_get(b, HASHSZ)); + G_TOBUF(gg, b, kx->c); + h = GH_INIT(algs.h); + HASH_STRING(h, "tripe-cookie"); + hashge(h, c); + GH_DONE(h, buf_get(b, algs.hashsz)); + GH_DESTROY(h); p_txend(kx->p); goto tidy; } /* --- Discard a packet with an invalid cookie --- */ - if (hc && memcmp(hc, kx->hc, HASHSZ) != 0) { + if (hc && memcmp(hc, kx->hc, algs.hashsz) != 0) { a_warn("incorrect cookie from `%s'", p_name(kx->p)); goto bad; } @@ -419,7 +509,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) if ((kxc = kxc_bychal(kx, c)) == 0) { size_t x, y, z; - mp *r; + ge *r; /* --- Be careful here --- * * @@ -428,83 +518,96 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) * it. */ - if (!hrx) + if (!ck) kxc = kxc_new(kx); else { - if ((r = getreply(kx, c, hrx)) == 0) + if ((r = getreply(kx, c, ck)) == 0) goto bad; kxc = kxc_new(kx); kxc->r = r; } - kxc->c = mp_copy(c); + kxc->c = G_CREATE(gg); + G_COPY(gg, kxc->c, c); /* --- Work out the cookie for this challenge --- */ - HASH_INIT(&h); - HASH_STRING(&h, "tripe-cookie"); - hashmp(&h, kxc->c); - HASH_DONE(&h, kxc->hc); + h = GH_INIT(algs.h); + HASH_STRING(h, "tripe-cookie"); + hashge(h, kxc->c); + GH_DONE(h, kxc->hc); + GH_DESTROY(h); + + IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { + trace_block(T_CRYPTO, "crypto: computed cookie", kxc->hc, algs.hashsz); + })) /* --- Compute the expected-reply hash --- */ - HASH_INIT(&h); - HASH_STRING(&h, "tripe-expected-reply"); - hashmp(&h, kx->c); - hashmp(&h, kxc->c); - hashmp(&h, kx->rx); - HASH_DONE(&h, kxc->hrx); + h = GH_INIT(algs.h); + HASH_STRING(h, "tripe-expected-reply"); + hashge(h, kx->c); + hashge(h, kxc->c); + hashge(h, kx->rx); + hc = GH_DONE(h, 0); + kxc->ck = mpencrypt(MP_NEW, kx->alpha, mp_octets(gg->r), hc); + IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { + trace_block(T_CRYPTO, "crypto: expected-reply hash", hc, algs.hashsz); + trace(T_CRYPTO, "crypto: my reply check = %s", mpstr(kxc->ck)); + })) + GH_DESTROY(h); /* --- Work out the shared key --- */ - r = mpmont_exp(&mg, MP_NEW, c, kx->alpha); + r = G_CREATE(gg); + G_EXP(gg, r, c, kx->alpha); + IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { + trace(T_CRYPTO, "crypto: shared secret = %s", gestr(gg, r)); + })) /* --- Compute the switch messages --- */ - HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request"); - hashmp(&h, kx->c); hashmp(&h, kxc->c); - HASH_DONE(&h, kxc->hswrq_out); - HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm"); - hashmp(&h, kx->c); hashmp(&h, kxc->c); - HASH_DONE(&h, kxc->hswok_out); + h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-request"); + hashge(h, kx->c); hashge(h, kxc->c); + GH_DONE(h, kxc->hswrq_out); GH_DESTROY(h); + h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-confirm"); + hashge(h, kx->c); hashge(h, kxc->c); + GH_DONE(h, kxc->hswok_out); GH_DESTROY(h); - HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request"); - hashmp(&h, kxc->c); hashmp(&h, kx->c); - HASH_DONE(&h, kxc->hswrq_in); - HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm"); - hashmp(&h, kxc->c); hashmp(&h, kx->c); - HASH_DONE(&h, kxc->hswok_in); + h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-request"); + hashge(h, kxc->c); hashge(h, kx->c); + GH_DONE(h, kxc->hswrq_in); GH_DESTROY(h); + h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-confirm"); + hashge(h, kxc->c); hashge(h, kx->c); + GH_DONE(h, kxc->hswok_in); GH_DESTROY(h); IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { - trace_block(T_CRYPTO, "crypto: computed cookie", kxc->hc, HASHSZ); - trace_block(T_CRYPTO, "crypto: my reply hash", kxc->hrx, HASHSZ); - trace(T_CRYPTO, "crypto: shared secret = %s", mpstr(r)); trace_block(T_CRYPTO, "crypto: outbound switch request", - kxc->hswrq_out, HASHSZ); + kxc->hswrq_out, algs.hashsz); trace_block(T_CRYPTO, "crypto: outbound switch confirm", - kxc->hswok_out, HASHSZ); + kxc->hswok_out, algs.hashsz); trace_block(T_CRYPTO, "crypto: inbound switch request", - kxc->hswrq_in, HASHSZ); + kxc->hswrq_in, algs.hashsz); trace_block(T_CRYPTO, "crypto: inbound switch confirm", - kxc->hswok_in, HASHSZ); + kxc->hswok_in, algs.hashsz); })) /* --- Create a new symmetric keyset --- */ buf_init(b, buf_o, sizeof(buf_o)); - buf_putmp(b, kx->c); x = BLEN(b); - buf_putmp(b, kxc->c); y = BLEN(b); - buf_putmp(b, r); z = BLEN(b); + G_TOBUF(gg, b, kx->c); x = BLEN(b); + G_TOBUF(gg, b, kxc->c); y = BLEN(b); + G_TOBUF(gg, b, r); z = BLEN(b); assert(BOK(b)); - kxc->ks = ks_gen(BBASE(b), x, y, z); - mp_drop(r); + kxc->ks = ks_gen(BBASE(b), x, y, z, kx->p); + G_DESTROY(gg, r); } /* --- Answer the challenge if we need to --- */ - if (hrx && !kxc->r) { - mp *r; - if ((r = getreply(kx, c, hrx)) == 0) + if (ck && !kxc->r) { + ge *r; + if ((r = getreply(kx, c, ck)) == 0) goto bad; kxc->r = r; } @@ -514,11 +617,13 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) /* --- Tidy up and go home --- */ tidy: - mp_drop(c); + G_DESTROY(gg, c); + mp_drop(ck); return (0); bad: - mp_drop(c); + G_DESTROY(gg, c); + mp_drop(ck); return (-1); } @@ -543,20 +648,20 @@ static void resend(keyexch *kx) T( trace(T_KEYEXCH, "keyexch: sending prechallenge to `%s'", p_name(kx->p)); ) b = p_txstart(kx->p, MSG_KEYEXCH | KX_PRECHAL); - buf_putmp(b, kx->c); + G_TOBUF(gg, b, kx->c); break; case KXS_COMMIT: T( trace(T_KEYEXCH, "keyexch: sending switch request to `%s'", p_name(kx->p)); ) kxc = kx->r[0]; b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCH); - buf_put(b, kx->hc, HASHSZ); - buf_put(b, kxc->hc, HASHSZ); + buf_put(b, kx->hc, algs.hashsz); + buf_put(b, kxc->hc, algs.hashsz); buf_init(&bb, buf_i, sizeof(buf_i)); - buf_putmp(&bb, kxc->r); - buf_put(&bb, kxc->hswrq_out, HASHSZ); + G_TOBUF(gg, &bb, kxc->r); + buf_put(&bb, kxc->hswrq_out, algs.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'", @@ -564,9 +669,9 @@ static void resend(keyexch *kx) kxc = kx->r[0]; b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCHOK); buf_init(&bb, buf_i, sizeof(buf_i)); - buf_put(&bb, kxc->hswok_out, HASHSZ); + buf_put(&bb, kxc->hswok_out, algs.hashsz); buf_flip(&bb); - ks_encrypt(kxc->ks, &bb, b); + ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, &bb, b); break; default: abort(); @@ -585,9 +690,10 @@ 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) - * @const octet *krx@ = his expected-reply hash (optional) + * @mp *ck@ = his expected-reply hash (optional) * @buf *b@ = encrypted remainder of the packet * * Returns: A pointer to the challenge block if OK, or null on failure. @@ -598,21 +704,21 @@ static void resend(keyexch *kx) * challenge is returned. */ -static kxchal *matchreply(keyexch *kx, const octet *hc_in, - const octet *hc_out, const octet *hrx, buf *b) +static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in, + const octet *hc_out, mp *ck, buf *b) { kxchal *kxc; buf bb; - mp *r = 0; + ge *r = 0; /* --- Check the plaintext portions of the data --- */ IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { - trace_block(T_CRYPTO, "crypto: challenge", hc_in, HASHSZ); - trace_block(T_CRYPTO, "crypto: cookie", hc_out, HASHSZ); - if (hrx) trace_block(T_CRYPTO, "crypto: response hash", hrx, HASHSZ); + trace_block(T_CRYPTO, "crypto: challenge", hc_in, algs.hashsz); + trace_block(T_CRYPTO, "crypto: cookie", hc_out, algs.hashsz); + if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck)); })) - if (memcmp(hc_out, kx->hc, HASHSZ) != 0) { + if (memcmp(hc_out, kx->hc, algs.hashsz) != 0) { a_warn("incorrect cookie from `%s'", p_name(kx->p)); goto bad; } @@ -624,11 +730,11 @@ static kxchal *matchreply(keyexch *kx, const octet *hc_in, /* --- Maybe compute a reply for the challenge --- */ if (!kxc->r) { - if (!hrx) { + if (!ck) { a_warn("unexpected switch request from `%s'", p_name(kx->p)); goto bad; } - if ((r = getreply(kx, kxc->c, hrx)) == 0) + if ((r = getreply(kx, kxc->c, ck)) == 0) goto bad; kxc->r = r; r = 0; @@ -637,30 +743,31 @@ 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; } buf_init(b, BBASE(&bb), BLEN(&bb)); - if ((r = buf_getmp(b)) == 0) { + r = G_CREATE(gg); + if (G_FROMBUF(gg, b, r)) { a_warn("invalid reply packet from `%s'", p_name(kx->p)); goto bad; } IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { - trace(T_CRYPTO, "crypto: reply = %s", mpstr(r)); + trace(T_CRYPTO, "crypto: reply = %s", gestr(gg, r)); })) - if (!mp_eq(r, kx->rx)) { + if (!G_EQ(gg, r, kx->rx)) { a_warn("incorrect reply from `%s'", p_name(kx->p)); goto bad; } /* --- Done --- */ - mp_drop(r); + G_DESTROY(gg, r); return (kxc); bad: - mp_drop(r); + if (r) G_DESTROY(gg, r); return (0); } @@ -702,20 +809,22 @@ static void commit(keyexch *kx, kxchal *kxc) static int doreply(keyexch *kx, buf *b) { - const octet *hc_in, *hc_out, *hrx; + const octet *hc_in, *hc_out; + mp *ck = 0; kxchal *kxc; if (kx->s != KXS_CHAL && kx->s != KXS_COMMIT) { a_warn("unexpected reply from `%s'", p_name(kx->p)); goto bad; } - if ((hc_in = buf_get(b, HASHSZ)) == 0 || - (hc_out = buf_get(b, HASHSZ)) == 0 || - (hrx = buf_get(b, HASHSZ)) == 0) { + if ((hc_in = buf_get(b, algs.hashsz)) == 0 || + (hc_out = buf_get(b, algs.hashsz)) == 0 || + (ck = buf_getmp(b)) == 0) { a_warn("invalid reply packet from `%s'", p_name(kx->p)); goto bad; } - if ((kxc = matchreply(kx, hc_in, hc_out, hrx, 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)); @@ -729,6 +838,7 @@ static int doreply(keyexch *kx, buf *b) return (0); bad: + mp_drop(ck); return (-1); } @@ -747,21 +857,22 @@ static int doswitch(keyexch *kx, buf *b) const octet *hc_in, *hc_out, *hswrq; kxchal *kxc; - if ((hc_in = buf_get(b, HASHSZ)) == 0 || - (hc_out = buf_get(b, HASHSZ)) == 0) { + if ((hc_in = buf_get(b, algs.hashsz)) == 0 || + (hc_out = buf_get(b, algs.hashsz)) == 0) { 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)) { + if ((hswrq = buf_get(b, algs.hashsz)) == 0 || BLEFT(b)) { a_warn("invalid switch request from `%s'", p_name(kx->p)); goto bad; } IF_TRACING(T_KEYEXCH, { - trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, HASHSZ); + trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, algs.hashsz); }) - if (memcmp(hswrq, kxc->hswrq_in, HASHSZ) != 0) { + if (memcmp(hswrq, kxc->hswrq_in, algs.hashsz) != 0) { a_warn("incorrect switch request hash from `%s'", p_name(kx->p)); goto bad; } @@ -803,19 +914,20 @@ 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; } buf_init(b, BBASE(&bb), BLEN(&bb)); - if ((hswok = buf_get(b, HASHSZ)) == 0 || BLEFT(b)) { + if ((hswok = buf_get(b, algs.hashsz)) == 0 || BLEFT(b)) { a_warn("invalid switch confirmation from `%s'", p_name(kx->p)); goto bad; } IF_TRACING(T_KEYEXCH, { - trace_block(T_CRYPTO, "crypto: switch confirmation hash", hswok, HASHSZ); + trace_block(T_CRYPTO, "crypto: switch confirmation hash", + hswok, algs.hashsz); }) - if (memcmp(hswok, kxc->hswok_in, HASHSZ) != 0) { + if (memcmp(hswok, kxc->hswok_in, algs.hashsz) != 0) { a_warn("incorrect switch confirmation hash from `%s'", p_name(kx->p)); goto bad; } @@ -858,8 +970,8 @@ static void stop(keyexch *kx) for (i = 0; i < kx->nr; i++) kxc_destroy(kx->r[i]); mp_drop(kx->alpha); - mp_drop(kx->c); - mp_drop(kx->rx); + G_DESTROY(gg, kx->c); + G_DESTROY(gg, kx->rx); kx->t_valid = 0; kx->f |= KXF_DEAD; kx->f &= ~KXF_TIMER; @@ -878,30 +990,31 @@ static void stop(keyexch *kx) static void start(keyexch *kx, time_t now) { - HASH_CTX h; + ghash *h; assert(kx->f & KXF_DEAD); kx->f &= ~KXF_DEAD; kx->nr = 0; - kx->alpha = mprand_range(MP_NEW, kpriv.dp.q, &rand_global, 0); - kx->c = mpmont_exp(&mg, MP_NEW, kpriv.dp.g, kx->alpha); - kx->rx = mpmont_exp(&mg, MP_NEW, kx->kpub.y, kx->alpha); + kx->alpha = mprand_range(MP_NEW, gg->r, &rand_global, 0); + kx->c = G_CREATE(gg); G_EXP(gg, kx->c, gg->g, kx->alpha); + kx->rx = G_CREATE(gg); G_EXP(gg, kx->rx, kx->kpub, kx->alpha); kx->s = KXS_CHAL; kx->t_valid = now + T_VALID; - HASH_INIT(&h); - HASH_STRING(&h, "tripe-cookie"); - hashmp(&h, kx->c); - HASH_DONE(&h, kx->hc); + h = GH_INIT(algs.h); + HASH_STRING(h, "tripe-cookie"); + hashge(h, kx->c); + GH_DONE(h, kx->hc); + GH_DESTROY(h); IF_TRACING(T_KEYEXCH, { trace(T_KEYEXCH, "keyexch: creating new challenge"); IF_TRACING(T_CRYPTO, { trace(T_CRYPTO, "crypto: secret = %s", mpstr(kx->alpha)); - trace(T_CRYPTO, "crypto: challenge = %s", mpstr(kx->c)); - trace(T_CRYPTO, "crypto: expected response = %s", mpstr(kx->rx)); - trace_block(T_CRYPTO, "crypto: challenge cookie", kx->hc, HASHSZ); + trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, kx->c)); + trace(T_CRYPTO, "crypto: expected response = %s", gestr(gg, kx->rx)); + trace_block(T_CRYPTO, "crypto: challenge cookie", kx->hc, algs.hashsz); }) }) } @@ -925,7 +1038,7 @@ static int checkpub(keyexch *kx) if (KEY_EXPIRED(now, kx->texp_kpub)) { stop(kx); a_warn("public key for `%s' has expired", p_name(kx->p)); - dh_pubfree(&kx->kpub); + G_COPY(gg, kx->kpub, gg->i); kx->f &= ~KXF_PUBKEY; return (-1); } @@ -1035,8 +1148,7 @@ void kx_message(keyexch *kx, unsigned msg, buf *b) void kx_free(keyexch *kx) { stop(kx); - if (kx->f & KXF_PUBKEY) - dh_pubfree(&kx->kpub); + G_DESTROY(gg, kx->kpub); } /* --- @kx_newkeys@ --- * @@ -1053,13 +1165,8 @@ void kx_free(keyexch *kx) void kx_newkeys(keyexch *kx) { - dh_pub dp; - - if (km_getpubkey(p_name(kx->p), &dp, &kx->texp_kpub)) + if (km_getpubkey(p_name(kx->p), kx->kpub, &kx->texp_kpub)) return; - if (kx->f & KXF_PUBKEY) - dh_pubfree(&kx->kpub); - kx->kpub = dp; kx->f |= KXF_PUBKEY; if ((kx->f & KXF_DEAD) || kx->s != KXS_SWITCH) { T( trace(T_KEYEXCH, "keyexch: restarting key negotiation with `%s'", @@ -1087,8 +1194,11 @@ int kx_init(keyexch *kx, peer *p, keyset **ks) { kx->ks = ks; kx->p = p; - if (km_getpubkey(p_name(p), &kx->kpub, &kx->texp_kpub)) + kx->kpub = G_CREATE(gg); + if (km_getpubkey(p_name(p), kx->kpub, &kx->texp_kpub)) { + G_DESTROY(gg, kx->kpub); return (-1); + } kx->f = KXF_DEAD | KXF_PUBKEY; start(kx, time(0)); resend(kx);