From de17bd5d7f8286d8b1f0a04a3f8f5782033f5ebd Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 15 Sep 2015 15:54:19 +0100 Subject: New ASN.1 embed macro. New ASN.1 macro ASN1_EMBED. This is the same as ASN1_SIMPLE except the structure is not allocated: it is part of the parent. That is instead of FOO *x; it must be: FOO x; This reduces memory fragmentation and make it impossible to accidentally set a mandatory field to NULL. This currently only works for SEQUENCE and since it is equivalent to ASN1_SIMPLE it cannot be tagged, OPTIONAL, SET OF or SEQUENCE OF. Reviewed-by: Rich Salz --- crypto/asn1/asn1_err.c | 2 +- crypto/asn1/tasn_dec.c | 10 ++++++++++ crypto/asn1/tasn_enc.c | 10 ++++++++++ crypto/asn1/tasn_fre.c | 27 ++++++++++++++++++++++----- crypto/asn1/tasn_new.c | 29 +++++++++++++++++++++++------ 5 files changed, 66 insertions(+), 12 deletions(-) (limited to 'crypto') diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 5dfd21be4a..0d1cf0cf57 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -104,7 +104,7 @@ static ERR_STRING_DATA ASN1_str_functs[] = { {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_EX_D2I), "ASN1_ITEM_EX_D2I"}, - {ERR_FUNC(ASN1_F_ASN1_ITEM_EX_NEW), "ASN1_ITEM_EX_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_FP), "ASN1_item_i2d_fp"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_PACK), "ASN1_item_pack"}, diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c index 732b4253d1..939ee205be 100644 --- a/crypto/asn1/tasn_dec.c +++ b/crypto/asn1/tasn_dec.c @@ -524,6 +524,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val, { int flags, aclass; int ret; + ASN1_VALUE *tval; const unsigned char *p, *q; if (!val) return 0; @@ -533,6 +534,15 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val, p = *in; q = p; + /* + * If field is embedded then val needs fixing so it is a pointer to + * a pointer to a field. + */ + if (tt->flags & ASN1_TFLG_EMBED) { + tval = (ASN1_VALUE *)val; + val = &tval; + } + if (flags & ASN1_TFLG_SK_MASK) { /* SET OF, SEQUENCE OF */ int sktag, skaclass; diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c index 35860e4514..e2feee0ec3 100644 --- a/crypto/asn1/tasn_enc.c +++ b/crypto/asn1/tasn_enc.c @@ -244,7 +244,17 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt, int tag, int iclass) { int i, ret, flags, ttag, tclass, ndef; + ASN1_VALUE *tval; flags = tt->flags; + + /* + * If field is embedded then val needs fixing so it is a pointer to + * a pointer to a field. + */ + if (flags & ASN1_TFLG_EMBED) { + tval = (ASN1_VALUE *)pval; + pval = &tval; + } /* * Work out tag and class to use: tagging may come either from the * template or the arguments, not both because this would create diff --git a/crypto/asn1/tasn_fre.c b/crypto/asn1/tasn_fre.c index e846561e21..e219e2c0a3 100644 --- a/crypto/asn1/tasn_fre.c +++ b/crypto/asn1/tasn_fre.c @@ -63,14 +63,23 @@ #include #include "asn1_locl.h" +static void asn1_item_embed_free(ASN1_VALUE **pval, const ASN1_ITEM *it, + int embed); + /* Free up an ASN1 structure */ void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it) { - ASN1_item_ex_free(&val, it); + asn1_item_embed_free(&val, it, 0); } void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + asn1_item_embed_free(pval, it, 0); +} + +static void asn1_item_embed_free(ASN1_VALUE **pval, const ASN1_ITEM *it, + int embed) { const ASN1_TEMPLATE *tt = NULL, *seqtt; const ASN1_EXTERN_FUNCS *ef; @@ -152,14 +161,22 @@ void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) } if (asn1_cb) asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL); - OPENSSL_free(*pval); - *pval = NULL; + if (embed == 0) { + OPENSSL_free(*pval); + *pval = NULL; + } break; } } void asn1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { + int embed = tt->flags & ASN1_TFLG_EMBED; + ASN1_VALUE *tval; + if (embed) { + tval = (ASN1_VALUE *)pval; + pval = &tval; + } if (tt->flags & ASN1_TFLG_SK_MASK) { STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; int i; @@ -167,12 +184,12 @@ void asn1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { ASN1_VALUE *vtmp = sk_ASN1_VALUE_value(sk, i); - ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item)); + asn1_item_embed_free(&vtmp, ASN1_ITEM_ptr(tt->item), embed); } sk_ASN1_VALUE_free(sk); *pval = NULL; } else { - ASN1_item_ex_free(pval, ASN1_ITEM_ptr(tt->item)); + asn1_item_embed_free(pval, ASN1_ITEM_ptr(tt->item), embed); } } diff --git a/crypto/asn1/tasn_new.c b/crypto/asn1/tasn_new.c index e7ceda3c54..294912c188 100644 --- a/crypto/asn1/tasn_new.c +++ b/crypto/asn1/tasn_new.c @@ -65,6 +65,8 @@ #include #include "asn1_locl.h" +static int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it, + int embed); static int asn1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it); static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); @@ -82,6 +84,11 @@ ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it) /* Allocate an ASN1 structure */ int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + return asn1_item_embed_new(pval, it, 0); +} + +int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed) { const ASN1_TEMPLATE *tt = NULL; const ASN1_EXTERN_FUNCS *ef; @@ -157,9 +164,13 @@ int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it) return 1; } } - *pval = OPENSSL_zalloc(it->size); - if (!*pval) - goto memerr; + if (embed) { + memset(*pval, 0, it->size); + } else { + *pval = OPENSSL_zalloc(it->size); + if (!*pval) + goto memerr; + } asn1_do_lock(pval, 0, it); asn1_enc_init(pval, it); for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { @@ -178,7 +189,7 @@ int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it) return 1; memerr: - ASN1err(ASN1_F_ASN1_ITEM_EX_NEW, ERR_R_MALLOC_FAILURE); + ASN1err(ASN1_F_ASN1_ITEM_EMBED_NEW, ERR_R_MALLOC_FAILURE); #ifdef CRYPTO_MDEBUG if (it->sname) CRYPTO_pop_info(); @@ -186,7 +197,7 @@ int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it) return 0; auxerr: - ASN1err(ASN1_F_ASN1_ITEM_EX_NEW, ASN1_R_AUX_ERROR); + ASN1err(ASN1_F_ASN1_ITEM_EMBED_NEW, ASN1_R_AUX_ERROR); ASN1_item_ex_free(pval, it); #ifdef CRYPTO_MDEBUG if (it->sname) @@ -232,7 +243,13 @@ static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { const ASN1_ITEM *it = ASN1_ITEM_ptr(tt->item); + int embed = tt->flags & ASN1_TFLG_EMBED; + ASN1_VALUE *tval; int ret; + if (embed) { + tval = (ASN1_VALUE *)pval; + pval = &tval; + } if (tt->flags & ASN1_TFLG_OPTIONAL) { asn1_template_clear(pval, tt); return 1; @@ -261,7 +278,7 @@ static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) goto done; } /* Otherwise pass it back to the item routine */ - ret = ASN1_item_ex_new(pval, it); + ret = asn1_item_embed_new(pval, it, embed); done: #ifdef CRYPTO_MDEBUG if (it->sname) -- cgit v1.2.3