bbd2dd
diff -up openssl-1.0.2k/crypto/asn1/asn1_err.c.asn1-recursive openssl-1.0.2k/crypto/asn1/asn1_err.c
bbd2dd
--- openssl-1.0.2k/crypto/asn1/asn1_err.c.asn1-recursive	2017-01-26 14:22:03.000000000 +0100
bbd2dd
+++ openssl-1.0.2k/crypto/asn1/asn1_err.c	2018-06-18 15:08:18.333412753 +0200
bbd2dd
@@ -279,6 +279,7 @@ static ERR_STRING_DATA ASN1_str_reasons[
bbd2dd
     {ERR_REASON(ASN1_R_MSTRING_NOT_UNIVERSAL), "mstring not universal"},
bbd2dd
     {ERR_REASON(ASN1_R_MSTRING_WRONG_TAG), "mstring wrong tag"},
bbd2dd
     {ERR_REASON(ASN1_R_NESTED_ASN1_STRING), "nested asn1 string"},
bbd2dd
+    {ERR_REASON(ASN1_R_NESTED_TOO_DEEP), "nested too deep"},
bbd2dd
     {ERR_REASON(ASN1_R_NON_HEX_CHARACTERS), "non hex characters"},
bbd2dd
     {ERR_REASON(ASN1_R_NOT_ASCII_FORMAT), "not ascii format"},
bbd2dd
     {ERR_REASON(ASN1_R_NOT_ENOUGH_DATA), "not enough data"},
bbd2dd
diff -up openssl-1.0.2k/crypto/asn1/asn1.h.asn1-recursive openssl-1.0.2k/crypto/asn1/asn1.h
bbd2dd
--- openssl-1.0.2k/crypto/asn1/asn1.h.asn1-recursive	2018-06-18 13:46:23.857127431 +0200
bbd2dd
+++ openssl-1.0.2k/crypto/asn1/asn1.h	2018-06-18 15:07:53.915826715 +0200
bbd2dd
@@ -1365,6 +1365,7 @@ void ERR_load_ASN1_strings(void);
bbd2dd
 # define ASN1_R_MSTRING_NOT_UNIVERSAL                     139
bbd2dd
 # define ASN1_R_MSTRING_WRONG_TAG                         140
bbd2dd
 # define ASN1_R_NESTED_ASN1_STRING                        197
bbd2dd
+# define ASN1_R_NESTED_TOO_DEEP                           219
bbd2dd
 # define ASN1_R_NON_HEX_CHARACTERS                        141
bbd2dd
 # define ASN1_R_NOT_ASCII_FORMAT                          190
bbd2dd
 # define ASN1_R_NOT_ENOUGH_DATA                           142
bbd2dd
diff -up openssl-1.0.2k/crypto/asn1/tasn_dec.c.asn1-recursive openssl-1.0.2k/crypto/asn1/tasn_dec.c
bbd2dd
--- openssl-1.0.2k/crypto/asn1/tasn_dec.c.asn1-recursive	2017-01-26 14:22:03.000000000 +0100
bbd2dd
+++ openssl-1.0.2k/crypto/asn1/tasn_dec.c	2018-06-18 15:14:28.978308482 +0200
bbd2dd
@@ -4,7 +4,7 @@
bbd2dd
  * 2000.
bbd2dd
  */
bbd2dd
 /* ====================================================================
bbd2dd
- * Copyright (c) 2000-2005 The OpenSSL Project.  All rights reserved.
bbd2dd
+ * Copyright (c) 2000-2018 The OpenSSL Project.  All rights reserved.
bbd2dd
  *
bbd2dd
  * Redistribution and use in source and binary forms, with or without
bbd2dd
  * modification, are permitted provided that the following conditions
bbd2dd
@@ -65,6 +65,14 @@
bbd2dd
 #include <openssl/buffer.h>
bbd2dd
 #include <openssl/err.h>
bbd2dd
 
bbd2dd
+/*
bbd2dd
+ * Constructed types with a recursive definition (such as can be found in PKCS7)
bbd2dd
+ * could eventually exceed the stack given malicious input with excessive
bbd2dd
+ * recursion. Therefore we limit the stack depth. This is the maximum number of
bbd2dd
+ * recursive invocations of asn1_item_embed_d2i().
bbd2dd
+ */
bbd2dd
+#define ASN1_MAX_CONSTRUCTED_NEST 30
bbd2dd
+
bbd2dd
 static int asn1_check_eoc(const unsigned char **in, long len);
bbd2dd
 static int asn1_find_end(const unsigned char **in, long len, char inf);
bbd2dd
 
bbd2dd
@@ -81,11 +89,11 @@ static int asn1_check_tlen(long *olen, i
bbd2dd
 static int asn1_template_ex_d2i(ASN1_VALUE **pval,
bbd2dd
                                 const unsigned char **in, long len,
bbd2dd
                                 const ASN1_TEMPLATE *tt, char opt,
bbd2dd
-                                ASN1_TLC *ctx);
bbd2dd
+                                ASN1_TLC *ctx, int depth);
bbd2dd
 static int asn1_template_noexp_d2i(ASN1_VALUE **val,
bbd2dd
                                    const unsigned char **in, long len,
bbd2dd
                                    const ASN1_TEMPLATE *tt, char opt,
bbd2dd
-                                   ASN1_TLC *ctx);
bbd2dd
+                                   ASN1_TLC *ctx, int depth);
bbd2dd
 static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
bbd2dd
                                  const unsigned char **in, long len,
bbd2dd
                                  const ASN1_ITEM *it,
bbd2dd
@@ -154,17 +162,16 @@ int ASN1_template_d2i(ASN1_VALUE **pval,
bbd2dd
 {
bbd2dd
     ASN1_TLC c;
bbd2dd
     asn1_tlc_clear_nc(&c);
bbd2dd
-    return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
bbd2dd
+    return asn1_template_ex_d2i(pval, in, len, tt, 0, &c, 0);
bbd2dd
 }
bbd2dd
 
bbd2dd
 /*
bbd2dd
  * Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and
bbd2dd
  * tag mismatch return -1 to handle OPTIONAL
bbd2dd
  */
bbd2dd
-
bbd2dd
-int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
bbd2dd
-                     const ASN1_ITEM *it,
bbd2dd
-                     int tag, int aclass, char opt, ASN1_TLC *ctx)
bbd2dd
+static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
bbd2dd
+                            long len, const ASN1_ITEM *it, int tag, int aclass,
bbd2dd
+                            char opt, ASN1_TLC *ctx, int depth)
bbd2dd
 {
bbd2dd
     const ASN1_TEMPLATE *tt, *errtt = NULL;
bbd2dd
     const ASN1_COMPAT_FUNCS *cf;
bbd2dd
@@ -189,6 +196,11 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
bbd2dd
     else
bbd2dd
         asn1_cb = 0;
bbd2dd
 
bbd2dd
+    if (++depth > ASN1_MAX_CONSTRUCTED_NEST) {
bbd2dd
+        ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NESTED_TOO_DEEP);
bbd2dd
+        goto err;
bbd2dd
+    }
bbd2dd
+
bbd2dd
     switch (it->itype) {
bbd2dd
     case ASN1_ITYPE_PRIMITIVE:
bbd2dd
         if (it->templates) {
bbd2dd
@@ -204,7 +216,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
bbd2dd
                 goto err;
bbd2dd
             }
bbd2dd
             return asn1_template_ex_d2i(pval, in, len,
bbd2dd
-                                        it->templates, opt, ctx);
bbd2dd
+                                        it->templates, opt, ctx, depth);
bbd2dd
         }
bbd2dd
         return asn1_d2i_ex_primitive(pval, in, len, it,
bbd2dd
                                      tag, aclass, opt, ctx);
bbd2dd
@@ -326,7 +338,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
bbd2dd
             /*
bbd2dd
              * We mark field as OPTIONAL so its absence can be recognised.
bbd2dd
              */
bbd2dd
-            ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
bbd2dd
+            ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx, depth);
bbd2dd
             /* If field not present, try the next one */
bbd2dd
             if (ret == -1)
bbd2dd
                 continue;
bbd2dd
@@ -444,7 +456,8 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
bbd2dd
              * attempt to read in field, allowing each to be OPTIONAL
bbd2dd
              */
bbd2dd
 
bbd2dd
-            ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);
bbd2dd
+            ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx,
bbd2dd
+                                       depth);
bbd2dd
             if (!ret) {
bbd2dd
                 errtt = seqtt;
bbd2dd
                 goto err;
bbd2dd
@@ -514,6 +527,13 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
bbd2dd
     return 0;
bbd2dd
 }
bbd2dd
 
bbd2dd
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
bbd2dd
+                     const ASN1_ITEM *it,
bbd2dd
+                     int tag, int aclass, char opt, ASN1_TLC *ctx)
bbd2dd
+{
bbd2dd
+    return asn1_item_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx, 0);
bbd2dd
+}
bbd2dd
+
bbd2dd
 /*
bbd2dd
  * Templates are handled with two separate functions. One handles any
bbd2dd
  * EXPLICIT tag and the other handles the rest.
bbd2dd
@@ -522,7 +542,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
bbd2dd
 static int asn1_template_ex_d2i(ASN1_VALUE **val,
bbd2dd
                                 const unsigned char **in, long inlen,
bbd2dd
                                 const ASN1_TEMPLATE *tt, char opt,
bbd2dd
-                                ASN1_TLC *ctx)
bbd2dd
+                                ASN1_TLC *ctx, int depth)
bbd2dd
 {
bbd2dd
     int flags, aclass;
bbd2dd
     int ret;
bbd2dd
@@ -557,7 +577,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
bbd2dd
             return 0;
bbd2dd
         }
bbd2dd
         /* We've found the field so it can't be OPTIONAL now */
bbd2dd
-        ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
bbd2dd
+        ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx, depth);
bbd2dd
         if (!ret) {
bbd2dd
             ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
bbd2dd
             return 0;
bbd2dd
@@ -581,7 +601,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
bbd2dd
             }
bbd2dd
         }
bbd2dd
     } else
bbd2dd
-        return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx);
bbd2dd
+        return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx, depth);
bbd2dd
 
bbd2dd
     *in = p;
bbd2dd
     return 1;
bbd2dd
@@ -594,7 +614,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
bbd2dd
 static int asn1_template_noexp_d2i(ASN1_VALUE **val,
bbd2dd
                                    const unsigned char **in, long len,
bbd2dd
                                    const ASN1_TEMPLATE *tt, char opt,
bbd2dd
-                                   ASN1_TLC *ctx)
bbd2dd
+                                   ASN1_TLC *ctx, int depth)
bbd2dd
 {
bbd2dd
     int flags, aclass;
bbd2dd
     int ret;
bbd2dd
@@ -665,14 +685,15 @@ static int asn1_template_noexp_d2i(ASN1_
bbd2dd
                 break;
bbd2dd
             }
bbd2dd
             skfield = NULL;
bbd2dd
-            if (!ASN1_item_ex_d2i(&skfield, &p, len,
bbd2dd
-                                  ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
bbd2dd
+            if (!asn1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item),
bbd2dd
+                                  -1, 0, 0, ctx, depth)) {
bbd2dd
                 ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
bbd2dd
                         ERR_R_NESTED_ASN1_ERROR);
bbd2dd
                 goto err;
bbd2dd
             }
bbd2dd
             len -= p - q;
bbd2dd
             if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, skfield)) {
bbd2dd
+                ASN1_item_ex_free(&skfield, ASN1_ITEM_ptr(tt->item));
bbd2dd
                 ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE);
bbd2dd
                 goto err;
bbd2dd
             }
bbd2dd
@@ -683,9 +704,8 @@ static int asn1_template_noexp_d2i(ASN1_
bbd2dd
         }
bbd2dd
     } else if (flags & ASN1_TFLG_IMPTAG) {
bbd2dd
         /* IMPLICIT tagging */
bbd2dd
-        ret = ASN1_item_ex_d2i(val, &p, len,
bbd2dd
-                               ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt,
bbd2dd
-                               ctx);
bbd2dd
+        ret = asn1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag,
bbd2dd
+                               aclass, opt, ctx, depth);
bbd2dd
         if (!ret) {
bbd2dd
             ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
bbd2dd
             goto err;
bbd2dd
@@ -693,8 +713,9 @@ static int asn1_template_noexp_d2i(ASN1_
bbd2dd
             return -1;
bbd2dd
     } else {
bbd2dd
         /* Nothing special */
bbd2dd
-        ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
bbd2dd
-                               -1, tt->flags & ASN1_TFLG_COMBINE, opt, ctx);
bbd2dd
+        ret = asn1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
bbd2dd
+                               -1, tt->flags & ASN1_TFLG_COMBINE, opt, ctx,
bbd2dd
+                               depth);
bbd2dd
         if (!ret) {
bbd2dd
             ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
bbd2dd
             goto err;