File openssl-CVE-2018-0739.patch of Package compat-openssl098.11471
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.8j/crypto/asn1/asn1.h
===================================================================
--- openssl-0.9.8j.orig/crypto/asn1/asn1.h 2018-03-28 15:13:24.531593270 +0200
+++ openssl-0.9.8j/crypto/asn1/asn1.h 2018-03-28 15:13:25.967615686 +0200
@@ -1281,6 +1281,7 @@ void ERR_load_ASN1_strings(void);
#define ASN1_R_MSTRING_NOT_UNIVERSAL 139
#define ASN1_R_MSTRING_WRONG_TAG 140
#define ASN1_R_NESTED_ASN1_STRING 197
+#define ASN1_R_NESTED_TOO_DEEP 219
#define ASN1_R_NON_HEX_CHARACTERS 141
#define ASN1_R_NOT_ASCII_FORMAT 190
#define ASN1_R_NOT_ENOUGH_DATA 142
Index: openssl-0.9.8j/crypto/asn1/asn1_err.c
===================================================================
--- openssl-0.9.8j.orig/crypto/asn1/asn1_err.c 2018-03-28 15:13:24.531593270 +0200
+++ openssl-0.9.8j/crypto/asn1/asn1_err.c 2018-03-28 15:13:25.967615686 +0200
@@ -258,6 +258,7 @@ static ERR_STRING_DATA ASN1_str_reasons[
{ERR_REASON(ASN1_R_MSTRING_NOT_UNIVERSAL),"mstring not universal"},
{ERR_REASON(ASN1_R_MSTRING_WRONG_TAG) ,"mstring wrong tag"},
{ERR_REASON(ASN1_R_NESTED_ASN1_STRING) ,"nested asn1 string"},
+{ERR_REASON(ASN1_R_NESTED_TOO_DEEP) ,"nested too deep"},
{ERR_REASON(ASN1_R_NON_HEX_CHARACTERS) ,"non hex characters"},
{ERR_REASON(ASN1_R_NOT_ASCII_FORMAT) ,"not ascii format"},
{ERR_REASON(ASN1_R_NOT_ENOUGH_DATA) ,"not enough data"},
Index: openssl-0.9.8j/crypto/asn1/tasn_dec.c
===================================================================
--- openssl-0.9.8j.orig/crypto/asn1/tasn_dec.c 2018-03-28 15:13:24.535593332 +0200
+++ openssl-0.9.8j/crypto/asn1/tasn_dec.c 2018-03-28 15:14:55.025027989 +0200
@@ -65,6 +65,14 @@
#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(const unsigned char **in, long len);
static int asn1_find_end(const unsigned char **in, long len, char inf);
@@ -77,16 +85,16 @@ static int asn1_check_tlen(long *olen, i
char *inf, char *cst,
const unsigned char **in, long len,
int exptag, int expclass, char opt,
- ASN1_TLC *ctx);
+ ASN1_TLC *ctx);
static int asn1_template_ex_d2i(ASN1_VALUE **pval,
const unsigned char **in, long len,
const ASN1_TEMPLATE *tt, char opt,
- ASN1_TLC *ctx);
+ ASN1_TLC *ctx, int depth);
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
const unsigned char **in, long len,
const ASN1_TEMPLATE *tt, char opt,
- ASN1_TLC *ctx);
+ ASN1_TLC *ctx, int depth);
static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
const unsigned char **in, long len,
const ASN1_ITEM *it,
@@ -141,7 +149,7 @@ int ASN1_template_d2i(ASN1_VALUE **pval,
{
ASN1_TLC c;
c.valid = 0;
- return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
+ return asn1_template_ex_d2i(pval, in, len, tt, 0, &c, 0);
}
@@ -149,9 +157,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, const 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, const 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;
@@ -175,6 +183,11 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
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:
@@ -193,7 +206,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
goto err;
}
return asn1_template_ex_d2i(pval, in, len,
- it->templates, opt, ctx);
+ it->templates, opt, ctx, depth);
}
return asn1_d2i_ex_primitive(pval, in, len, it,
tag, aclass, opt, ctx);
@@ -334,7 +347,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;
@@ -465,7 +478,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
* OPTIONAL */
ret = asn1_template_ex_d2i(pseqval, &p, len,
- seqtt, isopt, ctx);
+ seqtt, isopt, ctx, depth);
if (!ret)
{
errtt = seqtt;
@@ -545,6 +558,13 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
return 0;
}
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const 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.
*/
@@ -552,7 +572,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval,
static int asn1_template_ex_d2i(ASN1_VALUE **val,
const unsigned char **in, long inlen,
const ASN1_TEMPLATE *tt, char opt,
- ASN1_TLC *ctx)
+ ASN1_TLC *ctx, int depth)
{
int flags, aclass;
int ret;
@@ -592,7 +612,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,
@@ -625,7 +645,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
}
else
return asn1_template_noexp_d2i(val, in, inlen,
- tt, opt, ctx);
+ tt, opt, ctx, depth);
*in = p;
return 1;
@@ -638,7 +658,7 @@ static int asn1_template_ex_d2i(ASN1_VAL
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
const unsigned char **in, long len,
const ASN1_TEMPLATE *tt, char opt,
- ASN1_TLC *ctx)
+ ASN1_TLC *ctx, int depth)
{
int flags, aclass;
int ret;
@@ -722,9 +742,9 @@ static int asn1_template_noexp_d2i(ASN1_
break;
}
skfield = NULL;
- if (!ASN1_item_ex_d2i(&skfield, &p, len,
+ if (!asn1_item_ex_d2i(&skfield, &p, len,
ASN1_ITEM_ptr(tt->item),
- -1, 0, 0, ctx))
+ -1, 0, 0, ctx, depth))
{
ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_NESTED_ASN1_ERROR);
@@ -747,8 +767,8 @@ 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_NOEXP_D2I,
@@ -761,8 +781,8 @@ static int asn1_template_noexp_d2i(ASN1_
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_NOEXP_D2I,