X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/1a981bdb7da1f52ca5639e59610425f9d30ae860..5d418e241860be38becfa5450ac65f9a8cc5865a:/keyexch.c diff --git a/keyexch.c b/keyexch.c index c17f4009..be7b2a35 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.5 2002/01/13 14:54:40 mdw Exp $ * * Key exchange protocol * @@ -29,6 +29,10 @@ /*----- Revision history --------------------------------------------------* * * $Log: keyexch.c,v $ + * Revision 1.5 2002/01/13 14:54:40 mdw + * Patch up zero-knowledge property by passing an encrypted log with a + * challenge, so that the prover can verify that the challenge is good. + * * Revision 1.4 2001/06/22 19:40:36 mdw * Support expiry of other peers' public keys. * @@ -76,6 +80,31 @@ static void hashmp(HASH_CTX *r, mp *m) HASH(r, BBASE(&b), BLEN(&b)); } +/* --- @mpcrypt@ --- * + * + * 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 + * @size_t ksz@ = size of the key + * + * Returns: The encrypted/decrypted integer. + * + * Use: Encrypts (or decrypts) a multiprecision integer using another + * multiprecision integer as the key. This is a slightly grotty + * way to do this, but it's easier than the alternatives. + */ + +static mp *mpcrypt(mp *d, mp *x, size_t sz, const octet *k, size_t ksz) +{ + MGF_CTX m; + + MGF_INIT(&m, k, ksz, 0); + mp_storeb(x, buf_t, sz); + MGF_CRYPT(&m, buf_t, buf_t, sz); + return (mp_loadb(d, buf_t, sz)); +} + /* --- @timer@ --- * * * Arguments: @struct timeval *tv@ = the current time @@ -145,6 +174,7 @@ static void kxc_destroy(kxchal *kxc) sel_rmtimer(&kxc->t); mp_drop(kxc->c); mp_drop(kxc->r); + mp_drop(kxc->ck); ks_drop(kxc->ks); DESTROY(kxc); } @@ -194,6 +224,7 @@ static kxchal *kxc_new(keyexch *kx) kxc = CREATE(kxchal); kxc->c = 0; kxc->r = 0; + kxc->ck = 0; kxc->ks = 0; kxc->kx = kx; kxc->f = 0; @@ -277,7 +308,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) else buf_put(b, kx->hc, HASHSZ); buf_put(b, kxc->hc, HASHSZ); - buf_put(b, kxc->hrx, HASHSZ); + buf_putmp(b, kxc->ck); /* --- Maybe send an actual reply, if we have one --- */ @@ -316,18 +347,20 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) * * Arguments: @keyexch *kx@ = pointer to key exchange context * @mp *c@ = a challenge - * @const octet *hrx@ = the supplied expected-reply hash + * @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 mp *getreply(keyexch *kx, mp *c, mp *ck) { mp *r = mpmont_exp(&mg, MP_NEW, c, kpriv.x); + mp *a; HASH_CTX h; - octet buf[HASHSZ]; + octet buf[HASHSZ]; + int ok; HASH_INIT(&h); HASH_STRING(&h, "tripe-expected-reply"); @@ -335,16 +368,24 @@ static mp *getreply(keyexch *kx, mp *c, const octet *hrx) hashmp(&h, kx->c); hashmp(&h, r); HASH_DONE(&h, buf); + + a = mpcrypt(MP_NEW, ck, mp_octets(kpriv.dp.q), buf, sizeof(buf)); 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: recovered log = %s", mpstr(a)); })) - if (memcmp(buf, hrx, HASHSZ) != 0) { - a_warn("invalid expected-reply hash from `%s'", p_name(kx->p)); + a = mpmont_exp(&mg, a, kpriv.dp.g, a); + ok = mp_eq(a, 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", mpstr(a)); + })) mp_drop(r); - return (0); } - return (r); + mp_drop(a); + return (ok ? r : 0); } /* --- @dochallenge@ --- * @@ -360,10 +401,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; + mp *c = 0, *ck = 0; + const octet *hc = 0; kxchal *kxc; HASH_CTX h; + octet buf[HASHSZ]; /* --- Ensure that we're in a sensible state --- */ @@ -376,7 +418,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) if ((c = buf_getmp(b)) == 0 || (msg >= KX_COOKIE && (hc = buf_get(b, HASHSZ)) == 0) || - (msg >= KX_CHAL && (hrx = buf_get(b, HASHSZ)) == 0) || + (msg >= KX_CHAL && (ck = buf_getmp(b)) == 0) || BLEFT(b)) { a_warn("malformed packet from `%s'", p_name(kx->p)); goto bad; @@ -385,7 +427,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) 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); + if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck)); })) /* --- First, handle a bare challenge --- * @@ -428,10 +470,10 @@ 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; @@ -452,11 +494,16 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) hashmp(&h, kx->c); hashmp(&h, kxc->c); hashmp(&h, kx->rx); - HASH_DONE(&h, kxc->hrx); + HASH_DONE(&h, buf); + kxc->ck = mpcrypt(MP_NEW, kx->alpha, mp_octets(kpriv.dp.q), + buf, sizeof(buf)); /* --- Work out the shared key --- */ + trace(T_CRYPTO, "debug: c = %s", mpstr(c)); + trace(T_CRYPTO, "debug: alpha = %s", mpstr(kx->alpha)); r = mpmont_exp(&mg, MP_NEW, c, kx->alpha); + trace(T_CRYPTO, "debug: r = %s", mpstr(r)); /* --- Compute the switch messages --- */ @@ -476,7 +523,9 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) 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_block(T_CRYPTO, "crypto: expected-reply hash", + buf, HASHSZ); + trace(T_CRYPTO, "crypto: my reply check = %s", mpstr(kxc->ck)); trace(T_CRYPTO, "crypto: shared secret = %s", mpstr(r)); trace_block(T_CRYPTO, "crypto: outbound switch request", kxc->hswrq_out, HASHSZ); @@ -502,9 +551,9 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) /* --- Answer the challenge if we need to --- */ - if (hrx && !kxc->r) { + if (ck && !kxc->r) { mp *r; - if ((r = getreply(kx, c, hrx)) == 0) + if ((r = getreply(kx, c, ck)) == 0) goto bad; kxc->r = r; } @@ -515,10 +564,12 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) tidy: mp_drop(c); + mp_drop(ck); return (0); bad: mp_drop(c); + mp_drop(ck); return (-1); } @@ -587,7 +638,7 @@ static void resend(keyexch *kx) * Arguments: @keyexch *kx@ = pointer to key exchange context * @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. @@ -599,7 +650,7 @@ static void resend(keyexch *kx) */ static kxchal *matchreply(keyexch *kx, const octet *hc_in, - const octet *hc_out, const octet *hrx, buf *b) + const octet *hc_out, mp *ck, buf *b) { kxchal *kxc; buf bb; @@ -610,7 +661,7 @@ static kxchal *matchreply(keyexch *kx, const octet *hc_in, 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); + if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck)); })) if (memcmp(hc_out, kx->hc, HASHSZ) != 0) { a_warn("incorrect cookie from `%s'", p_name(kx->p)); @@ -624,11 +675,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; @@ -702,7 +753,8 @@ 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) { @@ -711,11 +763,11 @@ static int doreply(keyexch *kx, buf *b) } if ((hc_in = buf_get(b, HASHSZ)) == 0 || (hc_out = buf_get(b, HASHSZ)) == 0 || - (hrx = buf_get(b, 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, 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 +781,7 @@ static int doreply(keyexch *kx, buf *b) return (0); bad: + mp_drop(ck); return (-1); }