Skip to content
This repository was archived by the owner on Aug 24, 2025. It is now read-only.

Commit 2ac4c6f

Browse files
committed
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>
1 parent d8278da commit 2ac4c6f

File tree

3 files changed

+35
-16
lines changed

3 files changed

+35
-16
lines changed

crypto/asn1/asn1_err.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Generated by util/mkerr.pl DO NOT EDIT
3-
* Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
3+
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
44
*
55
* Licensed under the OpenSSL license (the "License"). You may not use
66
* this file except in compliance with the License. You can obtain a copy
@@ -203,6 +203,7 @@ static ERR_STRING_DATA ASN1_str_reasons[] = {
203203
{ERR_REASON(ASN1_R_MSTRING_NOT_UNIVERSAL), "mstring not universal"},
204204
{ERR_REASON(ASN1_R_MSTRING_WRONG_TAG), "mstring wrong tag"},
205205
{ERR_REASON(ASN1_R_NESTED_ASN1_STRING), "nested asn1 string"},
206+
{ERR_REASON(ASN1_R_NESTED_TOO_DEEP), "nested too deep"},
206207
{ERR_REASON(ASN1_R_NON_HEX_CHARACTERS), "non hex characters"},
207208
{ERR_REASON(ASN1_R_NOT_ASCII_FORMAT), "not ascii format"},
208209
{ERR_REASON(ASN1_R_NOT_ENOUGH_DATA), "not enough data"},

crypto/asn1/tasn_dec.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,18 @@
1717
#include "internal/numbers.h"
1818
#include "asn1_locl.h"
1919

20+
/*
21+
* Constructed types with a recursive definition (such as can be found in PKCS7)
22+
* could eventually exceed the stack given malicious input with excessive
23+
* recursion. Therefore we limit the stack depth. This is the maximum number of
24+
* recursive invocations of asn1_item_embed_d2i().
25+
*/
26+
#define ASN1_MAX_CONSTRUCTED_NEST 30
27+
2028
static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
2129
long len, const ASN1_ITEM *it,
22-
int tag, int aclass, char opt, ASN1_TLC *ctx);
30+
int tag, int aclass, char opt, ASN1_TLC *ctx,
31+
int depth);
2332

2433
static int asn1_check_eoc(const unsigned char **in, long len);
2534
static int asn1_find_end(const unsigned char **in, long len, char inf);
@@ -37,11 +46,11 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
3746
static int asn1_template_ex_d2i(ASN1_VALUE **pval,
3847
const unsigned char **in, long len,
3948
const ASN1_TEMPLATE *tt, char opt,
40-
ASN1_TLC *ctx);
49+
ASN1_TLC *ctx, int depth);
4150
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
4251
const unsigned char **in, long len,
4352
const ASN1_TEMPLATE *tt, char opt,
44-
ASN1_TLC *ctx);
53+
ASN1_TLC *ctx, int depth);
4554
static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
4655
const unsigned char **in, long len,
4756
const ASN1_ITEM *it,
@@ -111,7 +120,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
111120
int tag, int aclass, char opt, ASN1_TLC *ctx)
112121
{
113122
int rv;
114-
rv = asn1_item_embed_d2i(pval, in, len, it, tag, aclass, opt, ctx);
123+
rv = asn1_item_embed_d2i(pval, in, len, it, tag, aclass, opt, ctx, 0);
115124
if (rv <= 0)
116125
ASN1_item_ex_free(pval, it);
117126
return rv;
@@ -124,7 +133,8 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
124133

125134
static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
126135
long len, const ASN1_ITEM *it,
127-
int tag, int aclass, char opt, ASN1_TLC *ctx)
136+
int tag, int aclass, char opt, ASN1_TLC *ctx,
137+
int depth)
128138
{
129139
const ASN1_TEMPLATE *tt, *errtt = NULL;
130140
const ASN1_EXTERN_FUNCS *ef;
@@ -145,6 +155,11 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
145155
else
146156
asn1_cb = 0;
147157

158+
if (++depth > ASN1_MAX_CONSTRUCTED_NEST) {
159+
ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_NESTED_TOO_DEEP);
160+
goto err;
161+
}
162+
148163
switch (it->itype) {
149164
case ASN1_ITYPE_PRIMITIVE:
150165
if (it->templates) {
@@ -160,7 +175,7 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
160175
goto err;
161176
}
162177
return asn1_template_ex_d2i(pval, in, len,
163-
it->templates, opt, ctx);
178+
it->templates, opt, ctx, depth);
164179
}
165180
return asn1_d2i_ex_primitive(pval, in, len, it,
166181
tag, aclass, opt, ctx);
@@ -221,7 +236,7 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
221236
/*
222237
* We mark field as OPTIONAL so its absence can be recognised.
223238
*/
224-
ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
239+
ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx, depth);
225240
/* If field not present, try the next one */
226241
if (ret == -1)
227242
continue;
@@ -344,7 +359,8 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
344359
* attempt to read in field, allowing each to be OPTIONAL
345360
*/
346361

347-
ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);
362+
ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx,
363+
depth);
348364
if (!ret) {
349365
errtt = seqtt;
350366
goto err;
@@ -420,7 +436,7 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
420436
static int asn1_template_ex_d2i(ASN1_VALUE **val,
421437
const unsigned char **in, long inlen,
422438
const ASN1_TEMPLATE *tt, char opt,
423-
ASN1_TLC *ctx)
439+
ASN1_TLC *ctx, int depth)
424440
{
425441
int flags, aclass;
426442
int ret;
@@ -455,7 +471,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
455471
return 0;
456472
}
457473
/* We've found the field so it can't be OPTIONAL now */
458-
ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
474+
ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx, depth);
459475
if (!ret) {
460476
ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
461477
return 0;
@@ -479,7 +495,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
479495
}
480496
}
481497
} else
482-
return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx);
498+
return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx, depth);
483499

484500
*in = p;
485501
return 1;
@@ -491,7 +507,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
491507
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
492508
const unsigned char **in, long len,
493509
const ASN1_TEMPLATE *tt, char opt,
494-
ASN1_TLC *ctx)
510+
ASN1_TLC *ctx, int depth)
495511
{
496512
int flags, aclass;
497513
int ret;
@@ -573,7 +589,8 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
573589
}
574590
skfield = NULL;
575591
if (!asn1_item_embed_d2i(&skfield, &p, len,
576-
ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
592+
ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx,
593+
depth)) {
577594
ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
578595
ERR_R_NESTED_ASN1_ERROR);
579596
/* |skfield| may be partially allocated despite failure. */
@@ -595,7 +612,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
595612
/* IMPLICIT tagging */
596613
ret = asn1_item_embed_d2i(val, &p, len,
597614
ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt,
598-
ctx);
615+
ctx, depth);
599616
if (!ret) {
600617
ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
601618
goto err;
@@ -604,7 +621,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
604621
} else {
605622
/* Nothing special */
606623
ret = asn1_item_embed_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
607-
-1, 0, opt, ctx);
624+
-1, 0, opt, ctx, depth);
608625
if (!ret) {
609626
ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
610627
goto err;

include/openssl/asn1.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,7 @@ int ERR_load_ASN1_strings(void);
10511051
# define ASN1_R_MSTRING_NOT_UNIVERSAL 139
10521052
# define ASN1_R_MSTRING_WRONG_TAG 140
10531053
# define ASN1_R_NESTED_ASN1_STRING 197
1054+
# define ASN1_R_NESTED_TOO_DEEP 201
10541055
# define ASN1_R_NON_HEX_CHARACTERS 141
10551056
# define ASN1_R_NOT_ASCII_FORMAT 190
10561057
# define ASN1_R_NOT_ENOUGH_DATA 142

0 commit comments

Comments
 (0)