Fix buffer overrun in ASN1_parse().
authorViktor Dukhovni <openssl-users@dukhovni.org>
Wed, 20 Apr 2016 02:23:24 +0000 (22:23 -0400)
committerViktor Dukhovni <openssl-users@dukhovni.org>
Sat, 23 Apr 2016 04:46:32 +0000 (00:46 -0400)
Backport of commits:

        79c7f74d6cefd5d32fa20e69195ad3de834ce065
bdcd660e33710079b495cf5cc6a1aaa5d2dcd317

from master.

Reviewed-by: Matt Caswell <matt@openssl.org>
crypto/asn1/asn1_lib.c
crypto/asn1/asn1_par.c

index 0b61fc930967c80de65d56f47d44cef231e962fc..54b683c15152d2dfc519c41f06ee6e61ed8dbf7f 100644 (file)
@@ -63,7 +63,7 @@
 #include <openssl/asn1_mac.h>
 
 static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
-                           int max);
+                           long max);
 static void asn1_put_length(unsigned char **pp, int length);
 const char ASN1_version[] = "ASN.1" OPENSSL_VERSION_PTEXT;
 
@@ -131,7 +131,7 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
     }
     *ptag = tag;
     *pclass = xclass;
-    if (!asn1_get_length(&p, &inf, plength, (int)max))
+    if (!asn1_get_length(&p, &inf, plength, max))
         goto err;
 
     if (inf && !(ret & V_ASN1_CONSTRUCTED))
@@ -159,14 +159,14 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
 }
 
 static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
-                           int max)
+                           long max)
 {
     const unsigned char *p = *pp;
     unsigned long ret = 0;
-    unsigned int i;
+    unsigned long i;
 
     if (max-- < 1)
-        return (0);
+        return 0;
     if (*p == 0x80) {
         *inf = 1;
         ret = 0;
@@ -175,15 +175,11 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
         *inf = 0;
         i = *p & 0x7f;
         if (*(p++) & 0x80) {
-            if (i > sizeof(long))
+            if (i > sizeof(ret) || max < i)
                 return 0;
-            if (max-- == 0)
-                return (0);
             while (i-- > 0) {
                 ret <<= 8L;
                 ret |= *(p++);
-                if (max-- == 0)
-                    return (0);
             }
         } else
             ret = i;
@@ -192,7 +188,7 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
         return 0;
     *pp = p;
     *rl = (long)ret;
-    return (1);
+    return 1;
 }
 
 /*
index 0ca985a2be1e700e0def0c7ad02e2b16568fd2a0..e85e3398b6bb82c8b9498b35d93e07614befb29a 100644 (file)
@@ -173,6 +173,8 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
         if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0))
             goto end;
         if (j & V_ASN1_CONSTRUCTED) {
+            const unsigned char *sp;
+
             ep = p + len;
             if (BIO_write(bp, "\n", 1) <= 0)
                 goto end;
@@ -182,6 +184,7 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
                 goto end;
             }
             if ((j == 0x21) && (len == 0)) {
+                sp = p;
                 for (;;) {
                     r = asn1_parse2(bp, &p, (long)(tot - p),
                                     offset + (p - *pp), depth + 1,
@@ -190,19 +193,25 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
                         ret = 0;
                         goto end;
                     }
-                    if ((r == 2) || (p >= tot))
+                    if ((r == 2) || (p >= tot)) {
+                        len = p - sp;
                         break;
+                    }
                 }
-            } else
+            } else {
+                long tmp = len;
+
                 while (p < ep) {
-                    r = asn1_parse2(bp, &p, (long)len,
-                                    offset + (p - *pp), depth + 1,
+                    sp = p;
+                    r = asn1_parse2(bp, &p, tmp, offset + (p - *pp), depth + 1,
                                     indent, dump);
                     if (r == 0) {
                         ret = 0;
                         goto end;
                     }
+                    tmp -= p - sp;
                 }
+            }
         } else if (xclass != 0) {
             p += len;
             if (BIO_write(bp, "\n", 1) <= 0)