Free up ASN.1 structures at top level only.

When a decoding error in ASN.1 occurs only free up the partial structure
at the top level. This simplifies embedded handling and fixes freeing
up of structures when presented with malformed input.

Reviewed-by: Rich Salz <rsalz@openssl.org>
This commit is contained in:
Dr. Stephen Henson 2015-10-03 17:15:15 +01:00
parent 605236f6a8
commit f93ad22f6a
3 changed files with 42 additions and 30 deletions

View File

@ -103,7 +103,7 @@ static ERR_STRING_DATA ASN1_str_functs[] = {
{ERR_FUNC(ASN1_F_ASN1_INTEGER_TO_BN), "ASN1_INTEGER_to_BN"}, {ERR_FUNC(ASN1_F_ASN1_INTEGER_TO_BN), "ASN1_INTEGER_to_BN"},
{ERR_FUNC(ASN1_F_ASN1_ITEM_D2I_FP), "ASN1_item_d2i_fp"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_D2I_FP), "ASN1_item_d2i_fp"},
{ERR_FUNC(ASN1_F_ASN1_ITEM_DUP), "ASN1_item_dup"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_DUP), "ASN1_item_dup"},
{ERR_FUNC(ASN1_F_ASN1_ITEM_EX_D2I), "ASN1_ITEM_EX_D2I"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_EMBED_D2I), "asn1_item_embed_d2i"},
{ERR_FUNC(ASN1_F_ASN1_ITEM_EMBED_NEW), "ASN1_ITEM_EMBED_NEW"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_EMBED_NEW), "ASN1_ITEM_EMBED_NEW"},
{ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_BIO), "ASN1_item_i2d_bio"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_BIO), "ASN1_item_i2d_bio"},
{ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_FP), "ASN1_item_i2d_fp"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_FP), "ASN1_item_i2d_fp"},

View File

@ -66,6 +66,10 @@
#include <openssl/err.h> #include <openssl/err.h>
#include "asn1_locl.h" #include "asn1_locl.h"
static int asn1_item_embed_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_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);
@ -151,14 +155,25 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
return NULL; return NULL;
} }
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 rv;
rv = asn1_item_embed_d2i(pval, in, len, it, tag, aclass, opt, ctx);
if (rv <= 0)
ASN1_item_ex_free(pval, it);
return rv;
}
/* /*
* Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and * Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and
* tag mismatch return -1 to handle OPTIONAL * tag mismatch return -1 to handle OPTIONAL
*/ */
int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
const ASN1_ITEM *it, long len, const ASN1_ITEM *it,
int tag, int aclass, char opt, ASN1_TLC *ctx) int tag, int aclass, char opt, ASN1_TLC *ctx)
{ {
const ASN1_TEMPLATE *tt, *errtt = NULL; const ASN1_TEMPLATE *tt, *errtt = NULL;
const ASN1_EXTERN_FUNCS *ef; const ASN1_EXTERN_FUNCS *ef;
@ -189,7 +204,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
* template in the template itself. * template in the template itself.
*/ */
if ((tag != -1) || opt) { if ((tag != -1) || opt) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I,
ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
goto err; goto err;
} }
@ -205,7 +220,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL,
&p, len, -1, 0, 1, ctx); &p, len, -1, 0, 1, ctx);
if (!ret) { if (!ret) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
} }
@ -214,7 +229,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
/* If OPTIONAL, assume this is OK */ /* If OPTIONAL, assume this is OK */
if (opt) if (opt)
return -1; return -1;
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL);
goto err; goto err;
} }
/* Check tag matches bit map */ /* Check tag matches bit map */
@ -222,7 +237,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
/* If OPTIONAL, assume this is OK */ /* If OPTIONAL, assume this is OK */
if (opt) if (opt)
return -1; return -1;
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_WRONG_TAG); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MSTRING_WRONG_TAG);
goto err; goto err;
} }
return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx); return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx);
@ -245,7 +260,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
asn1_set_choice_selector(pval, -1, it); asn1_set_choice_selector(pval, -1, it);
} }
} else if (!ASN1_item_ex_new(pval, it)) { } else if (!ASN1_item_ex_new(pval, it)) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
} }
/* CHOICE type, try each possibility in turn */ /* CHOICE type, try each possibility in turn */
@ -264,7 +279,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
break; break;
/* Otherwise must be an ASN1 parsing error */ /* Otherwise must be an ASN1 parsing error */
errtt = tt; errtt = tt;
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
} }
@ -276,7 +291,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
ASN1_item_ex_free(pval, it); ASN1_item_ex_free(pval, it);
return -1; return -1;
} }
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE);
goto err; goto err;
} }
@ -300,7 +315,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst,
&p, len, tag, aclass, opt, ctx); &p, len, tag, aclass, opt, ctx);
if (!ret) { if (!ret) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
} else if (ret == -1) } else if (ret == -1)
return -1; return -1;
@ -312,12 +327,12 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
else else
seq_nolen = seq_eoc; seq_nolen = seq_eoc;
if (!cst) { if (!cst) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED);
goto err; goto err;
} }
if (!*pval && !ASN1_item_ex_new(pval, it)) { if (!*pval && !ASN1_item_ex_new(pval, it)) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
} }
@ -349,7 +364,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
q = p; q = p;
if (asn1_check_eoc(&p, len)) { if (asn1_check_eoc(&p, len)) {
if (!seq_eoc) { if (!seq_eoc) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_UNEXPECTED_EOC); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_UNEXPECTED_EOC);
goto err; goto err;
} }
len -= p - q; len -= p - q;
@ -388,12 +403,12 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
/* Check for EOC if expecting one */ /* Check for EOC if expecting one */
if (seq_eoc && !asn1_check_eoc(&p, len)) { if (seq_eoc && !asn1_check_eoc(&p, len)) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MISSING_EOC);
goto err; goto err;
} }
/* Check all data read */ /* Check all data read */
if (!seq_nolen && len) { if (!seq_nolen && len) {
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH);
goto err; goto err;
} }
@ -413,7 +428,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
asn1_template_free(pseqval, seqtt); asn1_template_free(pseqval, seqtt);
} else { } else {
errtt = seqtt; errtt = seqtt;
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_FIELD_MISSING); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_FIELD_MISSING);
goto err; goto err;
} }
} }
@ -429,9 +444,8 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
return 0; return 0;
} }
auxerr: auxerr:
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR); ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_AUX_ERROR);
err: err:
ASN1_item_ex_free(pval, it);
if (errtt) if (errtt)
ERR_add_error_data(4, "Field=", errtt->field_name, ERR_add_error_data(4, "Field=", errtt->field_name,
", Type=", it->sname); ", Type=", it->sname);
@ -513,7 +527,6 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
return 1; return 1;
err: err:
asn1_template_free(val, tt);
return 0; return 0;
} }
@ -601,8 +614,8 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
break; break;
} }
skfield = NULL; skfield = NULL;
if (!ASN1_item_ex_d2i(&skfield, &p, len, if (!asn1_item_embed_d2i(&skfield, &p, len,
ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) { ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_NESTED_ASN1_ERROR); ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
@ -619,9 +632,9 @@ 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, ret = asn1_item_embed_d2i(val, &p, len,
ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt,
ctx); ctx);
if (!ret) { if (!ret) {
ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
@ -629,8 +642,8 @@ 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), ret = asn1_item_embed_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
-1, 0, opt, ctx); -1, 0, opt, ctx);
if (!ret) { if (!ret) {
ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR); ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err; goto err;
@ -642,7 +655,6 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
return 1; return 1;
err: err:
asn1_template_free(val, tt);
return 0; return 0;
} }

View File

@ -942,7 +942,7 @@ void ERR_load_ASN1_strings(void);
# define ASN1_F_ASN1_INTEGER_TO_BN 119 # define ASN1_F_ASN1_INTEGER_TO_BN 119
# define ASN1_F_ASN1_ITEM_D2I_FP 206 # define ASN1_F_ASN1_ITEM_D2I_FP 206
# define ASN1_F_ASN1_ITEM_DUP 191 # define ASN1_F_ASN1_ITEM_DUP 191
# define ASN1_F_ASN1_ITEM_EX_D2I 120 # define ASN1_F_ASN1_ITEM_EMBED_D2I 120
# define ASN1_F_ASN1_ITEM_EMBED_NEW 121 # define ASN1_F_ASN1_ITEM_EMBED_NEW 121
# define ASN1_F_ASN1_ITEM_I2D_BIO 192 # define ASN1_F_ASN1_ITEM_I2D_BIO 192
# define ASN1_F_ASN1_ITEM_I2D_FP 193 # define ASN1_F_ASN1_ITEM_I2D_FP 193