]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Fix potential segfaults in reading OpenSSH's ASN.1 key format.
authorSimon Tatham <anakin@pobox.com>
Thu, 25 Feb 2016 20:26:33 +0000 (20:26 +0000)
committerSimon Tatham <anakin@pobox.com>
Mon, 29 Feb 2016 19:59:32 +0000 (19:59 +0000)
The length coming back from ber_read_id_len might have overflowed, so
treat it as potentially negative. Also, while I'm here, accumulate it
inside ber_read_id_len as an unsigned, so as to avoid undefined
behaviour on integer overflow, and toint() it before return.

Thanks to Hanno Böck for spotting this, with the aid of AFL.

(cherry picked from commit 5b7833cd474a24ec098654dcba8cb9509f3bf2c1)

Conflicts:
import.c

(cherry-picker's note: resolving the conflict involved removing an
entire section of the original commit which fixed ECDSA code not
present on this branch)

import.c

index 466326f69da3a0e5586a0705cb9f0b2752457a8a..4f3ed1fab00308ece7a40c467c4a8010d05e300b 100644 (file)
--- a/import.c
+++ b/import.c
@@ -176,14 +176,16 @@ static int ber_read_id_len(void *source, int sourcelen,
        return -1;
 
     if (*p & 0x80) {
+        unsigned len;
        int n = *p & 0x7F;
        p++, sourcelen--;
        if (sourcelen < n)
            return -1;
-       *length = 0;
+       len = 0;
        while (n--)
-           *length = (*length << 8) | (*p++);
+           len = (len << 8) | (*p++);
        sourcelen -= n;
+        *length = toint(len);
     } else {
        *length = *p;
        p++, sourcelen--;
@@ -599,7 +601,8 @@ struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase,
      * decrypt, if the key was encrypted. */
     ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
     p += ret;
-    if (ret < 0 || id != 16) {
+    if (ret < 0 || id != 16 || len < 0 ||
+        key->keyblob+key->keyblob_len-p < len) {
        errmsg = "ASN.1 decoding failure";
         retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL;
        goto error;
@@ -630,7 +633,7 @@ struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase,
        ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
                              &id, &len, &flags);
        p += ret;
-       if (ret < 0 || id != 2 ||
+       if (ret < 0 || id != 2 || len < 0 ||
            key->keyblob+key->keyblob_len-p < len) {
            errmsg = "ASN.1 decoding failure";
            retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL;