From b5c45da15703d85b506a1ea1eb38c318c3418ed3 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Sun, 18 Apr 2004 18:08:11 +0000 Subject: [PATCH] Allow user-specified symmetric crypto algorithms. Organization: Straylight/Edgeware From: mdw --- doc/tripe.8 | 28 ++++++ ethereal/packet-tripe.c | 56 +++++++---- keyexch.c | 199 ++++++++++++++++++++++------------------ keymgmt.c | 167 ++++++++++++++++++++++++++++++++- keyset.c | 177 +++++++++++++++++++++-------------- tripe.c | 6 +- tripe.h | 47 ++++------ 7 files changed, 471 insertions(+), 209 deletions(-) diff --git a/doc/tripe.8 b/doc/tripe.8 index b6da8d81..929f0191 100644 --- a/doc/tripe.8 +++ b/doc/tripe.8 @@ -444,6 +444,34 @@ Now start with the .B \-ttripe\-ec option, and all should be well. +.SS "Using other symmetric algorithms" +The default symmetric algorithms +.B tripe +uses are Blowfish (by Schneier) for symmetric encryption, and RIPEMD-160 +(by Dobbertin, Bosselaers and Preneel) for hashing and as a MAC (in HMAC +mode, designed by Bellare, Canetti and Krawczyk). These can all be +overridden by setting attributes on your private key, as follows. +.TP +.B cipher +Names the symmetric encryption scheme to use. The default is +.BR blowfish\-cbc . +.TP +.B hash +Names the hash function to use. The default is +.BR rmd160 . +.TP +.B mac +Names the message authentication code to use. The name of the MAC may +be followed by a +.RB ` / ' +and the desired tag length in bits. The default is +.IB hash \-hmac +at half the underlying hash function's output length. +.TP +.B mgf +A `mask-generation function', used in the key-exchange. The default is +.IB hash \-mgf +and there's no good reason to change it. .SS "About the name" The program's name is .BR tripe , diff --git a/ethereal/packet-tripe.c b/ethereal/packet-tripe.c index 4b4e0ace..afeb1bcc 100644 --- a/ethereal/packet-tripe.c +++ b/ethereal/packet-tripe.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: packet-tripe.c,v 1.3 2004/04/08 01:36:17 mdw Exp $ + * $Id: packet-tripe.c,v 1.4 2004/04/18 18:08:11 mdw Exp $ * * TrIPE protocol dissector for Ethereal * @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef ETHEREAL_BUGGERED # define plugin_address_table_t void @@ -53,6 +54,8 @@ static int proto_tripe = -1; +static guint hashsz = 20, tagsz = 10, ivsz = 8; + typedef struct hfmp { int hf, hf_len, hf_val, tt; } hfmp; @@ -65,8 +68,8 @@ static int hf_tripe_packet_type = -1; static int hf_tripe_ct = -1; static int hf_tripe_ct_seq = -1; 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_ct_ct = -1; +static int hf_tripe_ct_tag = -1; static int hf_tripe_kx_type = -1; static hfge hf_tripe_kx_mychal = { -1, -1, -1, -1, -1, -1, -1, -1 }; static int hf_tripe_kx_mycookie = -1; @@ -81,10 +84,12 @@ G_MODULE_EXPORT const gchar version[] = VERSION; /*----- Main code ---------------------------------------------------------*/ +static void prefcb(void) { } + static gint gethash(proto_tree *tt, int hf, tvbuff_t *b, gint off) { - proto_tree_add_item(tt, hf, b, off, 20, FALSE); - return (off + 20); + proto_tree_add_item(tt, hf, b, off, hashsz, FALSE); + return (off + hashsz); } static gint getmp(proto_tree *tt, const hfmp *hf, tvbuff_t *b, gint off) @@ -246,17 +251,21 @@ static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t) goto done; ct: ti = proto_tree_add_item(tt, hf_tripe_ct, b, off, -1, FALSE); - seq = tvb_get_ntohl(b, off + 10); + seq = tvb_get_ntohl(b, off + tagsz); proto_item_set_text(ti, "Encrypted ciphertext (sequence number %lu)", (unsigned long)seq); tt = proto_item_add_subtree(ti, tt_tripe_ct); - proto_tree_add_item(tt, hf_tripe_ct_mac, b, off, 10, FALSE); - off += 10; + if (tagsz) { + proto_tree_add_item(tt, hf_tripe_ct_tag, b, off, tagsz, FALSE); + off += tagsz; + } proto_tree_add_item(tt, hf_tripe_ct_seq, b, off, 4, FALSE); off += 4; - proto_tree_add_item(tt, hf_tripe_ct_iv, b, off, 8, FALSE); - off += 8; - proto_tree_add_item(ti, hf_tripe_ct_cbc, b, off, -1, FALSE); + if (ivsz) { + proto_tree_add_item(tt, hf_tripe_ct_iv, b, off, ivsz, FALSE); + off += ivsz; + } + proto_tree_add_item(ti, hf_tripe_ct_ct, b, off, -1, FALSE); goto done; done:; } @@ -264,6 +273,8 @@ static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t) void proto_register_tripe(void) { + module_t *mod; + static value_string vs_kxtype[] = { { KX_PRECHAL, "KX_PRECHAL (prechallenge)" }, { KX_COOKIE, "KX_COOKIE (cookie)" }, @@ -299,15 +310,15 @@ void proto_register_tripe(void) FT_BYTES, BASE_NONE, 0, 0, "This is the initialization vector used for the actual encryption." }, - &hf_tripe_ct_cbc, { - "CBC-encrypted data", "tripe.ct.cbc", + &hf_tripe_ct_ct, { + "Actual encrypted data", "tripe.ct.ct", FT_BYTES, BASE_NONE, 0, 0, - "This is the CBC-encrypted message. Reading it ought to be hard." + "This is the encrypted message. Reading it ought to be hard." }, - &hf_tripe_ct_mac, { - "Message authentication code", "tripe.ct.mac", + &hf_tripe_ct_tag, { + "Message authentication code", "tripe.ct.tag", FT_BYTES, BASE_NONE, 0, 0, - "This is the message authentication code for the ciphertext." + "This is the message authentication code tag for the ciphertext." }, &hf_tripe_kx_type, { "Key-exchange message type", "tripe.kx.type", @@ -392,6 +403,17 @@ void proto_register_tripe(void) proto_tripe = proto_register_protocol("TrIPE", "TrIPE", "tripe"); proto_register_field_array(proto_tripe, hfs, array_length(hfs)); proto_register_subtree_array(tts, array_length(tts)); + + mod = prefs_register_protocol(proto_tripe, prefcb); + prefs_register_uint_preference(mod, "hashsz", "Hash length", + "hash function output length (in octets)", + 10, &hashsz); + prefs_register_uint_preference(mod, "tagsz", "MAC tag length", + "MAC tag length (in octets)", 10, &tagsz); + prefs_register_uint_preference(mod, "ivsz", "IV length", + "block cipher initialization vector length" + " (in octets)", + 10, &ivsz); } void proto_reg_handoff_tripe(void) diff --git a/keyexch.c b/keyexch.c index 97965c85..18594cf3 100644 --- a/keyexch.c +++ b/keyexch.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keyexch.c,v 1.12 2004/04/08 01:36:17 mdw Exp $ + * $Id: keyexch.c,v 1.13 2004/04/18 18:08:11 mdw Exp $ * * Key exchange protocol * @@ -91,7 +91,7 @@ /* --- @hashge@ --- * * - * Arguments: @HASH_CTX *r@ = pointer to hash context + * Arguments: @ghash *h@ = pointer to hash context * @ge *x@ = pointer to group element * * Returns: --- @@ -100,22 +100,21 @@ * @buf_t@. */ -static void hashge(HASH_CTX *r, ge *x) +static void hashge(ghash *h, ge *x) { buf b; buf_init(&b, buf_t, sizeof(buf_t)); G_TOBUF(gg, &b, x); assert(BOK(&b)); - HASH(r, BBASE(&b), BLEN(&b)); + GH_HASH(h, BBASE(&b), BLEN(&b)); } -/* --- @mpcrypt@ --- * +/* --- @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 - * @size_t ksz@ = size of the key * * Returns: The encrypted/decrypted integer. * @@ -125,13 +124,25 @@ static void hashge(HASH_CTX *r, ge *x) * encryption thing. */ -static mp *mpcrypt(mp *d, mp *x, size_t sz, const octet *k, size_t ksz) +static mp *mpencrypt(mp *d, mp *x, size_t sz, const octet *k) { - MGF_CTX m; + gcipher *mgf; - MGF_INIT(&m, k, ksz, 0); + mgf = GC_INIT(algs.mgf, k, algs.hashsz); mp_storeb(x, buf_t, sz); - MGF_CRYPT(&m, buf_t, 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)); } @@ -299,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); @@ -337,8 +348,8 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) if (!kxc->r) G_TOBUF(gg, b, kx->c); else - 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_putmp(b, kxc->ck); /* --- Maybe send an actual reply, if we have one --- */ @@ -390,24 +401,25 @@ static ge *getreply(keyexch *kx, ge *c, mp *ck) ge *r = G_CREATE(gg); ge *y = G_CREATE(gg); mp *a = MP_NEW; - HASH_CTX h; - octet buf[HASHSZ]; + ghash *h; + const octet *hh; int ok; G_EXP(gg, r, c, kpriv); - HASH_INIT(&h); - HASH_STRING(&h, "tripe-expected-reply"); - hashge(&h, c); - hashge(&h, kx->c); - hashge(&h, r); - HASH_DONE(&h, buf); - - a = mpcrypt(MP_NEW, ck, mp_octets(gg->r), buf, sizeof(buf)); + 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", gestr(gg, r)); - trace_block(T_CRYPTO, "crypto: computed reply hash", buf, HASHSZ); + trace_block(T_CRYPTO, "crypto: computed reply hash", hh, algs.hashsz); trace(T_CRYPTO, "crypto: recovered log = %s", mpstr(a)); })) + GH_DESTROY(h); G_EXP(gg, y, gg->g, a); ok = G_EQ(gg, y, c); if (!ok) { @@ -440,8 +452,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) mp *ck = MP_NEW; const octet *hc = 0; kxchal *kxc; - HASH_CTX h; - octet buf[HASHSZ]; + ghash *h; /* --- Ensure that we're in a sensible state --- */ @@ -453,7 +464,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) /* --- Unpack the packet --- */ if (G_FROMBUF(gg, b, c) || - (msg >= KX_COOKIE && (hc = buf_get(b, HASHSZ)) == 0) || + (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)); @@ -462,7 +473,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, { trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, c)); - if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, HASHSZ); + if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, algs.hashsz); if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck)); })) @@ -475,17 +486,18 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) T( trace(T_KEYEXCH, "keyexch: too many challenges -- sending cookie"); ) b = p_txstart(kx->p, MSG_KEYEXCH | KX_COOKIE); G_TOBUF(gg, b, kx->c); - HASH_INIT(&h); - HASH_STRING(&h, "tripe-cookie"); - hashge(&h, c); - HASH_DONE(&h, buf_get(b, HASHSZ)); + 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; } @@ -519,57 +531,64 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b) /* --- Work out the cookie for this challenge --- */ - HASH_INIT(&h); - HASH_STRING(&h, "tripe-cookie"); - hashge(&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"); - 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(gg->r), - buf, sizeof(buf)); + 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 = 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"); - hashge(&h, kx->c); hashge(&h, kxc->c); - HASH_DONE(&h, kxc->hswrq_out); - HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm"); - hashge(&h, kx->c); hashge(&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"); - hashge(&h, kxc->c); hashge(&h, kx->c); - HASH_DONE(&h, kxc->hswrq_in); - HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm"); - hashge(&h, kxc->c); hashge(&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: expected-reply hash", - buf, HASHSZ); - trace(T_CRYPTO, "crypto: my reply check = %s", mpstr(kxc->ck)); - trace(T_CRYPTO, "crypto: shared secret = %s", gestr(gg, 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 --- */ @@ -636,11 +655,11 @@ static void resend(keyexch *kx) 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)); G_TOBUF(gg, &bb, kxc->r); - buf_put(&bb, kxc->hswrq_out, HASHSZ); + buf_put(&bb, kxc->hswrq_out, algs.hashsz); buf_flip(&bb); ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b); break; @@ -650,7 +669,7 @@ 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, MSG_KEYEXCH | KX_SWITCHOK, &bb, b); break; @@ -695,11 +714,11 @@ static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in, /* --- 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); + 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; } @@ -798,8 +817,8 @@ static int doreply(keyexch *kx, buf *b) 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 || + 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; @@ -838,22 +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, 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; } @@ -900,14 +919,15 @@ static int doswitchok(keyexch *kx, buf *b) 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; } @@ -970,7 +990,7 @@ static void stop(keyexch *kx) static void start(keyexch *kx, time_t now) { - HASH_CTX h; + ghash *h; assert(kx->f & KXF_DEAD); @@ -982,10 +1002,11 @@ static void start(keyexch *kx, time_t now) kx->s = KXS_CHAL; kx->t_valid = now + T_VALID; - HASH_INIT(&h); - HASH_STRING(&h, "tripe-cookie"); - hashge(&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"); @@ -993,7 +1014,7 @@ static void start(keyexch *kx, time_t now) trace(T_CRYPTO, "crypto: secret = %s", mpstr(kx->alpha)); 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); + trace_block(T_CRYPTO, "crypto: challenge cookie", kx->hc, algs.hashsz); }) }) } diff --git a/keymgmt.c b/keymgmt.c index 2935f1c9..e05706ac 100644 --- a/keymgmt.c +++ b/keymgmt.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keymgmt.c,v 1.5 2004/04/08 01:36:17 mdw Exp $ + * $Id: keymgmt.c,v 1.6 2004/04/18 18:08:11 mdw Exp $ * * Key loading and storing * @@ -34,6 +34,7 @@ group *gg; mp *kpriv; +algswitch algs; /*----- Static variables --------------------------------------------------*/ @@ -159,6 +160,132 @@ static const kgops kgec_ops = { "tripe-ec", kgec_priv, kgec_pub }; static const kgops *kgtab[] = { &kgdh_ops, &kgec_ops, 0 }; +/*----- Algswitch stuff ---------------------------------------------------*/ + +/* --- @algs_get@ --- * + * + * Arguments: @algswitch *a@ = where to put the algorithms + * @key_file *kf@ = key file (for some stupid reason) + * @key *k@ = key to inspect + * + * Returns: Null if OK, or an error message. + * + * Use: Extracts an algorithm choice from a key. + */ + +static const char *algs_get(algswitch *a, key_file *kf, key *k) +{ + const char *p; + char *q; + dstr d = DSTR_INIT; + const char *e; + +#define FAIL(msg) do { e = msg; goto done; } while (0) + + if ((p = key_getattr(kf, k, "cipher")) == 0) + p = "blowfish-cbc"; + if ((a->c = gcipher_byname(p)) == 0) + FAIL("unknown cipher"); + + if ((p = key_getattr(kf, k, "hash")) == 0) + p = "rmd160"; + if ((a->h = ghash_byname(p)) == 0) + FAIL("unknown hash function"); + + if ((p = key_getattr(kf, k, "mgf")) != 0) { + dstr_reset(&d); + dstr_putf(&d, "%s-mgf"); + p = d.buf; + } + if ((a->mgf = gcipher_byname(p)) == 0) + FAIL("unknown MGF cipher"); + + if ((p = key_getattr(kf, k, "mac")) != 0) { + dstr_reset(&d); + dstr_puts(&d, p); + if ((q = strchr(d.buf, '/')) != 0) + *q++ = 0; + if ((a->m = gmac_byname(d.buf)) == 0) + FAIL("unknown message authentication code"); + if (!q) + a->tagsz = a->m->hashsz; + else { + unsigned long n = strtoul(q, &q, 0); + if (*q) FAIL("bad tag length string"); + if (n%8 || n > ~(size_t)0) FAIL("bad tag length"); + a->tagsz = n/8; + } + } else { + dstr_reset(&d); + dstr_putf(&d, "%s-hmac", a->h->name); + if ((a->m = gmac_byname(d.buf)) == 0) + FAIL("failed to derive HMAC from hash function"); + a->tagsz = a->h->hashsz/2; + } + + e = 0; +done: + dstr_destroy(&d); + return (e); +} + +/* --- @algs_check@ --- * + * + * Arguments: @algswitch *a@ = a choice of algorithms + * @const group *g@ = the group we're working in + * + * Returns: Null if OK, or an error message. + * + * Use: Checks an algorithm choice for sensibleness. This also + * derives some useful information from the choices, and you + * must call this before committing the algorithm selection + * for use by @keyset@ functions. + */ + +static const char *algs_check(algswitch *a, const group *g) +{ + /* --- Derive the key sizes --- * + * + * Must ensure that we have non-empty keys. This isn't ideal, but it + * provides a handy sanity check. + */ + + a->hashsz = a->h->hashsz; + if ((a->cksz = keysz(a->hashsz, a->c->keysz)) == 0) + return ("no key size found for cipher"); + if ((a->mksz = keysz(a->hashsz, a->m->keysz)) == 0) + return ("no key size found for MAC"); + + /* --- Ensure that the tag size is sane --- */ + + if (a->tagsz > a->m->hashsz) return ("tag length too large"); + + /* --- Ensure the MGF accepts hashes as keys --- */ + + if (keysz(a->hashsz, a->mgf->keysz) != a->hashsz) + return ("MGF not suitable -- restrictive key schedule"); + + /* --- All ship-shape and Bristol-fashion --- */ + + return (0); +} + +/* --- @algs_samep@ --- * + * + * Arguments: @const algswitch *a, *aa@ = two algorithm selections + * + * Returns: Nonzero if the two selections are the same. + * + * Use: Checks sameness of algorithm selections: used to ensure that + * peers are using sensible algorithms. + */ + +static int algs_samep(const algswitch *a, const algswitch *aa) +{ + return (a->c == aa->c && a->mgf == aa->mgf && a->h == aa->h && + a->m == aa->m && a->tagsz == aa->tagsz); +} + /*----- Main code ---------------------------------------------------------*/ /* --- @keymoan@ --- * @@ -196,6 +323,7 @@ static int loadpriv(dstr *d) int rc = -1; const kgops **ko; const char *e; + algswitch a; /* --- Open the private key file --- */ @@ -237,6 +365,15 @@ tymatch:; goto done_1; } + /* --- Collect the algorithms --- */ + + if ((e = algs_get(&a, &kf, k)) != 0 || + (e = algs_check(&a, g)) != 0) { + dstr_putf(d, "bad symmetric algorithm selection 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 @@ -263,12 +400,18 @@ tymatch:; 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)); + trace(T_CRYPTO, "crypto: cipher = %s", a.c->name); + trace(T_CRYPTO, "crypto: mgf = %s", a.mgf->name); + trace(T_CRYPTO, "crypto: hash = %s", a.h->name); + trace(T_CRYPTO, "crypto: mac = %s/%lu", + a.m->name, (unsigned long)a.tagsz * 8); }) }) /* --- Success! --- */ gg = g; g = 0; + algs = a; kpriv = x; x = 0; rc = 0; @@ -367,6 +510,7 @@ int km_interval(void) void km_init(const char *priv, const char *pub, const char *tag) { dstr d = DSTR_INIT; + const gchash *const *hh; kr_priv = priv; kr_pub = pub; @@ -374,6 +518,13 @@ void km_init(const char *priv, const char *pub, const char *tag) fwatch_init(&w_priv, kr_priv); fwatch_init(&w_pub, kr_pub); + for (hh = ghashtab; *hh; hh++) { + if ((*hh)->hashsz > MAXHASHSZ) { + die(EXIT_FAILURE, "INTERNAL ERROR: %s hash length %lu > MAXHASHSZ %d", + (*hh)->name, (unsigned long)(*hh)->hashsz, MAXHASHSZ); + } + } + DRESET(&d); if (loadpriv(&d)) die(EXIT_FAILURE, "%s", d.buf); @@ -401,12 +552,13 @@ int km_getpubkey(const char *tag, ge *kpub, time_t *t_exp) const char *e; group *g = 0; ge *p = 0; + algswitch a; 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); + a_warn("public key `%s' not found in keyring `%s'", tag, kr_pub); goto done; } @@ -445,6 +597,17 @@ tymatch:; goto done; } + /* --- Check the algorithms --- */ + + if ((e = algs_get(&a, kf_pub, k)) != 0) { + a_warn("public key `%s' has bad algorithm selection: %s", t.buf, e); + goto done; + } + if (!algs_samep(&a, &algs)) { + a_warn("public key `%s' specifies different algorithms", t.buf); + goto done; + } + /* --- Dump the public key --- */ IF_TRACING(T_KEYMGMT, { diff --git a/keyset.c b/keyset.c index 0a320457..8893e606 100644 --- a/keyset.c +++ b/keyset.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: keyset.c,v 1.10 2004/04/08 01:36:17 mdw Exp $ + * $Id: keyset.c,v 1.11 2004/04/18 18:08:11 mdw Exp $ * * Handling of symmetric keysets * @@ -36,7 +36,8 @@ * * For a 64-bit block cipher (e.g., Blowfish), the probability of a collision * occurring after 32 MB is less than %$2^{-21}$%, and the probability of a - * collision occurring after 64 MB is less than %$2^{-19}$%. + * collision occurring after 64 MB is less than %$2^{-19}$%. These could be + * adjusted dependent on the encryption scheme, but it's too much pain. */ #define T_EXP MIN(60) /* Expiry time for a key */ @@ -48,6 +49,8 @@ #define KEYOK(ks, now) ((ks)->sz_exp > 0 && (ks)->t_exp > now) +#define SEQSZ 4 /* Size of sequence number packet */ + /*----- Low-level packet encryption and decryption ------------------------*/ /* --- Encrypted data format --- * @@ -90,47 +93,59 @@ static int doencrypt(keyset *ks, unsigned ty, buf *b, buf *bb) { ghash *h; - gcipher *c; + gcipher *c = ks->cout; const octet *p = BCUR(b); size_t sz = BLEFT(b); octet *qmac, *qseq, *qiv, *qpk; uint32 oseq; + size_t ivsz = GC_CLASS(c)->blksz; + size_t tagsz = ks->tagsz; size_t osz, nsz; octet t[4]; int rc = 0; /* --- Allocate the required buffer space --- */ - c = ks->cout; - if (buf_ensure(bb, MACSZ + SEQSZ + IVSZ + sz)) + if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0); /* Caution! */ - qmac = BCUR(bb); qseq = qmac + MACSZ; qiv = qseq + SEQSZ; qpk = qiv + IVSZ; - BSTEP(bb, MACSZ + SEQSZ + IVSZ + sz); + qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz; + BSTEP(bb, tagsz + SEQSZ + ivsz + sz); STORE32(t, ty); - /* --- Encrypt the packet --- */ - oseq = ks->oseq++; STORE32(qseq, oseq); - rand_get(RAND_GLOBAL, qiv, IVSZ); - c->ops->setiv(c, qiv); - c->ops->encrypt(c, p, qpk, sz); IF_TRACING(T_KEYSET, { trace(T_KEYSET, "keyset: encrypting packet %lu using keyset %u", (unsigned long)oseq, ks->seq); - trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz); + trace_block(T_CRYPTO, "crypto: plaintext packet", p, sz); }) - /* --- Now compute the MAC --- */ + /* --- Encrypt the packet --- */ - h = ks->mout->ops->init(ks->mout); - h->ops->hash(h, t, sizeof(t)); - h->ops->hash(h, qseq, SEQSZ + IVSZ + sz); - memcpy(qmac, h->ops->done(h, 0), MACSZ); - h->ops->destroy(h); + if (ivsz) { + rand_get(RAND_GLOBAL, qiv, ivsz); + GC_SETIV(c, qiv); + IF_TRACING(T_KEYSET, { + trace_block(T_CRYPTO, "crypto: initialization vector", qiv, ivsz); + }) + } + GC_ENCRYPT(c, p, qpk, sz); IF_TRACING(T_KEYSET, { - trace_block(T_CRYPTO, "crypto: computed MAC", qmac, MACSZ); + trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz); }) + /* --- Now compute the MAC --- */ + + if (tagsz) { + h = GM_INIT(ks->mout); + GH_HASH(h, t, sizeof(t)); + GH_HASH(h, qseq, SEQSZ + ivsz + sz); + memcpy(qmac, GH_DONE(h, 0), tagsz); + GH_DESTROY(h); + IF_TRACING(T_KEYSET, { + trace_block(T_CRYPTO, "crypto: computed MAC", qmac, tagsz); + }) + } + /* --- Deduct the packet size from the key's data life --- */ osz = ks->sz_exp; @@ -173,45 +188,57 @@ static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) octet *q = BCUR(bb); ghash *h; gcipher *c = ks->cin; - size_t ivsz = c->ops->c->blksz; + size_t ivsz = GC_CLASS(c)->blksz; + size_t tagsz = ks->tagsz; octet *mac; int eq; octet t[4]; /* --- Break up the packet into its components --- */ - if (psz < ivsz + 4) { + if (psz < ivsz + SEQSZ + tagsz) { T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); ) return (-1); } - sz = psz - IVSZ - SEQSZ - MACSZ; - pmac = BCUR(b); pseq = pmac + MACSZ; piv = pseq + SEQSZ; ppk = piv + IVSZ; + sz = psz - ivsz - SEQSZ - tagsz; + pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz; STORE32(t, ty); - /* --- Verify the MAC on the packet --- */ - - h = ks->min->ops->init(ks->min); - h->ops->hash(h, t, sizeof(t)); - h->ops->hash(h, pseq, SEQSZ + IVSZ + sz); - mac = h->ops->done(h, 0); - eq = !memcmp(mac, pmac, MACSZ); IF_TRACING(T_KEYSET, { trace(T_KEYSET, "keyset: decrypting using keyset %u", ks->seq); - trace_block(T_CRYPTO, "crypto: computed MAC", mac, MACSZ); + trace_block(T_CRYPTO, "crypto: ciphertext packet", ppk, sz); }) - h->ops->destroy(h); - if (!eq) { + + /* --- Verify the MAC on the packet --- */ + + if (tagsz) { + h = GM_INIT(ks->min); + GH_HASH(h, t, sizeof(t)); + GH_HASH(h, pseq, SEQSZ + ivsz + sz); + mac = GH_DONE(h, 0); + eq = !memcmp(mac, pmac, tagsz); IF_TRACING(T_KEYSET, { - trace(T_KEYSET, "keyset: incorrect MAC: decryption failed"); - trace_block(T_CRYPTO, "crypto: expected MAC", pmac, MACSZ); + trace_block(T_CRYPTO, "crypto: computed MAC", mac, tagsz); }) - return (-1); + GH_DESTROY(h); + if (!eq) { + IF_TRACING(T_KEYSET, { + trace(T_KEYSET, "keyset: incorrect MAC: decryption failed"); + trace_block(T_CRYPTO, "crypto: expected MAC", pmac, tagsz); + }) + return (-1); + } } /* --- Decrypt the packet --- */ - c->ops->setiv(c, piv); - c->ops->decrypt(c, ppk, q, sz); + if (ivsz) { + GC_SETIV(c, piv); + IF_TRACING(T_KEYSET, { + trace_block(T_CRYPTO, "crypto: initialization vector", piv, ivsz); + }) + } + GC_DECRYPT(c, ppk, q, sz); if (seq) *seq = LOAD32(pseq); IF_TRACING(T_KEYSET, { @@ -278,10 +305,10 @@ void ks_drop(keyset *ks) { if (--ks->ref) return; - ks->cin->ops->destroy(ks->cin); - ks->cout->ops->destroy(ks->cout); - ks->min->ops->destroy(ks->min); - ks->mout->ops->destroy(ks->mout); + GC_DESTROY(ks->cin); + GC_DESTROY(ks->cout); + GM_DESTROY(ks->min); + GM_DESTROY(ks->mout); DESTROY(ks); } @@ -310,8 +337,8 @@ void ks_drop(keyset *ks) keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p) { - HASH_CTX h; - octet buf[HASHSZ]; + ghash *h; + const octet *hh; keyset *ks = CREATE(keyset); time_t now = time(0); const octet *pp = k; @@ -324,39 +351,47 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p) * This is done with macros, because it's quite tedious. */ -#define MINE HASH(&h, pp, x) -#define YOURS HASH(&h, pp + x, y - x) -#define OURS HASH(&h, pp + y, z - y) - -#define IN MINE; YOURS; OURS -#define OUT YOURS; MINE; OURS -#define STR_IN "incoming" -#define STR_OUT "outgoing" - -#define GETHASH(str, dir) do { \ - HASH_INIT(&h); \ - HASH_STRING(&h, "tripe-" str); \ - dir; \ - HASH_DONE(&h, buf); \ +#define MINE GH_HASH(h, pp, x) +#define YOURS GH_HASH(h, pp + x, y - x) +#define OURS GH_HASH(h, pp + y, z - y) + +#define HASH_in MINE; YOURS; OURS +#define HASH_out YOURS; MINE; OURS +#define INIT_c(k) GC_INIT(algs.c, (k), algs.cksz) +#define INIT_m(k) GM_KEY(algs.m, (k), algs.mksz) +#define STR_c "encryption" +#define STR_m "integrity" +#define STR_in "incoming" +#define STR_out "outgoing" + +#define SETKEY(a, dir) do { \ + h = GH_INIT(algs.h); \ + HASH_STRING(h, "tripe-" STR_##a); \ + HASH_##dir; \ + hh = GH_DONE(h, 0); \ IF_TRACING(T_KEYSET, { \ - trace_block(T_CRYPTO, "crypto: " STR_##dir " key " str, \ - buf, sizeof(buf)); \ + trace_block(T_CRYPTO, "crypto: " STR_##dir " key " STR_##a, \ + hh, algs.a##ksz); \ }) \ + ks->a##dir = INIT_##a(hh); \ + GH_DESTROY(h); \ } while (0) - GETHASH("encryption", IN); ks->cin = CIPHER->init(buf, sizeof(buf)); - GETHASH("integrity", IN); ks->min = MAC->key(buf, sizeof(buf)); - GETHASH("encryption", OUT); ks->cout = CIPHER->init(buf, sizeof(buf)); - GETHASH("integrity", OUT); ks->mout = MAC->key(buf, sizeof(buf)); + SETKEY(c, in); SETKEY(c, out); + SETKEY(m, in); SETKEY(m, out); #undef MINE #undef YOURS #undef OURS -#undef IN -#undef OUT -#undef STR_IN -#undef STR_OUT -#undef GETHASH +#undef STR_c +#undef STR_m +#undef STR_in +#undef STR_out +#undef INIT_c +#undef INIT_m +#undef HASH_in +#undef HASH_out +#undef SETKEY T( ks->seq = seq++; ) ks->ref = 1; @@ -367,7 +402,7 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p) ks->next = 0; ks->p = p; ks->f = KSF_LISTEN; - BURN(buf); + ks->tagsz = algs.tagsz; return (ks); } diff --git a/tripe.c b/tripe.c index 9680dd4a..92a6a62d 100644 --- a/tripe.c +++ b/tripe.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: tripe.c,v 1.13 2004/04/08 01:36:17 mdw Exp $ + * $Id: tripe.c,v 1.14 2004/04/18 18:08:11 mdw Exp $ * * Main program * @@ -55,7 +55,7 @@ void interval(struct timeval *tv, void *v) { struct timeval tvv; T( trace(T_PEER, "peer: interval timer"); ) - rand_seed(RAND_GLOBAL, HASHSZ); + rand_seed(RAND_GLOBAL, MAXHASHSZ); p_interval(); tvv = *tv; tvv.tv_sec += T_INTERVAL; @@ -269,7 +269,7 @@ int main(int argc, char *argv[]) sel_init(&sel); sig_init(&sel); rand_noisesrc(RAND_GLOBAL, &noise_source); - rand_seed(RAND_GLOBAL, RMD160_HASHSZ); + rand_seed(RAND_GLOBAL, MAXHASHSZ); signal(SIGPIPE, SIG_IGN); tun_init(); p_init(baddr, port); diff --git a/tripe.h b/tripe.h index 5138d110..7de033d3 100644 --- a/tripe.h +++ b/tripe.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: tripe.h,v 1.19 2004/04/08 01:36:17 mdw Exp $ + * $Id: tripe.h,v 1.20 2004/04/18 18:08:11 mdw Exp $ * * Main header file for TrIPE * @@ -137,29 +137,21 @@ /*----- Cipher selections -------------------------------------------------*/ -#include -#include -#include -#include -#include +typedef struct algswitch { + const gccipher *c; /* Symmetric encryption scheme */ + const gccipher *mgf; /* Mask-generation function */ + const gchash *h; /* Hash function */ + const gcmac *m; /* Message authentication code */ + size_t hashsz; /* Hash output size */ + size_t tagsz; /* Length to truncate MAC tags */ + size_t cksz, mksz; /* Key lengths for @c@ and @m@ */ +} algswitch; -#define CIPHER (&blowfish_cbc) -#define MAC (&rmd160_hmac) +extern algswitch algs; -#define HASH_CTX rmd160_ctx -#define HASH_INIT rmd160_init -#define HASH rmd160_hash -#define HASH_STRING(c, s) HASH((c), s, sizeof(s)) -#define HASH_DONE rmd160_done -#define HASHSZ RMD160_HASHSZ +#define MAXHASHSZ 64 /* Largest possible hash size */ -#define MGF_CTX blowfish_counterctx -#define MGF_INIT blowfish_counterinit -#define MGF_CRYPT blowfish_counterencrypt - -#define SEQSZ 4 -#define IVSZ BLOWFISH_BLKSZ -#define MACSZ 10 +#define HASH_STRING(h, s) GH_HASH((h), (s), sizeof(s)) /*----- Data structures ---------------------------------------------------*/ @@ -195,6 +187,7 @@ typedef struct keyset { T( unsigned seq; ) /* Sequence number for tracing */ unsigned f; /* Various useful flags */ gcipher *cin, *cout; /* Keyset ciphers for encryption */ + size_t tagsz; /* Length to truncate MAC tags */ gmac *min, *mout; /* Keyset MACs for integrity */ uint32 oseq; /* Outbound sequence number */ uint32 iseq, iwin; /* Inbound sequence number */ @@ -224,12 +217,12 @@ typedef struct kxchal { keyset *ks; /* Pointer to temporary keyset */ unsigned f; /* Various useful flags */ sel_timer t; /* Response timer for challenge */ - octet hc[HASHSZ]; /* Hash of his challenge */ + octet hc[MAXHASHSZ]; /* Hash of his challenge */ mp *ck; /* The check value */ - octet hswrq_in[HASHSZ]; /* Inbound switch request message */ - octet hswok_in[HASHSZ]; /* Inbound switch confirmation */ - octet hswrq_out[HASHSZ]; /* Outbound switch request message */ - octet hswok_out[HASHSZ]; /* Outbound switch confirmation */ + octet hswrq_in[MAXHASHSZ]; /* Inbound switch request message */ + octet hswok_in[MAXHASHSZ]; /* Inbound switch confirmation */ + octet hswrq_out[MAXHASHSZ]; /* Outbound switch request message */ + octet hswok_out[MAXHASHSZ]; /* Outbound switch confirmation */ } kxchal; typedef struct keyexch { @@ -245,7 +238,7 @@ typedef struct keyexch { 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 */ + octet hc[MAXHASHSZ]; /* Hash of my challenge */ kxchal *r[KX_NCHAL]; /* Array of challenges */ } keyexch; -- [mdw]