Fix buffer overrun in ASN1_parse().
authorBen Laurie <ben@links.org>
Tue, 29 Mar 2016 18:37:57 +0000 (19:37 +0100)
committerBen Laurie <ben@links.org>
Wed, 30 Mar 2016 19:28:44 +0000 (20:28 +0100)
Fix buffer overrun in asn1_get_length().

Reproducer: asn1parse-reproduce crash-6bfd417f47bc940f6984f5e639b637fd4e6074bc

Fix length calculations.

Reproducer: asn1parse-reproduce crash-1819d0e54cd2b0430626c59053e6077ef04c2ffb
Reproducer: asn1parse-reproduce crash-9969db8603e644ddc0ba3459b51eac7a2c4b729b

Make i long.

Reviewed-by: Rich Salz <rsalz@openssl.org>
crypto/asn1/asn1_lib.c
crypto/asn1/asn1_par.c

index da1ac78e06766d3677c4cbaacbd99f4f8fb57f42..938984d50959955d139da13667f8cce6791568c0 100644 (file)
@@ -61,7 +61,7 @@
 #include <openssl/asn1.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);
 
 static int _asn1_check_infinite_end(const unsigned char **p, long len)
@@ -128,7 +128,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))
@@ -150,14 +150,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;
@@ -166,7 +166,7 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
         *inf = 0;
         i = *p & 0x7f;
         if (*(p++) & 0x80) {
-            if (max < (int)i)
+            if (max < (long)i + 1)
                 return 0;
             /* Skip leading zeroes */
             while (i && *p == 0) {
@@ -186,7 +186,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 773b8b2ee3e03310c752f2db6d66a8b97da4b6f2..b721273cf1757f32198ffc36bbc9af06366948a3 100644 (file)
@@ -164,6 +164,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 = p;
+                
             ep = p + len;
             if (BIO_write(bp, "\n", 1) <= 0)
                 goto end;
@@ -181,19 +183,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 {
                 while (p < ep) {
-                    r = asn1_parse2(bp, &p, (long)len,
+                    sp = p;
+                    r = asn1_parse2(bp, &p, len,
                                     offset + (p - *pp), depth + 1,
                                     indent, dump);
                     if (r == 0) {
                         ret = 0;
                         goto end;
                     }
+                    len -= p - sp;
                 }
+                len = length;
+            }
         } else if (xclass != 0) {
             p += len;
             if (BIO_write(bp, "\n", 1) <= 0)
@@ -229,7 +237,8 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
                         goto end;
                     dump_cont = 1;
                 }
-                BIO_printf(bp, ":%u", p[0]);
+                if (len > 0)
+                    BIO_printf(bp, ":%u", p[0]);
             } else if (tag == V_ASN1_BMPSTRING) {
                 /* do the BMP thang */
             } else if (tag == V_ASN1_OCTET_STRING) {