Chris Weyl 8d25ddb
commit 1aba38cd7d2658146675ce1737e5090f879f3068
Chris Weyl 8d25ddb
Author: Peter Stuge <peter@stuge.se>
Chris Weyl 8d25ddb
Date:   Sun Dec 6 07:20:58 2009 +0100
Chris Weyl 8d25ddb
Chris Weyl 8d25ddb
    Fix padding in ssh-dss signature blob encoding
Chris Weyl 8d25ddb
    
Chris Weyl 8d25ddb
    DSA signatures consist of two 160-bit integers called r and s. In ssh-dss
Chris Weyl 8d25ddb
    signature blobs r and s are stored directly after each other in binary
Chris Weyl 8d25ddb
    representation, making up a 320-bit (40 byte) string. (See RFC4253 p14.)
Chris Weyl 8d25ddb
    
Chris Weyl 8d25ddb
    The crypto wrappers in libssh2 would either pack r and s incorrectly, or
Chris Weyl 8d25ddb
    fail, when at least one integer was small enough to be stored in 19 bytes
Chris Weyl 8d25ddb
    or less.
Chris Weyl 8d25ddb
    
Chris Weyl 8d25ddb
    The patch ensures that r and s are always stored as two 160 bit numbers.
Chris Weyl 8d25ddb
Chris Weyl 8d25ddb
diff --git a/src/libgcrypt.c b/src/libgcrypt.c
Chris Weyl 8d25ddb
index ba00284..b06be42 100644
Chris Weyl 8d25ddb
--- a/src/libgcrypt.c
Chris Weyl 8d25ddb
+++ b/src/libgcrypt.c
Chris Weyl 8d25ddb
@@ -424,6 +424,8 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
Chris Weyl 8d25ddb
         return -1;
Chris Weyl 8d25ddb
     }
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
+    memset(sig, 0, 40);
Chris Weyl 8d25ddb
+
Chris Weyl 8d25ddb
 /* Extract R. */
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     data = gcry_sexp_find_token(sig_sexp, "r", 0);
Chris Weyl 8d25ddb
@@ -433,22 +435,12 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
Chris Weyl 8d25ddb
     }
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     tmp = gcry_sexp_nth_data(data, 1, &size);
Chris Weyl 8d25ddb
-    if (!tmp) {
Chris Weyl 8d25ddb
-        ret = -1;
Chris Weyl 8d25ddb
-        goto out;
Chris Weyl 8d25ddb
-    }
Chris Weyl 8d25ddb
-
Chris Weyl 8d25ddb
-    if (tmp[0] == '\0') {
Chris Weyl 8d25ddb
-        tmp++;
Chris Weyl 8d25ddb
-        size--;
Chris Weyl 8d25ddb
-    }
Chris Weyl 8d25ddb
-
Chris Weyl 8d25ddb
-    if (size != 20) {
Chris Weyl 8d25ddb
+    if (!tmp || size < 1 || size > 20) {
Chris Weyl 8d25ddb
         ret = -1;
Chris Weyl 8d25ddb
         goto out;
Chris Weyl 8d25ddb
     }
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
-    memcpy(sig, tmp, 20);
Chris Weyl 8d25ddb
+    memcpy(sig + (20 - size), tmp, size);
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     gcry_sexp_release(data);
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
@@ -461,22 +453,12 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
Chris Weyl 8d25ddb
     }
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     tmp = gcry_sexp_nth_data(data, 1, &size);
Chris Weyl 8d25ddb
-    if (!tmp) {
Chris Weyl 8d25ddb
-        ret = -1;
Chris Weyl 8d25ddb
-        goto out;
Chris Weyl 8d25ddb
-    }
Chris Weyl 8d25ddb
-
Chris Weyl 8d25ddb
-    if (tmp[0] == '\0') {
Chris Weyl 8d25ddb
-        tmp++;
Chris Weyl 8d25ddb
-        size--;
Chris Weyl 8d25ddb
-    }
Chris Weyl 8d25ddb
-
Chris Weyl 8d25ddb
-    if (size != 20) {
Chris Weyl 8d25ddb
+    if (!tmp || size < 1 || size > 20) {
Chris Weyl 8d25ddb
         ret = -1;
Chris Weyl 8d25ddb
         goto out;
Chris Weyl 8d25ddb
     }
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
-    memcpy(sig + 20, tmp, 20);
Chris Weyl 8d25ddb
+    memcpy(sig + 20 + (20 - size), tmp, size);
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     ret = 0;
Chris Weyl 8d25ddb
   out:
Chris Weyl 8d25ddb
diff --git a/src/openssl.c b/src/openssl.c
Chris Weyl 8d25ddb
index 250ea63..000c9ec 100644
Chris Weyl 8d25ddb
--- a/src/openssl.c
Chris Weyl 8d25ddb
+++ b/src/openssl.c
Chris Weyl 8d25ddb
@@ -420,7 +420,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
Chris Weyl 8d25ddb
                        unsigned long hash_len, unsigned char *signature)
Chris Weyl 8d25ddb
 {
Chris Weyl 8d25ddb
     DSA_SIG *sig;
Chris Weyl 8d25ddb
-    int r_len, s_len, rs_pad;
Chris Weyl 8d25ddb
+    int r_len, s_len;
Chris Weyl 8d25ddb
     (void) hash_len;
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
Chris Weyl 8d25ddb
@@ -429,15 +429,20 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
Chris Weyl 8d25ddb
     }
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     r_len = BN_num_bytes(sig->r);
Chris Weyl 8d25ddb
+    if (r_len < 1 || r_len > 20) {
Chris Weyl 8d25ddb
+        DSA_SIG_free(sig);
Chris Weyl 8d25ddb
+        return -1;
Chris Weyl 8d25ddb
+    }
Chris Weyl 8d25ddb
     s_len = BN_num_bytes(sig->s);
Chris Weyl 8d25ddb
-    rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
Chris Weyl 8d25ddb
-    if (rs_pad < 0) {
Chris Weyl 8d25ddb
+    if (s_len < 1 || s_len > 20) {
Chris Weyl 8d25ddb
         DSA_SIG_free(sig);
Chris Weyl 8d25ddb
         return -1;
Chris Weyl 8d25ddb
     }
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
-    BN_bn2bin(sig->r, signature + rs_pad);
Chris Weyl 8d25ddb
-    BN_bn2bin(sig->s, signature + rs_pad + r_len);
Chris Weyl 8d25ddb
+    memset(signature, 0, 40);
Chris Weyl 8d25ddb
+
Chris Weyl 8d25ddb
+    BN_bn2bin(sig->r, signature + (20 - r_len));
Chris Weyl 8d25ddb
+    BN_bn2bin(sig->s, signature + 20 + (20 - s_len));
Chris Weyl 8d25ddb
 
Chris Weyl 8d25ddb
     DSA_SIG_free(sig);
Chris Weyl 8d25ddb