From 044855e14678c7779827d2f9772a6782c673f91a Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sat, 14 Mar 2009 18:33:25 +0000 Subject: [PATCH] Permit nested ASN1 string encoding but with a maximum depth to avoid stack overflow. --- CHANGES | 4 ++++ crypto/asn1/tasn_dec.c | 30 +++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 5141936823..8455d94d98 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,10 @@ Changes between 0.9.8j and 0.9.8k [xx XXX xxxx] + *) Permit restricted recursion of ASN1 strings. This is needed in practice + to handle some structures. + [Steve Henson] + *) Improve efficiency of mem_gets: don't search whole buffer each time for a '\n' [Jeremy Shapiro ] diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c index ced641698e..05129f229c 100644 --- a/crypto/asn1/tasn_dec.c +++ b/crypto/asn1/tasn_dec.c @@ -69,7 +69,7 @@ static int asn1_check_eoc(const unsigned char **in, long len); static int asn1_find_end(const unsigned char **in, long len, char inf); static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, - char inf, int tag, int aclass); + char inf, int tag, int aclass, int depth); static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen); @@ -878,7 +878,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, * internally irrespective of the type. So instead just check * for UNIVERSAL class and ignore the tag. */ - if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL)) + if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) { free_cont = 1; goto err; @@ -1128,8 +1128,18 @@ static int asn1_find_end(const unsigned char **in, long len, char inf) * if it is indefinite length. */ +#ifndef ASN1_MAX_STRING_NEST +/* This determines how many levels of recursion are permitted in ASN1 + * string types. If it is not limited stack overflows can occur. If set + * to zero no recursion is allowed at all. Although zero should be adequate + * examples exist that require a value of 1. So 5 should be more than enough. + */ +#define ASN1_MAX_STRING_NEST 5 +#endif + + static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, - char inf, int tag, int aclass) + char inf, int tag, int aclass, int depth) { const unsigned char *p, *q; long plen; @@ -1171,13 +1181,15 @@ static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, /* If indefinite length constructed update max length */ if (cst) { -#ifdef OPENSSL_ALLOW_NESTED_ASN1_STRINGS - if (!asn1_collect(buf, &p, plen, ininf, tag, aclass)) + if (depth >= ASN1_MAX_STRING_NEST) + { + ASN1err(ASN1_F_ASN1_COLLECT, + ASN1_R_NESTED_ASN1_STRING); + return 0; + } + if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, + depth + 1)) return 0; -#else - ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING); - return 0; -#endif } else if (plen && !collect_data(buf, &p, plen)) return 0; -- 2.25.1