/* -*-c-*-
*
- * $Id: keyexch.c,v 1.13 2004/04/18 18:08:11 mdw Exp $
+ * $Id$
*
* Key exchange protocol
*
* 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))$%
+ * %$\cookie{kx-switch-rq}, c_A, c_B, E_K(r_B^\alpha, w_A))$%
* Reply received: here's my reply. Committed; send data; move to
* @KXS_SWITCH@.
*
#define T_VALID MIN(2) /* Challenge validity period */
#define T_RETRY SEC(10) /* Challenge retransmit interval */
-#define ISVALID(kx, now) ((now) < (kx)->t_valid)
+#define VALIDP(kx, now) ((now) < (kx)->t_valid)
+
+/*----- Static tables -----------------------------------------------------*/
+
+static const char *const pkname[] = {
+ "pre-challenge", "cookie", "challenge",
+ "reply", "switch-rq", "switch-ok"
+};
/*----- Various utilities -------------------------------------------------*/
keyexch *kx = v;
kx->f &= ~KXF_TIMER;
T( trace(T_KEYEXCH, "keyexch: timer has popped"); )
- kx_start(kx);
+ kx_start(kx, 0);
}
/* --- @settimer@ --- *
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));
+ a_warn("KX %s bad-expected-reply-log", p_name(kx->p));
IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
trace(T_CRYPTO, "crypto: computed challenge = %s", gestr(gg, y));
}))
/* --- Ensure that we're in a sensible state --- */
if (kx->s != KXS_CHAL) {
- a_warn("unexpected challenge from `%s'", p_name(kx->p));
+ a_warn("KX %s unexpected %s", p_name(kx->p), pkname[msg]);
goto bad;
}
(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));
+ a_warn("KX %s invalid %s", p_name(kx->p), pkname[msg]);
goto bad;
}
if (!hc && kx->nr >= KX_THRESH) {
T( trace(T_KEYEXCH, "keyexch: too many challenges -- sending cookie"); )
+ a_warn("KX %s sending-cookie", p_name(kx->p));
b = p_txstart(kx->p, MSG_KEYEXCH | KX_COOKIE);
G_TOBUF(gg, b, kx->c);
h = GH_INIT(algs.h);
/* --- Discard a packet with an invalid cookie --- */
if (hc && memcmp(hc, kx->hc, algs.hashsz) != 0) {
- a_warn("incorrect cookie from `%s'", p_name(kx->p));
+ a_warn("KX %s incorrect cookie", p_name(kx->p));
goto bad;
}
if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck));
}))
if (memcmp(hc_out, kx->hc, algs.hashsz) != 0) {
- a_warn("incorrect cookie from `%s'", p_name(kx->p));
+ a_warn("KX %s incorrect cookie", p_name(kx->p));
goto bad;
}
if ((kxc = kxc_byhc(kx, hc_in)) == 0) {
- a_warn("received reply for unknown challenge from `%s'", p_name(kx->p));
+ a_warn("KX %s unknown-challenge", p_name(kx->p));
goto bad;
}
if (!kxc->r) {
if (!ck) {
- a_warn("unexpected switch request from `%s'", p_name(kx->p));
+ a_warn("KX %s unexpected switch-rq", p_name(kx->p));
goto bad;
}
if ((r = getreply(kx, kxc->c, ck)) == 0)
buf_init(&bb, buf_o, sizeof(buf_o));
if (ks_decrypt(kxc->ks, ty, b, &bb)) {
- a_warn("failed to decrypt reply from `%s'", p_name(kx->p));
+ a_warn("KX %s decrypt-failed reply", p_name(kx->p));
goto bad;
}
buf_init(b, BBASE(&bb), BLEN(&bb));
r = G_CREATE(gg);
if (G_FROMBUF(gg, b, r)) {
- a_warn("invalid reply packet from `%s'", p_name(kx->p));
+ a_warn("KX %s invalid reply", p_name(kx->p));
goto bad;
}
IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
trace(T_CRYPTO, "crypto: reply = %s", gestr(gg, r));
}))
if (!G_EQ(gg, r, kx->rx)) {
- a_warn("incorrect reply from `%s'", p_name(kx->p));
+ a_warn("KX %s incorrect reply", p_name(kx->p));
goto bad;
}
kxchal *kxc;
if (kx->s != KXS_CHAL && kx->s != KXS_COMMIT) {
- a_warn("unexpected reply from `%s'", p_name(kx->p));
+ a_warn("KX %s unexpected-reply", p_name(kx->p));
goto bad;
}
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));
+ a_warn("KX %s invalid reply", p_name(kx->p));
goto bad;
}
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));
+ a_warn("KX %s invalid reply", p_name(kx->p));
goto bad;
}
if (kx->s == KXS_CHAL) {
return (-1);
}
+/* --- @kxfinish@ --- *
+ *
+ * Arguments: @keyexch *kx@ = pointer to key exchange block
+ *
+ * Returns: ---
+ *
+ * Use: Sets everything up following a successful key exchange.
+ */
+
+static void kxfinish(keyexch *kx)
+{
+ kxchal *kxc = kx->r[0];
+ ks_activate(kxc->ks);
+ settimer(kx, ks_tregen(kxc->ks));
+ kx->s = KXS_SWITCH;
+ a_notify("KXDONE %s", p_name(kx->p));
+ p_stats(kx->p)->t_kx = time(0);
+}
+
/* --- @doswitch@ --- *
*
* Arguments: @keyexch *kx@ = pointer to key exchange block
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));
+ a_warn("KX %s invalid switch-rq", 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, algs.hashsz)) == 0 || BLEFT(b)) {
- a_warn("invalid switch request from `%s'", p_name(kx->p));
+ a_warn("KX %s invalid switch-rq", p_name(kx->p));
goto bad;
}
IF_TRACING(T_KEYEXCH, {
trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, algs.hashsz);
})
if (memcmp(hswrq, kxc->hswrq_in, algs.hashsz) != 0) {
- a_warn("incorrect switch request hash from `%s'", p_name(kx->p));
+ a_warn("KX %s incorrect switch-rq", p_name(kx->p));
goto bad;
}
switch (kx->s) {
case KXS_CHAL:
commit(kx, kxc);
case KXS_COMMIT:
- ks_activate(kxc->ks);
- settimer(kx, ks_tregen(kxc->ks));
- kx->s = KXS_SWITCH;
+ kxfinish(kx);
break;
}
resend(kx);
buf bb;
if (kx->s < KXS_COMMIT) {
- a_warn("unexpected switch confirmation from `%s'", p_name(kx->p));
+ a_warn("KX %s unexpected switch-ok", p_name(kx->p));
goto bad;
}
kxc = kx->r[0];
buf_init(&bb, buf_o, sizeof(buf_o));
if (ks_decrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, b, &bb)) {
- a_warn("failed to decrypt switch confirmation from `%s'", p_name(kx->p));
+ a_warn("KX %s decrypt-failed switch-ok", p_name(kx->p));
goto bad;
}
buf_init(b, BBASE(&bb), BLEN(&bb));
if ((hswok = buf_get(b, algs.hashsz)) == 0 || BLEFT(b)) {
- a_warn("invalid switch confirmation from `%s'", p_name(kx->p));
+ a_warn("KX %s invalid switch-ok", p_name(kx->p));
goto bad;
}
IF_TRACING(T_KEYEXCH, {
hswok, algs.hashsz);
})
if (memcmp(hswok, kxc->hswok_in, algs.hashsz) != 0) {
- a_warn("incorrect switch confirmation hash from `%s'", p_name(kx->p));
+ a_warn("KX %s incorrect switch-ok", p_name(kx->p));
goto bad;
}
- if (kx->s < KXS_SWITCH) {
- ks_activate(kxc->ks);
- settimer(kx, ks_tregen(kxc->ks));
- kx->s = KXS_SWITCH;
- }
+ if (kx->s < KXS_SWITCH)
+ kxfinish(kx);
return (0);
bad:
now = time(0);
if (KEY_EXPIRED(now, kx->texp_kpub)) {
stop(kx);
- a_warn("public key for `%s' has expired", p_name(kx->p));
+ a_warn("KX %s public-key-expired", p_name(kx->p));
G_COPY(gg, kx->kpub, gg->i);
kx->f &= ~KXF_PUBKEY;
return (-1);
/* --- @kx_start@ --- *
*
* Arguments: @keyexch *kx@ = pointer to key exchange context
+ * @int forcep@ = nonzero to ignore the quiet timer
*
* Returns: ---
*
* this); if no exchange is in progress, one is commenced.
*/
-void kx_start(keyexch *kx)
+void kx_start(keyexch *kx, int forcep)
{
time_t now = time(0);
if (checkpub(kx))
return;
- if (!ISVALID(kx, now)) {
+ if (forcep || !VALIDP(kx, now)) {
stop(kx);
start(kx, now);
+ a_notify("KXSTART %s", p_name(kx->p));
}
resend(kx);
}
size_t sz = BSZ(b);
int rc;
-#ifndef NTRACE
- static const char *const pkname[] = {
- "prechallenge", "cookie", "challenge",
- "reply", "switch request", "switch confirmation"
- };
-#endif
-
if (checkpub(kx))
return;
- if (!ISVALID(kx, now)) {
+ if (!VALIDP(kx, now)) {
stop(kx);
start(kx, now);
}
rc = doswitchok(kx, b);
break;
default:
- a_warn("unexpected key exchange message type %u from `%p'",
- p_name(kx->p));
+ a_warn("KX %s unknown-message 0x%02x", p_name(kx->p), msg);
rc = -1;
break;
}
kx->f = KXF_DEAD | KXF_PUBKEY;
start(kx, time(0));
resend(kx);
+ /* Don't notify here: the ADD message hasn't gone out yet. */
return (0);
}