@@ -66,6 +66,14 @@
#include "../internal.h"
#include "../internal.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_check_eoc(const unsigned char **in, long len);
static int asn1_find_end(const unsigned char **in, long len, char inf);
static int asn1_find_end(const unsigned char **in, long len, char inf);
@@ -82,11 +90,11 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
static int asn1_template_ex_d2i(ASN1_VALUE **pval,
static int asn1_template_ex_d2i(ASN1_VALUE **pval,
const unsigned char **in, long len,
const unsigned char **in, long len,
const ASN1_TEMPLATE *tt, char opt,
const ASN1_TEMPLATE *tt, char opt,
ASN1_TLC *ctx);
ASN1_TLC *ctx, int depth );
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
const unsigned char **in, long len,
const unsigned char **in, long len,
const ASN1_TEMPLATE *tt, char opt,
const ASN1_TEMPLATE *tt, char opt,
ASN1_TLC *ctx);
ASN1_TLC *ctx, int depth );
static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
const unsigned char **in, long len,
const unsigned char **in, long len,
const ASN1_ITEM *it,
const ASN1_ITEM *it,
@@ -153,9 +161,9 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
* tag mismatch return -1 to handle OPTIONAL
* tag mismatch return -1 to handle OPTIONAL
*/
*/
int ASN 1_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 asn 1_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_TEMPLATE *tt, *errtt = NULL;
const ASN1_COMPAT_FUNCS *cf;
const ASN1_COMPAT_FUNCS *cf;
@@ -188,6 +196,11 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
len = INT_MAX/2;
len = INT_MAX/2;
}
}
if (++depth > ASN1_MAX_CONSTRUCTED_NEST) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_TOO_DEEP);
goto err;
}
switch (it->itype) {
switch (it->itype) {
case ASN1_ITYPE_PRIMITIVE:
case ASN1_ITYPE_PRIMITIVE:
if (it->templates) {
if (it->templates) {
@@ -203,7 +216,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
goto err;
goto err;
}
}
return asn1_template_ex_d2i(pval, in, len,
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,
return asn1_d2i_ex_primitive(pval, in, len, it,
tag, aclass, opt, ctx);
tag, aclass, opt, ctx);
@@ -326,7 +339,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
/*
/*
* We mark field as OPTIONAL so its absence can be recognised.
* 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 field not present, try the next one */
if (ret == -1)
if (ret == -1)
continue;
continue;
@@ -444,7 +457,8 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
* attempt to read in field, allowing each to be 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) {
if (!ret) {
errtt = seqtt;
errtt = seqtt;
goto err;
goto err;
@@ -514,6 +528,13 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
return 0;
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
* Templates are handled with two separate functions. One handles any
* EXPLICIT tag and the other handles the rest.
* EXPLICIT tag and the other handles the rest.
@@ -522,7 +543,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
static int asn1_template_ex_d2i(ASN1_VALUE **val,
static int asn1_template_ex_d2i(ASN1_VALUE **val,
const unsigned char **in, long inlen,
const unsigned char **in, long inlen,
const ASN1_TEMPLATE *tt, char opt,
const ASN1_TEMPLATE *tt, char opt,
ASN1_TLC *ctx)
ASN1_TLC *ctx, int depth )
{
{
int flags, aclass;
int flags, aclass;
int ret;
int ret;
@@ -556,7 +577,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
return 0;
return 0;
}
}
/* We've found the field so it can't be OPTIONAL now */
/* 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) {
if (!ret) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
return 0;
return 0;
@@ -579,7 +600,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
}
}
}
}
} else
} 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;
*in = p;
return 1;
return 1;
@@ -592,7 +613,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
const unsigned char **in, long len,
const unsigned char **in, long len,
const ASN1_TEMPLATE *tt, char opt,
const ASN1_TEMPLATE *tt, char opt,
ASN1_TLC *ctx)
ASN1_TLC *ctx, int depth )
{
{
int flags, aclass;
int flags, aclass;
int ret;
int ret;
@@ -661,8 +682,8 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
break;
break;
}
}
skfield = NULL;
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 )) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
goto err;
goto err;
}
}
@@ -679,9 +700,8 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
}
}
} else if (flags & ASN1_TFLG_IMPTAG) {
} else if (flags & ASN1_TFLG_IMPTAG) {
/* IMPLICIT tagging */
/* 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) {
if (!ret) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
goto err;
goto err;
@@ -689,8 +709,9 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
return -1;
return -1;
} else {
} else {
/* Nothing special */
/* 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) {
if (!ret) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
goto err;
goto err;