Avoid trying to take the modular inverse of zero in response to a
[u/mdw/putty] / sshdss.c
index 8c9f93e..3ea3695 100644 (file)
--- a/sshdss.c
+++ b/sshdss.c
@@ -82,6 +82,8 @@ static Bignum get160(char **data, int *datalen)
     return b;
 }
 
+static void dss_freekey(void *key);    /* forward reference */
+
 static void *dss_newkey(char *data, int len)
 {
     char *p;
@@ -89,8 +91,6 @@ static void *dss_newkey(char *data, int len)
     struct dss_key *dss;
 
     dss = snew(struct dss_key);
-    if (!dss)
-       return NULL;
     getstring(&data, &len, &p, &slen);
 
 #ifdef DEBUG_DSS
@@ -113,6 +113,13 @@ static void *dss_newkey(char *data, int len)
     dss->y = getmp(&data, &len);
     dss->x = NULL;
 
+    if (!dss->p || !dss->q || !dss->g || !dss->y ||
+        !bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) {
+        /* Invalid key. */
+        dss_freekey(dss);
+        return NULL;
+    }
+
     return dss;
 }
 
@@ -261,8 +268,19 @@ static int dss_verifysig(void *key, char *sig, int siglen,
     }
     r = get160(&sig, &siglen);
     s = get160(&sig, &siglen);
-    if (!r || !s)
+    if (!r || !s) {
+        if (r)
+            freebn(r);
+        if (s)
+            freebn(s);
        return 0;
+    }
+
+    if (!bignum_cmp(s, Zero)) {
+        freebn(r);
+        freebn(s);
+        return 0;
+    }
 
     /*
      * Step 1. w <- s^-1 mod q.
@@ -391,7 +409,13 @@ static void *dss_createkey(unsigned char *pub_blob, int pub_len,
     Bignum ytest;
 
     dss = dss_newkey((char *) pub_blob, pub_len);
+    if (!dss)
+        return NULL;
     dss->x = getmp(&pb, &priv_len);
+    if (!dss->x) {
+        dss_freekey(dss);
+        return NULL;
+    }
 
     /*
      * Check the obsolete hash in the old DSS key format.
@@ -430,8 +454,6 @@ static void *dss_openssh_createkey(unsigned char **blob, int *len)
     struct dss_key *dss;
 
     dss = snew(struct dss_key);
-    if (!dss)
-       return NULL;
 
     dss->p = getmp(b, len);
     dss->q = getmp(b, len);
@@ -439,14 +461,11 @@ static void *dss_openssh_createkey(unsigned char **blob, int *len)
     dss->y = getmp(b, len);
     dss->x = getmp(b, len);
 
-    if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x) {
-       freebn(dss->p);
-       freebn(dss->q);
-       freebn(dss->g);
-       freebn(dss->y);
-       freebn(dss->x);
-       sfree(dss);
-       return NULL;
+    if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x ||
+        !bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) {
+        /* Invalid key. */
+        dss_freekey(dss);
+        return NULL;
     }
 
     return dss;
@@ -486,6 +505,8 @@ static int dss_pubkey_bits(void *blob, int len)
     int ret;
 
     dss = dss_newkey((char *) blob, len);
+    if (!dss)
+        return -1;
     ret = bignum_bitcount(dss->p);
     dss_freekey(dss);
 
@@ -614,6 +635,7 @@ static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen)
     s = modmul(kinv, hxr, dss->q);     /* s = k^-1 * (hash + x*r) mod q */
     freebn(hxr);
     freebn(kinv);
+    freebn(k);
     freebn(hash);
 
     /*