From 174476813f0ed94337aecc3e2d13a202a1dc2fa8 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 5 Feb 2015 19:39:17 +0000 Subject: [PATCH] Enforce acceptable range for Diffie-Hellman server value. Florent Daigniere of Matta points out that RFC 4253 actually _requires_ us to refuse to accept out-of-range values, though it isn't completely clear to me why this should be a MUST on the receiving end. Matta considers this to be a security vulnerability, on the grounds that if a server should accidentally send an obviously useless value such as 1 then we will fail to reject it and agree a key that an eavesdropper could also figure out. Their id for this vulnerability is MATTA-2015-002. --- ssh.c | 7 +++++++ ssh.h | 1 + sshdh.c | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/ssh.c b/ssh.c index a7f5882f..6009e06f 100644 --- a/ssh.c +++ b/ssh.c @@ -6645,6 +6645,13 @@ static void do_ssh2_transport(Ssh ssh, void *vin, int inlen, } ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); + { + const char *err = dh_validate_f(ssh->kex_ctx, s->f); + if (err) { + bombout(("key exchange reply failed validation: %s", err)); + crStopV; + } + } s->K = dh_find_K(ssh->kex_ctx, s->f); /* We assume everything from now on will be quick, and it might diff --git a/ssh.h b/ssh.h index 89f772d6..52500ac8 100644 --- a/ssh.h +++ b/ssh.h @@ -536,6 +536,7 @@ void *dh_setup_group(const struct ssh_kex *kex); void *dh_setup_gex(Bignum pval, Bignum gval); void dh_cleanup(void *); Bignum dh_create_e(void *, int nbits); +const char *dh_validate_f(void *handle, Bignum f); Bignum dh_find_K(void *, Bignum f); int loadrsakey(const Filename *filename, struct RSAKey *key, diff --git a/sshdh.c b/sshdh.c index c733b61f..8f8ab2d2 100644 --- a/sshdh.c +++ b/sshdh.c @@ -218,6 +218,29 @@ Bignum dh_create_e(void *handle, int nbits) return ctx->e; } +/* + * DH stage 2-epsilon: given a number f, validate it to ensure it's in + * range. (RFC 4253 section 8: "Values of 'e' or 'f' that are not in + * the range [1, p-1] MUST NOT be sent or accepted by either side." + * Also, we rule out 1 and p-1 too, since that's easy to do and since + * they lead to obviously weak keys that even a passive eavesdropper + * can figure out.) + */ +const char *dh_validate_f(void *handle, Bignum f) +{ + struct dh_ctx *ctx = (struct dh_ctx *)handle; + if (bignum_cmp(f, One) <= 0) { + return "f value received is too small"; + } else { + Bignum pm1 = bigsub(ctx->p, One); + int cmp = bignum_cmp(f, pm1); + freebn(pm1); + if (cmp >= 0) + return "f value received is too large"; + } + return NULL; +} + /* * DH stage 2: given a number f, compute K = f^x mod p. */