commit 9310d45087ae546e27e61ddf8f6367f29848220d
Author: Matt Caswell <matt@openssl.org>
Date:   Thu Mar 22 10:05:40 2018 +0000

    Limit ASN.1 constructed types recursive definition depth
    
    Constructed types with a recursive definition (such as can be found in
    PKCS7) could eventually exceed the stack given malicious input with
    excessive recursion. Therefore we limit the stack depth.
    
    CVE-2018-0739
    
    Credit to OSSFuzz for finding this issue.
    
    Reviewed-by: Rich Salz <rsalz@openssl.org>

Index: openssl-0.9.7g/crypto/asn1/asn1.h
===================================================================
--- openssl-0.9.7g.orig/crypto/asn1/asn1.h	2018-08-14 11:54:44.552243114 +0200
+++ openssl-0.9.7g/crypto/asn1/asn1.h	2018-08-14 11:54:45.164247153 +0200
@@ -1082,6 +1082,7 @@ void ERR_load_ASN1_strings(void);
 #define ASN1_R_MISSING_SECOND_NUMBER			 138
 #define ASN1_R_MSTRING_NOT_UNIVERSAL			 139
 #define ASN1_R_MSTRING_WRONG_TAG			 140
+#define ASN1_R_NESTED_TOO_DEEP                           219
 #define ASN1_R_NON_HEX_CHARACTERS			 141
 #define ASN1_R_NOT_ENOUGH_DATA				 142
 #define ASN1_R_NO_MATCHING_CHOICE_TYPE			 143
Index: openssl-0.9.7g/crypto/asn1/asn1_err.c
===================================================================
--- openssl-0.9.7g.orig/crypto/asn1/asn1_err.c	2018-08-14 11:54:44.552243114 +0200
+++ openssl-0.9.7g/crypto/asn1/asn1_err.c	2018-08-14 11:54:45.164247153 +0200
@@ -204,6 +204,7 @@ static ERR_STRING_DATA ASN1_str_reasons[
 {ASN1_R_MISSING_SECOND_NUMBER            ,"missing second number"},
 {ASN1_R_MSTRING_NOT_UNIVERSAL            ,"mstring not universal"},
 {ASN1_R_MSTRING_WRONG_TAG                ,"mstring wrong tag"},
+{ASN1_R_NESTED_TOO_DEEP                  ,"nested too deep"},
 {ASN1_R_NON_HEX_CHARACTERS               ,"non hex characters"},
 {ASN1_R_NOT_ENOUGH_DATA                  ,"not enough data"},
 {ASN1_R_NO_MATCHING_CHOICE_TYPE          ,"no matching choice type"},
Index: openssl-0.9.7g/crypto/asn1/tasn_dec.c
===================================================================
--- openssl-0.9.7g.orig/crypto/asn1/tasn_dec.c	2018-08-14 11:54:44.924245569 +0200
+++ openssl-0.9.7g/crypto/asn1/tasn_dec.c	2018-08-14 12:56:45.452979698 +0200
@@ -65,13 +65,21 @@
 #include <openssl/buffer.h>
 #include <openssl/err.h>
 
+/*
+ * Constructed types with a recursive definition (such as can be found in PKCS7)
+ * could eventually exceed the stack given malicious input with excessive
+ * recursion. Therefore we limit the stack depth. This is the maximum number of
+ * recursive invocations of asn1_item_embed_d2i().
+ */
+#define ASN1_MAX_CONSTRUCTED_NEST 30
+
 static int asn1_check_eoc(unsigned char **in, long len);
 static int asn1_collect(BUF_MEM *buf, unsigned char **in, long len, char inf, int tag, int aclass);
 static int collect_data(BUF_MEM *buf, unsigned char **p, long plen);
 static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst,
 			unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx);
-static int asn1_template_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
-static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
+static int asn1_template_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx, int depth);
+static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx, int depth);
 static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long len,
 					const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx);
 
@@ -121,7 +129,7 @@ int ASN1_template_d2i(ASN1_VALUE **pval,
 {
 	ASN1_TLC c;
 	asn1_tlc_clear(&c);
-	return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
+	return asn1_template_ex_d2i(pval, in, len, tt, 0, &c, 0);
 }
 
 
@@ -129,8 +137,9 @@ int ASN1_template_d2i(ASN1_VALUE **pval,
  * If 'opt' set and tag mismatch return -1 to handle OPTIONAL
  */
 
-int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_ITEM *it,
-				int tag, int aclass, char opt, ASN1_TLC *ctx)
+static int asn1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in,
+                            long len, const ASN1_ITEM *it, int tag, int aclass,
+                            char opt, ASN1_TLC *ctx, int depth)
 {
 	const ASN1_TEMPLATE *tt, *errtt = NULL;
 	const ASN1_COMPAT_FUNCS *cf;
@@ -150,6 +159,11 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
 	if(aux && aux->asn1_cb) asn1_cb = aux->asn1_cb;
 	else asn1_cb = 0;
 
+    if (++depth > ASN1_MAX_CONSTRUCTED_NEST) {
+        ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NESTED_TOO_DEEP);
+        goto err;
+    }
+
 	switch(it->itype) {
 
 		case ASN1_ITYPE_PRIMITIVE:
@@ -163,7 +177,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
 				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
 				goto err;
 			}
-			return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx);
+			return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx, depth);
 		}
 		return asn1_d2i_ex_primitive(pval, in, len, it, tag, aclass, opt, ctx);
 		break;
@@ -270,7 +284,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
 			/* We mark field as OPTIONAL so its absence
 			 * can be recognised.
 			 */
-			ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
+			ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx, depth);
 			/* If field not present, try the next one */
 			if(ret == -1) continue;
 			/* If positive return, read OK, break loop */
@@ -369,7 +383,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
 			if(i == (it->tcount - 1)) isopt = 0;
 			else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL);
 			/* attempt to read in field, allowing each to be OPTIONAL */
-			ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);
+			ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx, depth);
 			if(!ret) {
 				errtt = seqtt;
 				goto err;
@@ -431,11 +445,18 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
 	return 0;
 }
 
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len,
+                     const ASN1_ITEM *it,
+                     int tag, int aclass, char opt, ASN1_TLC *ctx)
+{
+    return asn1_item_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx, 0);
+}
+
 /* Templates are handled with two separate functions. One handles any EXPLICIT tag and the other handles the
  * rest.
  */
 
-static int asn1_template_ex_d2i(ASN1_VALUE **val, unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
+static int asn1_template_ex_d2i(ASN1_VALUE **val, unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx, int depth)
 {
 	int flags, aclass;
 	int ret;
@@ -465,7 +486,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
 			return 0;
 		}
 		/* We've found the field so it can't be OPTIONAL now */
-		ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
+		ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx, depth);
 		if(!ret) {
 			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
 			return 0;
@@ -486,7 +507,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
 			}
 		}
 	} else 
-		return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx);
+		return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx, depth);
 
 	*in = p;
 	return 1;
@@ -496,7 +517,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
 	return 0;
 }
 
-static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
+static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx, int depth)
 {
 	int flags, aclass;
 	int ret;
@@ -557,7 +578,7 @@ static int asn1_template_noexp_d2i(ASN1_
 				break;
 			}
 			skfield = NULL;
-			if(!ASN1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
+			if(!asn1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx, depth)) {
 				ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
 				goto err;
 			}
@@ -573,14 +594,14 @@ static int asn1_template_noexp_d2i(ASN1_
 		}
 	} else if(flags & ASN1_TFLG_IMPTAG) {
 		/* IMPLICIT tagging */
-		ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx);
+		ret = asn1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx, depth);
 		if(!ret) {
 			ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
 			goto err;
 		} else if(ret == -1) return -1;
 	} else {
 		/* Nothing special */
-		ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, tt->flags & ASN1_TFLG_COMBINE, opt, ctx);
+		ret = asn1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, tt->flags & ASN1_TFLG_COMBINE, opt, ctx, depth);
 		if(!ret) {
 			ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
 			goto err;
