From 52c03a2aa0b5c3461055ca0dcf38e29f2ca88f35 Mon Sep 17 00:00:00 2001 Message-Id: <52c03a2aa0b5c3461055ca0dcf38e29f2ca88f35.1714591368.git.mdw@distorted.org.uk> From: Mark Wooding Date: Sat, 3 Apr 2004 12:35:13 +0000 Subject: [PATCH] Support elliptic curve key exchange. Organization: Straylight/Edgeware From: mdw --- debian/changelog | 4 +- debian/control | 2 +- doc/tripe.8 | 35 ++++ ethereal/packet-tripe.c | 73 ++++++-- keyexch.c | 180 ++++++++++---------- keymgmt.c | 364 +++++++++++++++++++++++++++++++--------- mallory.c | 6 +- servutil.c | 23 ++- tripe-init.in | 1 + tripe.conf | 5 + tripe.h | 40 +++-- 11 files changed, 538 insertions(+), 195 deletions(-) diff --git a/debian/changelog b/debian/changelog index a19e8839..9a02285d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,7 @@ tripe (1.0.0pre6) experimental; urgency=low * Debianization! + * Don't report uninteresting errors when accepting connections. + * Support elliptic curve keys. - -- Mark Wooding Sat, 22 Nov 2003 18:35:50 +0000 + -- Mark Wooding Sat, 3 Apr 2004 11:23:40 +0100 diff --git a/debian/control b/debian/control index d4482636..1fb7fdf7 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: tripe Section: net Priority: extra Maintainer: Mark Wooding -Build-Depends: catacomb-dev (>= 2.0.1), mlib-dev (>= 2.0.2), +Build-Depends: catacomb-dev (>= 2.1.0), mlib-dev (>= 2.0.3), ethereal-dev, debhelper (>= 4.0.2) Standards-Version: 3.1.1 diff --git a/doc/tripe.8 b/doc/tripe.8 index 262b2344..b6da8d81 100644 --- a/doc/tripe.8 +++ b/doc/tripe.8 @@ -409,6 +409,41 @@ server to talk to .hP 7. Congratulations. The two servers will exchange keys and begin sending packets almost immediately. You've set up a virtual private network. +.SS "Using elliptic curve keys" +The +.B tripe +server can use elliptic curve Diffie-Hellman for key exchange, rather +than traditional integer Diffie-Hellman. Given current public +knowledge, elliptic curves can provide similar or better security to +systems based on integer discrete log problems, faster, and with less +transmitted data. It's a matter of controversy whether this will +continue to be the case. The author uses elliptic curves. +.PP +The server works out which it +should be doing based on the key type, which is either +.B tripe\-dh +for standard Diffie-Hellman, or +.B tripe\-ec +for elliptic curves. To create elliptic curve keys, say something like +.VS +key add \-aec\-param \-Cnist-p192 \-eforever \e + \-tparam tripe\-ec\-param +.VE +to construct a parameters key, using your preferred elliptic curve in +the +.B \-C +option (see +.BR key (1) +for details); and create the private keys by +.VS +key add \-aec \-pparam \-talice \e + \-e"now + 1 year" tripe\-ec +.VE +Now start +.B tripe +with the +.B \-ttripe\-ec +option, and all should be well. .SS "About the name" The program's name is .BR tripe , diff --git a/ethereal/packet-tripe.c b/ethereal/packet-tripe.c index 93f1e0e0..386f383c 100644 --- a/ethereal/packet-tripe.c +++ b/ethereal/packet-tripe.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: packet-tripe.c,v 1.1 2003/10/15 09:30:19 mdw Exp $ + * $Id: packet-tripe.c,v 1.2 2004/04/03 12:35:13 mdw Exp $ * * TrIPE protocol dissector for Ethereal * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: packet-tripe.c,v $ + * Revision 1.2 2004/04/03 12:35:13 mdw + * Support elliptic curve key exchange. + * * Revision 1.1 2003/10/15 09:30:19 mdw * Add support for Ethereal protocol analysis. * @@ -61,7 +64,12 @@ static int proto_tripe = -1; -typedef struct hfmp { int hf, hf_len, hf_val, tt; } hfmp; +typedef struct hfmp { + int hf, hf_len, hf_val, tt; +} hfmp; +typedef struct hfge { + int hf, hf_len, hf_val, hfx_len, hfx_val, hfy_len, hfy_val, tt; +} hfge; static int hf_tripe_cat = -1; static int hf_tripe_packet_type = -1; @@ -71,7 +79,7 @@ static int hf_tripe_ct_iv = -1; static int hf_tripe_ct_cbc = -1; static int hf_tripe_ct_mac = -1; static int hf_tripe_kx_type = -1; -static hfmp hf_tripe_kx_mychal = { -1, -1, -1, -1 }; +static hfge hf_tripe_kx_mychal = { -1, -1, -1, -1, -1, -1, -1, -1 }; static int hf_tripe_kx_mycookie = -1; static int hf_tripe_kx_yourcookie = -1; static hfmp hf_tripe_kx_check = { -1, -1, -1, -1 }; @@ -100,6 +108,31 @@ static gint getmp(proto_tree *tt, const hfmp *hf, tvbuff_t *b, gint off) return (off + 2 + len); } +static gint getge(proto_tree *tt, const hfge *hf, tvbuff_t *b, gint off) +{ + guint16 len = tvb_get_ntohs(b, off), len2; + guint r; + proto_item *ti; + r = tvb_length_remaining(b, off); + if (r < 4 + len || + (len2 = tvb_get_ntohs(b, off + 2 + len), r < 4 + len + len2)) { + ti = proto_tree_add_item(tt, hf->hf, b, off, len + 2, FALSE); + tt = proto_item_add_subtree(ti, hf->tt); + proto_tree_add_item(tt, hf->hf_len, b, off, 2, FALSE); + proto_tree_add_item(tt, hf->hf_val, b, off + 2, len, FALSE); + r = off + len + 2; + } else { + ti = proto_tree_add_item(tt, hf->hf, b, off, len + len2 + 4, FALSE); + tt = proto_item_add_subtree(ti, hf->tt); + proto_tree_add_item(tt, hf->hfx_len, b, off, 2, FALSE); + proto_tree_add_item(tt, hf->hfx_val, b, off + 2, len, FALSE); + proto_tree_add_item(tt, hf->hfy_len, b, off + 2 + len, 2, FALSE); + proto_tree_add_item(tt, hf->hfy_val, b, off + 4 + len, len2, FALSE); + r = off + len + len2 + 4; + } + return (r); +} + static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t) { proto_item *ti; @@ -186,14 +219,14 @@ static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t) proto_tree_add_item(tt, hf_tripe_kx_type, b, 0, 1, FALSE); switch (ty & MSG_TYPEMASK) { case KX_PRECHAL: - off = getmp(tt, &hf_tripe_kx_mychal, b, off); + off = getge(tt, &hf_tripe_kx_mychal, b, off); goto tail; case KX_COOKIE: - off = getmp(tt, &hf_tripe_kx_mychal, b, off); + off = getge(tt, &hf_tripe_kx_mychal, b, off); off = gethash(tt, hf_tripe_kx_yourcookie, b, off); goto tail; case KX_CHAL: - off = getmp(tt, &hf_tripe_kx_mychal, b, off); + off = getge(tt, &hf_tripe_kx_mychal, b, off); off = gethash(tt, hf_tripe_kx_yourcookie, b, off); off = getmp(tt, &hf_tripe_kx_check, b, off); goto tail; @@ -295,17 +328,37 @@ void proto_register_tripe(void) &hf_tripe_kx_mychal.hf, { "Sender's challenge data", "tripe.kx.mychal", FT_BYTES, BASE_NONE, 0, 0, - "This is the sender's challenge value." + "This is the sender's challenge." }, &hf_tripe_kx_mychal.hf_len, { "Challenge length", "tripe.kx.mychal.len", FT_UINT16, BASE_DEC, 0, 0, - "This is the length of the sender's challenge value." + "This is the length of the sender's challenge." }, &hf_tripe_kx_mychal.hf_val, { - "Challenge value", "tripe.kx.mychal.val", + "Challenge", "tripe.kx.mychal.val", + FT_BYTES, BASE_NONE, 0, 0, + "This is the value of the sender's challenge." + }, + &hf_tripe_kx_mychal.hfx_len, { + "Challenge x length", "tripe.kx.mychal.x.len", + FT_UINT16, BASE_DEC, 0, 0, + "This is the length of the sender's challenge x-coordinate." + }, + &hf_tripe_kx_mychal.hfy_val, { + "Challenge x value", "tripe.kx.mychal.x.val", + FT_BYTES, BASE_NONE, 0, 0, + "This is the value of the sender's challenge x-coordinate." + }, + &hf_tripe_kx_mychal.hfy_len, { + "Challenge y length", "tripe.kx.mychal.y.len", + FT_UINT16, BASE_DEC, 0, 0, + "This is the length of the sender's challenge x-coordinate." + }, + &hf_tripe_kx_mychal.hfx_val, { + "Challenge y value", "tripe.kx.mychal.y.val", FT_BYTES, BASE_NONE, 0, 0, - "This is the value of the sender's challenge value." + "This is the value of the sender's challenge x-coordinate." }, &hf_tripe_kx_mycookie, { "Sender's hashed cookie", "tripe.kx.mycookie", diff --git a/keyexch.c b/keyexch.c index 35f027ec..ea503583 100644 --- a/keyexch.c +++ b/keyexch.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keyexch.c,v 1.10 2003/10/15 09:29:38 mdw Exp $ + * $Id: keyexch.c,v 1.11 2004/04/03 12:35:13 mdw Exp $ * * Key exchange protocol * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: keyexch.c,v $ + * Revision 1.11 2004/04/03 12:35:13 mdw + * Support elliptic curve key exchange. + * * Revision 1.10 2003/10/15 09:29:38 mdw * Cosmetic fix to changelog comment. * @@ -128,22 +131,22 @@ /*----- Various utilities -------------------------------------------------*/ -/* --- @hashmp@ --- * +/* --- @hashge@ --- * * * Arguments: @HASH_CTX *r@ = pointer to hash context - * @mp *m@ = pointer to multiprecision integer + * @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(HASH_CTX *r, 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)); } @@ -158,9 +161,10 @@ static void hashmp(HASH_CTX *r, mp *m) * * 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. + * 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 *mpcrypt(mp *d, mp *x, size_t sz, const octet *k, size_t ksz) @@ -240,8 +244,8 @@ 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); @@ -291,9 +295,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 = 0; + kxc->ck = MP_NEW; kxc->ks = 0; kxc->kx = kx; kxc->f = 0; @@ -304,19 +308,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); @@ -373,7 +377,7 @@ 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); @@ -387,7 +391,7 @@ 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, MSG_KEYEXCH | KX_REPLY, &bb, b); } @@ -415,7 +419,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) /* --- @getreply@ --- * * * Arguments: @keyexch *kx@ = pointer to key exchange context - * @mp *c@ = a challenge + * @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. @@ -423,38 +427,42 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) * Use: Computes replies to challenges. */ -static mp *getreply(keyexch *kx, mp *c, mp *ck) +static ge *getreply(keyexch *kx, ge *c, mp *ck) { - mp *r = mpmont_exp(&mg, MP_NEW, c, kpriv.x); - mp *a; + ge *r = G_CREATE(gg); + ge *y = G_CREATE(gg); + mp *a = MP_NEW; HASH_CTX h; octet buf[HASHSZ]; int ok; + G_EXP(gg, r, c, kpriv); HASH_INIT(&h); HASH_STRING(&h, "tripe-expected-reply"); - hashmp(&h, c); - hashmp(&h, kx->c); - hashmp(&h, r); + hashge(&h, c); + hashge(&h, kx->c); + hashge(&h, r); HASH_DONE(&h, buf); - a = mpcrypt(MP_NEW, ck, mp_octets(kpriv.dp.q), buf, sizeof(buf)); + a = mpcrypt(MP_NEW, ck, mp_octets(gg->r), buf, sizeof(buf)); IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { - trace(T_CRYPTO, "crypto: computed reply = %s", mpstr(r)); + trace(T_CRYPTO, "crypto: computed reply = %s", gestr(gg, r)); trace_block(T_CRYPTO, "crypto: computed reply hash", buf, HASHSZ); trace(T_CRYPTO, "crypto: recovered log = %s", mpstr(a)); })) - a = mpmont_exp(&mg, a, kpriv.dp.g, a); - ok = mp_eq(a, c); + 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", mpstr(a)); + trace(T_CRYPTO, "crypto: computed challenge = %s", gestr(gg, y)); })) - mp_drop(r); + G_DESTROY(gg, r); + r = 0; } mp_drop(a); - return (ok ? r : 0); + G_DESTROY(gg, y); + return (r); } /* --- @dochallenge@ --- * @@ -470,7 +478,8 @@ static mp *getreply(keyexch *kx, mp *c, mp *ck) static int dochallenge(keyexch *kx, unsigned msg, buf *b) { - mp *c = 0, *ck = 0; + ge *c = G_CREATE(gg); + mp *ck = MP_NEW; const octet *hc = 0; kxchal *kxc; HASH_CTX h; @@ -485,7 +494,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) /* --- Unpack the packet --- */ - if ((c = buf_getmp(b)) == 0 || + if (G_FROMBUF(gg, b, c) || (msg >= KX_COOKIE && (hc = buf_get(b, HASHSZ)) == 0) || (msg >= KX_CHAL && (ck = buf_getmp(b)) == 0) || BLEFT(b)) { @@ -494,7 +503,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)); + trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, c)); if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, HASHSZ); if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck)); })) @@ -507,10 +516,10 @@ 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); + G_TOBUF(gg, b, kx->c); HASH_INIT(&h); HASH_STRING(&h, "tripe-cookie"); - hashmp(&h, c); + hashge(&h, c); HASH_DONE(&h, buf_get(b, HASHSZ)); p_txend(kx->p); goto tidy; @@ -530,7 +539,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 --- * * @@ -547,47 +556,46 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) 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); + hashge(&h, kxc->c); HASH_DONE(&h, kxc->hc); /* --- 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); + hashge(&h, kx->c); + hashge(&h, kxc->c); + hashge(&h, kx->rx); HASH_DONE(&h, buf); - kxc->ck = mpcrypt(MP_NEW, kx->alpha, mp_octets(kpriv.dp.q), + kxc->ck = mpcrypt(MP_NEW, kx->alpha, mp_octets(gg->r), 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)); + r = G_CREATE(gg); + G_EXP(gg, r, c, kx->alpha); /* --- Compute the switch messages --- */ HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request"); - hashmp(&h, kx->c); hashmp(&h, kxc->c); + hashge(&h, kx->c); hashge(&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); + hashge(&h, kx->c); hashge(&h, kxc->c); HASH_DONE(&h, kxc->hswok_out); HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request"); - hashmp(&h, kxc->c); hashmp(&h, kx->c); + hashge(&h, kxc->c); hashge(&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); + hashge(&h, kxc->c); hashge(&h, kx->c); HASH_DONE(&h, kxc->hswok_in); IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { @@ -595,7 +603,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) 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(T_CRYPTO, "crypto: shared secret = %s", gestr(gg, r)); trace_block(T_CRYPTO, "crypto: outbound switch request", kxc->hswrq_out, HASHSZ); trace_block(T_CRYPTO, "crypto: outbound switch confirm", @@ -609,19 +617,19 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) /* --- 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, kx->p); - mp_drop(r); + G_DESTROY(gg, r); } /* --- Answer the challenge if we need to --- */ if (ck && !kxc->r) { - mp *r; + ge *r; if ((r = getreply(kx, c, ck)) == 0) goto bad; kxc->r = r; @@ -632,12 +640,12 @@ 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); } @@ -663,7 +671,7 @@ 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'", @@ -673,7 +681,7 @@ static void resend(keyexch *kx) buf_put(b, kx->hc, HASHSZ); buf_put(b, kxc->hc, HASHSZ); buf_init(&bb, buf_i, sizeof(buf_i)); - buf_putmp(&bb, kxc->r); + G_TOBUF(gg, &bb, kxc->r); buf_put(&bb, kxc->hswrq_out, HASHSZ); buf_flip(&bb); ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b); @@ -724,7 +732,7 @@ static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in, { kxchal *kxc; buf bb; - mp *r = 0; + ge *r = 0; /* --- Check the plaintext portions of the data --- */ @@ -763,25 +771,26 @@ static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in, 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); } @@ -983,8 +992,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; @@ -1009,23 +1018,23 @@ static void start(keyexch *kx, time_t now) 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); + hashge(&h, kx->c); HASH_DONE(&h, kx->hc); 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(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, HASHSZ); }) }) @@ -1050,7 +1059,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); } @@ -1160,8 +1169,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@ --- * @@ -1178,13 +1186,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'", @@ -1212,8 +1215,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); diff --git a/keymgmt.c b/keymgmt.c index 54a31b0b..a1097134 100644 --- a/keymgmt.c +++ b/keymgmt.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keymgmt.c,v 1.3 2001/06/22 19:40:36 mdw Exp $ + * $Id: keymgmt.c,v 1.4 2004/04/03 12:35:13 mdw Exp $ * * Key loading and storing * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: keymgmt.c,v $ + * Revision 1.4 2004/04/03 12:35:13 mdw + * Support elliptic curve key exchange. + * * Revision 1.3 2001/06/22 19:40:36 mdw * Support expiry of other peers' public keys. * @@ -46,8 +49,8 @@ /*----- Global variables --------------------------------------------------*/ -mpmont mg; -dh_priv kpriv; +group *gg; +mp *kpriv; /*----- Static variables --------------------------------------------------*/ @@ -55,6 +58,124 @@ static key_file *kf_pub; static const char *kr_priv, *kr_pub, *tag_priv; static fwatch w_priv, w_pub; +/*----- Key groups --------------------------------------------------------*/ + +typedef struct kgops { + const char *ty; + const char *(*loadpriv)(key_data *, group **, mp **, dstr *); + const char *(*loadpub)(key_data *, group **, ge **, dstr *); +} kgops; + +/* --- Diffie-Hellman --- */ + +static const char *kgdh_priv(key_data *kd, group **g, mp **x, dstr *t) +{ + key_packstruct kps[DH_PRIVFETCHSZ]; + key_packdef *kp; + dh_priv dp; + const char *e; + int rc; + + kp = key_fetchinit(dh_privfetch, kps, &dp); + if ((rc = key_unpack(kp, kd, t)) != 0) { + e = key_strerror(rc); + goto done; + } + *g = group_prime(&dp.dp); + *x = MP_COPY(dp.x); + e = 0; +done: + key_fetchdone(kp); + return (e); +} + +static const char *kgdh_pub(key_data *kd, group **g, ge **p, dstr *t) +{ + key_packstruct kps[DH_PUBFETCHSZ]; + key_packdef *kp; + dh_pub dp; + const char *e; + int rc; + + kp = key_fetchinit(dh_pubfetch, kps, &dp); + if ((rc = key_unpack(kp, kd, t)) != 0) { + e = key_strerror(rc); + goto done; + } + *g = group_prime(&dp.dp); + *p = G_CREATE(*g); + if (G_FROMINT(*g, *p, dp.y)) { + e = "bad public value"; + goto done; + } + e = 0; +done: + key_fetchdone(kp); + return (e); +} + +static const kgops kgdh_ops = { "tripe-dh", kgdh_priv, kgdh_pub }; + +/* --- Elliptic curve --- */ + +static const char *kgec_priv(key_data *kd, group **g, mp **x, dstr *t) +{ + key_packstruct kps[EC_PRIVFETCHSZ]; + key_packdef *kp; + ec_priv ep; + ec_info ei; + const char *e; + int rc; + + kp = key_fetchinit(ec_privfetch, kps, &ep); + if ((rc = key_unpack(kp, kd, t)) != 0) { + e = key_strerror(rc); + goto done; + } + if ((e = ec_getinfo(&ei, ep.cstr)) != 0) + goto done; + *g = group_ec(&ei); + *x = MP_COPY(ep.x); + e = 0; +done: + key_fetchdone(kp); + return (e); +} + +static const char *kgec_pub(key_data *kd, group **g, ge **p, dstr *t) +{ + key_packstruct kps[EC_PUBFETCHSZ]; + key_packdef *kp; + ec_pub ep; + ec_info ei; + const char *e; + int rc; + + kp = key_fetchinit(ec_pubfetch, kps, &ep); + if ((rc = key_unpack(kp, kd, t)) != 0) { + e = key_strerror(rc); + goto done; + } + if ((e = ec_getinfo(&ei, ep.cstr)) != 0) + goto done; + *g = group_ec(&ei); + *p = G_CREATE(*g); + if (G_FROMEC(*g, *p, &ep.p)) { + e = "bad public point"; + goto done; + } + e = 0; +done: + key_fetchdone(kp); + return (e); +} + +static const kgops kgec_ops = { "tripe-ec", kgec_priv, kgec_pub }; + +/* --- Table of supported key types --- */ + +static const kgops *kgtab[] = { &kgdh_ops, &kgec_ops, 0 }; + /*----- Main code ---------------------------------------------------------*/ /* --- @keymoan@ --- * @@ -70,60 +191,112 @@ static fwatch w_priv, w_pub; */ static void keymoan(const char *file, int line, const char *msg, void *p) -{ - a_warn("%s:%i: error: %s", file, line, msg); -} + { a_warn("%s:%i: error: %s", file, line, msg); } /* --- @loadpriv@ --- * * * Arguments: @dstr *d@ = string to write errors in - * @dh_priv *dh@ = where to store the key * * Returns: Zero if OK, nonzero on error. * * Use: Loads the private key from its keyfile. */ -static int loadpriv(dstr *d, dh_priv *dh) +static int loadpriv(dstr *d) { key_file kf; - key_packstruct kps[DH_PRIVFETCHSZ]; - key_packdef *kp; - dh_priv mydh; - int rc = 0; - int e; + key *k; + key_data *kd; + dstr t = DSTR_INIT; + group *g = 0; + mp *x = 0; + int rc = -1; + const kgops **ko; + const char *e; + + /* --- Open the private key file --- */ if (key_open(&kf, kr_priv, KOPEN_READ, keymoan, 0)) { dstr_putf(d, "error reading private keyring `%s': %s", kr_priv, strerror(errno)); - rc = -1; - } else { - T( trace(T_KEYMGMT, "keymgmt: loaded private keyring `%s'", kr_priv); ) - kp = key_fetchinit(dh_privfetch, kps, &mydh); - if ((e = key_fetchbyname(kp, &kf, tag_priv)) != 0) { - dstr_putf(d, "error loading private key `%s': %s", - tag_priv, key_strerror(e)); - rc = -1; - } else { - dh->dp.p = MP_COPY(mydh.dp.p); - dh->dp.q = MP_COPY(mydh.dp.q); - dh->dp.g = MP_COPY(mydh.dp.g); - dh->x = MP_COPY(mydh.x); - dh->y = MP_COPY(mydh.y); - IF_TRACING(T_KEYMGMT, { - trace(T_KEYMGMT, "keymgmt: extracted private key `%s'", tag_priv); - IF_TRACING(T_CRYPTO, { - trace(T_CRYPTO, "crypto: p = %s", mpstr(kpriv.dp.p)); - trace(T_CRYPTO, "crypto: q = %s", mpstr(kpriv.dp.q)); - trace(T_CRYPTO, "crypto: g = %s", mpstr(kpriv.dp.g)); - trace(T_CRYPTO, "crypto: x = %s", mpstr(kpriv.x)); - trace(T_CRYPTO, "crypto: g^x = %s", mpstr(kpriv.y)); - }) - }) + goto done_0; + } + + /* --- Find the private key --- */ + + if (key_qtag(&kf, tag_priv, &t, &k, &kd)) { + dstr_putf(d, "private key `%s' not found in keyring `%s'", + tag_priv, kr_priv); + goto done_1; + } + + /* --- Look up the key type in the table --- */ + + for (ko = kgtab; *ko; ko++) { + if (strcmp((*ko)->ty, k->type) == 0) + goto tymatch; + } + dstr_putf(d, "private key `%s' has unknown type `%s'", t.buf, k->type); + goto done_1; +tymatch:; + + /* --- Load the key --- */ + + if ((e = (*ko)->loadpriv(kd, &g, &x, &t)) != 0) { + dstr_putf(d, "error reading private key `%s': %s", t.buf, e); + goto done_1; + } + + /* --- Check that the key is sensible --- */ + + if ((e = G_CHECK(g, &rand_global)) != 0) { + dstr_putf(d, "bad group in private key `%s': %s", t.buf, e); + goto done_1; + } + + /* --- Good, we're happy --- * + * + * Dodginess! We change the group over here, but don't free any old group + * elements. This assumes that the new group is basically the same as the + * old one, and will happily adopt the existing elements. If it isn't, + * then we lose badly. Check this, then. + */ + + if (gg) { + if (!group_samep(g, gg)) { + dstr_putf(d, "private key `%s' has different group", t.buf); + goto done_1; } - key_fetchdone(kp); - key_close(&kf); + G_DESTROYGROUP(gg); } + if (kpriv) + mp_drop(kpriv); + + /* --- Dump out the group --- */ + + IF_TRACING(T_KEYMGMT, { + trace(T_KEYMGMT, "keymgmt: extracted private key `%s'", t.buf); + IF_TRACING(T_CRYPTO, { + trace(T_CRYPTO, "crypto: r = %s", mpstr(g->r)); + trace(T_CRYPTO, "crypto: h = %s", mpstr(g->h)); + trace(T_CRYPTO, "crypto: x = %s", mpstr(x)); + }) + }) + + /* --- Success! --- */ + + gg = g; g = 0; + kpriv = x; x = 0; + rc = 0; + + /* --- Tidy up --- */ + +done_1: + key_close(&kf); +done_0: + dstr_destroy(&t); + if (x) mp_drop(x); + if (g) G_DESTROYGROUP(g); return (rc); } @@ -163,7 +336,6 @@ static int loadpub(dstr *d) int km_interval(void) { dstr d = DSTR_INIT; - dh_priv dh; key_file *kf; int reload = 0; @@ -172,15 +344,10 @@ int km_interval(void) if (fwatch_update(&w_priv, kr_priv)) { T( trace(T_KEYMGMT, "keymgmt: private keyring updated: reloading..."); ) DRESET(&d); - if (loadpriv(&d, &dh)) + if (loadpriv(&d)) a_warn("%s -- ignoring changes", d.buf); - else { + else reload = 1; - mpmont_destroy(&mg); - dh_privfree(&kpriv); - kpriv = dh; - mpmont_create(&mg, kpriv.dp.p); - } } /* --- Now check the public keys --- */ @@ -225,9 +392,8 @@ void km_init(const char *priv, const char *pub, const char *tag) fwatch_init(&w_pub, kr_pub); DRESET(&d); - if (loadpriv(&d, &kpriv)) + if (loadpriv(&d)) die(EXIT_FAILURE, "%s", d.buf); - mpmont_create(&mg, kpriv.dp.p); if (loadpub(&d)) die(EXIT_FAILURE, "%s", d.buf); } @@ -235,7 +401,7 @@ void km_init(const char *priv, const char *pub, const char *tag) /* --- @km_getpubkey@ --- * * * Arguments: @const char *tag@ = public key tag to load - * @dh_pub *kpub@ = where to put the public key + * @ge *kpub@ = where to put the public key * @time_t *t_exp@ = where to put the expiry time * * Returns: Zero if OK, nonzero if it failed. @@ -243,45 +409,79 @@ void km_init(const char *priv, const char *pub, const char *tag) * Use: Fetches a public key from the keyring. */ -int km_getpubkey(const char *tag, dh_pub *kpub, time_t *t_exp) +int km_getpubkey(const char *tag, ge *kpub, time_t *t_exp) { - key_packstruct kps[DH_PUBFETCHSZ]; - key_packdef *kp; key *k; - dh_pub dp; - int e; + key_data *kd; + dstr t = DSTR_INIT; + const kgops **ko; + const char *e; + group *g = 0; + ge *p = 0; + int rc = -1; + + /* --- Find the key --- */ + + if (key_qtag(kf_pub, tag, &t, &k, &kd)) { + a_warn("private key `%s' not found in keyring `%s'", tag_priv, kr_priv); + goto done; + } - kp = key_fetchinit(dh_pubfetch, kps, &dp); - if ((k = key_bytag(kf_pub, tag)) == 0) - e = KERR_NOTFOUND; - else - e = key_fetch(kp, k); - key_fetchdone(kp); - if (e) { - a_warn("error loading public key `%s': %s", tag, key_strerror(e)); - return (-1); + /* --- Look up the key type in the table --- */ + + for (ko = kgtab; *ko; ko++) { + if (strcmp((*ko)->ty, k->type) == 0) + goto tymatch; + } + a_warn("public key `%s' has unknown type `%s'", t.buf, k->type); + goto done; +tymatch:; + + /* --- Load the key --- */ + + if ((e = (*ko)->loadpub(kd, &g, &p, &t)) != 0) { + a_warn("error reading public key `%s': %s", t.buf, e); + goto done; + } + + /* --- Ensure that the group is correct --- * + * + * Dodginess! We assume that if this works, our global group is willing to + * adopt this public element. Probably reasonable. + */ + + if (!group_samep(gg, g)) { + a_warn("public key `%s' has incorrect group", t.buf); + goto done; + } + + /* --- Check the public group element --- */ + + if (group_check(gg, p)) { + a_warn("public key `%s' has bad public group element", t.buf); + goto done; } + + /* --- Dump the public key --- */ + IF_TRACING(T_KEYMGMT, { - trace(T_KEYMGMT, "keymgmt: extracted public key `%s'", tag); - IF_TRACING(T_CRYPTO, { - trace(T_CRYPTO, "crypto: p = %s", mpstr(dp.dp.p)); - trace(T_CRYPTO, "crypto: q = %s", mpstr(dp.dp.q)); - trace(T_CRYPTO, "crypto: g = %s", mpstr(dp.dp.g)); - trace(T_CRYPTO, "crypto: g^x = %s", mpstr(dp.y)); - }) + trace(T_KEYMGMT, "keymgmt: extracted public key `%s'", t.buf); + trace(T_CRYPTO, "crypto: p = %s", gestr(gg, p)); }) - if (!mp_eq(dp.dp.p, kpriv.dp.p) || - !mp_eq(dp.dp.q, kpriv.dp.q) || - !mp_eq(dp.dp.g, kpriv.dp.g)) { - a_warn("public key `%s' has different group from private key", tag); - return (-1); - } - kpub->dp.p = MP_COPY(dp.dp.p); - kpub->dp.q = MP_COPY(dp.dp.q); - kpub->dp.g = MP_COPY(dp.dp.g); - kpub->y = MP_COPY(dp.y); + + /* --- OK, accept the public key --- */ + *t_exp = k->exp; - return (0); + G_COPY(gg, kpub, p); + rc = 0; + + /* --- Tidy up --- */ + +done: + if (p) G_DESTROY(g, p); + if (g) G_DESTROYGROUP(g); + dstr_destroy(&t); + return (rc); } /*----- That's all, folks -------------------------------------------------*/ diff --git a/mallory.c b/mallory.c index c66b45f4..bca2cff1 100644 --- a/mallory.c +++ b/mallory.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: mallory.c,v 1.2 2003/10/15 09:31:06 mdw Exp $ + * $Id: mallory.c,v 1.3 2004/04/03 12:35:13 mdw Exp $ * * An evil proxy for TrIPE * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: mallory.c,v $ + * Revision 1.3 2004/04/03 12:35:13 mdw + * Support elliptic curve key exchange. + * * Revision 1.2 2003/10/15 09:31:06 mdw * Make forking work properly. * @@ -73,7 +76,6 @@ #include #include -#include #include #include diff --git a/servutil.c b/servutil.c index dac92b7b..c3465e79 100644 --- a/servutil.c +++ b/servutil.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: servutil.c,v 1.3 2001/06/19 22:08:11 mdw Exp $ + * $Id: servutil.c,v 1.4 2004/04/03 12:35:13 mdw Exp $ * * Various handy server-only utilities * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: servutil.c,v $ + * Revision 1.4 2004/04/03 12:35:13 mdw + * Support elliptic curve key exchange. + * * Revision 1.3 2001/06/19 22:08:11 mdw * Use magic number for packet size. * @@ -68,6 +71,24 @@ const char *mpstr(mp *m) return ((const char *)buf_t); } +/* --- @gestr@ --- * + * + * Arguments: @group *g@ = a group + * @ge *x@ = a group element + * + * Returns: A pointer to the element's textual representation. + * + * Use: Converts a group element to a string. Corrupts + * @buf_t@. + */ + +const char *gestr(group *g, ge *x) +{ + if (group_writestring(g, x, (char *)buf_t, sizeof(buf_t))) + return (""); + return ((const char *)buf_t); +} + /* --- @timestr@ --- * * * Arguments: @time_t t@ = a time to convert diff --git a/tripe-init.in b/tripe-init.in index db9cb35f..8c4730e5 100755 --- a/tripe-init.in +++ b/tripe-init.in @@ -105,6 +105,7 @@ case "$1" in $tripectl -D -s -p$tripe \ -f${logfile-@logfile@} \ -P${pidfile-@pidfile@} \ + ${keytag+-S-t}$keytag \ ${addr+-S-b}$addr \ ${port+-S-p}${port} \ ${user+-S-u}${user} \ diff --git a/tripe.conf b/tripe.conf index 36bb1326..dd2de57e 100644 --- a/tripe.conf +++ b/tripe.conf @@ -6,6 +6,11 @@ # keyrings, and where its admin socket and logfile are kept. # TRIPEDIR=/etc/tripe +# The name of the private key to use. This is usually `tripe-dh' for +# integer Diffie-Hellman keys (the default) or `tripe-ec' for elliptic +# curve keys. +# keytag=tripe-dh + # The address you want tripe to bind to. By default, tripe will accept # packets to any address acceptable to the host, and send packets from the # most appropriate address for the destination; setting this means it will diff --git a/tripe.h b/tripe.h index 385c45a2..2929200c 100644 --- a/tripe.h +++ b/tripe.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: tripe.h,v 1.17 2003/10/15 09:30:18 mdw Exp $ + * $Id: tripe.h,v 1.18 2004/04/03 12:35:13 mdw Exp $ * * Main header file for TrIPE * @@ -29,6 +29,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: tripe.h,v $ + * Revision 1.18 2004/04/03 12:35:13 mdw + * Support elliptic curve key exchange. + * * Revision 1.17 2003/10/15 09:30:18 mdw * Add support for Ethereal protocol analysis. * @@ -153,9 +156,11 @@ #include #include -#include #include #include +#include +#include +#include #include "tripe-protocol.h" #include "util.h" @@ -278,8 +283,8 @@ typedef struct keyset { typedef struct kxchal { struct keyexch *kx; /* Pointer back to key exchange */ - mp *c; /* Responder's challenge */ - mp *r; /* My reply to the challenge */ + ge *c; /* Responder's challenge */ + ge *r; /* My reply to the challenge */ keyset *ks; /* Pointer to temporary keyset */ unsigned f; /* Various useful flags */ sel_timer t; /* Response timer for challenge */ @@ -297,11 +302,11 @@ typedef struct keyexch { unsigned f; /* Various useful flags */ unsigned s; /* Current state in exchange */ sel_timer t; /* Timer for next exchange */ - dh_pub kpub; /* Peer's public key */ + ge *kpub; /* Peer's public key */ time_t texp_kpub; /* Expiry time for public key */ mp *alpha; /* My temporary secret */ - mp *c; /* My challenge */ - mp *rx; /* The expected response */ + ge *c; /* My challenge */ + ge *rx; /* The expected response */ unsigned nr; /* Number of extant responses */ time_t t_valid; /* When this exchange goes bad */ octet hc[HASHSZ]; /* Hash of my challenge */ @@ -415,8 +420,8 @@ typedef struct admin { /*----- Global variables --------------------------------------------------*/ extern sel_state sel; /* Global I/O event state */ -extern dh_priv kpriv; /* Our private key */ -extern mpmont mg; /* Montgomery context for DH group */ +extern group *gg; /* The group we work in */ +extern mp *kpriv; /* Our private key */ extern octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ]; #ifndef NTRACE @@ -458,7 +463,7 @@ extern void km_init(const char */*kr_priv*/, const char */*kr_pub*/, /* --- @km_getpubkey@ --- * * * Arguments: @const char *tag@ = public key tag to load - * @dh_pub *kpub@ = where to put the public key + * @ge *kpub@ = where to put the public key * @time_t *t_exp@ = where to put the expiry time * * Returns: Zero if OK, nonzero if it failed. @@ -466,7 +471,7 @@ extern void km_init(const char */*kr_priv*/, const char */*kr_pub*/, * Use: Fetches a public key from the keyring. */ -extern int km_getpubkey(const char */*tag*/, dh_pub */*kpub*/, +extern int km_getpubkey(const char */*tag*/, ge */*kpub*/, time_t */*t_exp*/); /*----- Key exchange ------------------------------------------------------*/ @@ -988,6 +993,19 @@ extern void tun_destroy(tunnel */*t*/); extern const char *mpstr(mp */*m*/); +/* --- @gestr@ --- * + * + * Arguments: @group *g@ = a group + * @ge *x@ = a group element + * + * Returns: A pointer to the element's textual representation. + * + * Use: Converts a group element to a string. Corrupts + * @buf_t@. + */ + +extern const char *gestr(group */*g*/, ge */*x*/); + /* --- @timestr@ --- * * * Arguments: @time_t t@ = a time to convert -- [mdw]