]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - sshdh.c
first pass
[PuTTY.git] / sshdh.c
diff --git a/sshdh.c b/sshdh.c
index 48f277a7cf31eaf02a2a34f5a6f8ebce7b22d5ee..f254bc1de7c3a255f03c53ced7bc9fb5acb31b0c 100644 (file)
--- a/sshdh.c
+++ b/sshdh.c
@@ -1,3 +1,7 @@
+/*
+ * Diffie-Hellman implementation for PuTTY.
+ */
+
 #include "ssh.h"
 
 /*
@@ -46,9 +50,18 @@ static const unsigned char P14[] = {
  */
 static const unsigned char G[] = { 2 };
 
+struct dh_extra {
+    const unsigned char *pdata, *gdata; /* NULL means group exchange */
+    int plen, glen;
+};
+
+static const struct dh_extra extra_group1 = {
+    P1, G, lenof(P1), lenof(G),
+};
+
 static const struct ssh_kex ssh_diffiehellman_group1_sha1 = {
     "diffie-hellman-group1-sha1", "group1",
-    P1, G, lenof(P1), lenof(G), &ssh_sha1
+    KEXTYPE_DH, &ssh_sha1, &extra_group1,
 };
 
 static const struct ssh_kex *const group1_list[] = {
@@ -60,9 +73,13 @@ const struct ssh_kexes ssh_diffiehellman_group1 = {
     group1_list
 };
 
+static const struct dh_extra extra_group14 = {
+    P14, G, lenof(P14), lenof(G),
+};
+
 static const struct ssh_kex ssh_diffiehellman_group14_sha1 = {
     "diffie-hellman-group14-sha1", "group14",
-    P14, G, lenof(P14), lenof(G), &ssh_sha1
+    KEXTYPE_DH, &ssh_sha1, &extra_group14,
 };
 
 static const struct ssh_kex *const group14_list[] = {
@@ -74,14 +91,18 @@ const struct ssh_kexes ssh_diffiehellman_group14 = {
     group14_list
 };
 
+static const struct dh_extra extra_gex = {
+    NULL, NULL, 0, 0,
+};
+
 static const struct ssh_kex ssh_diffiehellman_gex_sha256 = {
     "diffie-hellman-group-exchange-sha256", NULL,
-    NULL, NULL, 0, 0, &ssh_sha256
+    KEXTYPE_DH, &ssh_sha256, &extra_gex,
 };
 
 static const struct ssh_kex ssh_diffiehellman_gex_sha1 = {
     "diffie-hellman-group-exchange-sha1", NULL,
-    NULL, NULL, 0, 0, &ssh_sha1
+    KEXTYPE_DH, &ssh_sha1, &extra_gex,
 };
 
 static const struct ssh_kex *const gex_list[] = {
@@ -111,14 +132,21 @@ static void dh_init(struct dh_ctx *ctx)
     ctx->x = ctx->e = NULL;
 }
 
+int dh_is_gex(const struct ssh_kex *kex)
+{
+    const struct dh_extra *extra = (const struct dh_extra *)kex->extra;
+    return extra->pdata == NULL;
+}
+
 /*
  * Initialise DH for a standard group.
  */
 void *dh_setup_group(const struct ssh_kex *kex)
 {
+    const struct dh_extra *extra = (const struct dh_extra *)kex->extra;
     struct dh_ctx *ctx = snew(struct dh_ctx);
-    ctx->p = bignum_from_bytes(kex->pdata, kex->plen);
-    ctx->g = bignum_from_bytes(kex->gdata, kex->glen);
+    ctx->p = bignum_from_bytes(extra->pdata, extra->plen);
+    ctx->g = bignum_from_bytes(extra->gdata, extra->glen);
     dh_init(ctx);
     return ctx;
 }
@@ -214,6 +242,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.
  */