Limit recursion depth in old d2i_ASN1_bytes function
authorDr. Stephen Henson <steve@openssl.org>
Thu, 4 Aug 2016 14:00:26 +0000 (15:00 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 4 Aug 2016 21:12:59 +0000 (22:12 +0100)
Thanks to Shi Lei for reporting this bug.

Reviewed-by: Rich Salz <rsalz@openssl.org>
(cherry picked from commit 81f69e5b69b8e87ca5d7080ab643ebda7808542c)

crypto/asn1/a_bytes.c

index 385b53986a29915398c4f803d1cd2d53f137729b..65e5394664a4b63a69e64215088453013661d0e7 100644 (file)
 #include "cryptlib.h"
 #include <openssl/asn1.h>
 
-static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c);
+static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c,
+                                  int depth);
+static ASN1_STRING *int_d2i_ASN1_bytes(ASN1_STRING **a,
+                                       const unsigned char **pp, long length,
+                                       int Ptag, int Pclass, int depth,
+                                       int *perr);
 /*
  * type is a 'bitmap' of acceptable string types.
  */
@@ -99,7 +104,7 @@ ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a, const unsigned char **pp,
         ret = (*a);
 
     if (len != 0) {
-        s = (unsigned char *)OPENSSL_malloc((int)len + 1);
+        s = OPENSSL_malloc((int)len + 1);
         if (s == NULL) {
             i = ERR_R_MALLOC_FAILURE;
             goto err;
@@ -154,15 +159,38 @@ int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass)
     return (r);
 }
 
+/*
+ * Maximum recursion depth of d2i_ASN1_bytes(): much more than should be
+ * encountered in pratice.
+ */
+
+#define ASN1_BYTES_MAXDEPTH 20
+
 ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
                             long length, int Ptag, int Pclass)
+{
+    int err = 0;
+    ASN1_STRING *s = int_d2i_ASN1_bytes(a, pp, length, Ptag, Pclass, 0, &err);
+    if (err != 0)
+        ASN1err(ASN1_F_D2I_ASN1_BYTES, err);
+    return s;
+}
+
+static ASN1_STRING *int_d2i_ASN1_bytes(ASN1_STRING **a,
+                                       const unsigned char **pp, long length,
+                                       int Ptag, int Pclass,
+                                       int depth, int *perr)
 {
     ASN1_STRING *ret = NULL;
     const unsigned char *p;
     unsigned char *s;
     long len;
     int inf, tag, xclass;
-    int i = 0;
+
+    if (depth > ASN1_BYTES_MAXDEPTH) {
+        *perr = ASN1_R_NESTED_ASN1_STRING;
+        return NULL;
+    }
 
     if ((a == NULL) || ((*a) == NULL)) {
         if ((ret = ASN1_STRING_new()) == NULL)
@@ -173,18 +201,19 @@ ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
     p = *pp;
     inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
     if (inf & 0x80) {
-        i = ASN1_R_BAD_OBJECT_HEADER;
+        *perr = ASN1_R_BAD_OBJECT_HEADER;
         goto err;
     }
 
     if (tag != Ptag) {
-        i = ASN1_R_WRONG_TAG;
+        *perr = ASN1_R_WRONG_TAG;
         goto err;
     }
 
     if (inf & V_ASN1_CONSTRUCTED) {
         ASN1_const_CTX c;
 
+        c.error = 0;
         c.pp = pp;
         c.p = p;
         c.inf = inf;
@@ -192,17 +221,18 @@ ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
         c.tag = Ptag;
         c.xclass = Pclass;
         c.max = (length == 0) ? 0 : (p + length);
-        if (!asn1_collate_primitive(ret, &c))
+        if (!asn1_collate_primitive(ret, &c, depth)) {
+            *perr = c.error;
             goto err;
-        else {
+        else {
             p = c.p;
         }
     } else {
         if (len != 0) {
             if ((ret->length < len) || (ret->data == NULL)) {
-                s = (unsigned char *)OPENSSL_malloc((int)len + 1);
+                s = OPENSSL_malloc((int)len + 1);
                 if (s == NULL) {
-                    i = ERR_R_MALLOC_FAILURE;
+                    *perr = ERR_R_MALLOC_FAILURE;
                     goto err;
                 }
                 if (ret->data != NULL)
@@ -230,7 +260,6 @@ ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
  err:
     if ((ret != NULL) && ((a == NULL) || (*a != ret)))
         ASN1_STRING_free(ret);
-    ASN1err(ASN1_F_D2I_ASN1_BYTES, i);
     return (NULL);
 }
 
@@ -242,7 +271,8 @@ ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
  * There have been a few bug fixes for this function from Paul Keogh
  * <paul.keogh@sse.ie>, many thanks to him
  */
-static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c)
+static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c,
+                                  int depth)
 {
     ASN1_STRING *os = NULL;
     BUF_MEM b;
@@ -270,9 +300,8 @@ static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c)
         }
 
         c->q = c->p;
-        if (d2i_ASN1_bytes(&os, &c->p, c->max - c->p, c->tag, c->xclass)
-            == NULL) {
-            c->error = ERR_R_ASN1_LIB;
+        if (int_d2i_ASN1_bytes(&os, &c->p, c->max - c->p, c->tag, c->xclass,
+                               depth + 1, &c->error) == NULL) {
             goto err;
         }
 
@@ -297,7 +326,6 @@ static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c)
         ASN1_STRING_free(os);
     return (1);
  err:
-    ASN1err(ASN1_F_ASN1_COLLATE_PRIMITIVE, c->error);
     if (os != NULL)
         ASN1_STRING_free(os);
     if (b.data != NULL)