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 <rsalz@openssl.org>
This commit is contained in:
Dr. Stephen Henson 2015-09-15 15:54:19 +01:00
parent 05e97f1d4f
commit de17bd5d7f
7 changed files with 72 additions and 13 deletions

View file

@ -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"},

View file

@ -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;

View file

@ -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

View file

@ -63,14 +63,23 @@
#include <openssl/objects.h>
#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);
}
}

View file

@ -65,6 +65,8 @@
#include <string.h>
#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)

View file

@ -943,7 +943,7 @@ void ERR_load_ASN1_strings(void);
# define ASN1_F_ASN1_ITEM_D2I_FP 206
# define ASN1_F_ASN1_ITEM_DUP 191
# define ASN1_F_ASN1_ITEM_EX_D2I 120
# define ASN1_F_ASN1_ITEM_EX_NEW 121
# define ASN1_F_ASN1_ITEM_EMBED_NEW 121
# define ASN1_F_ASN1_ITEM_I2D_BIO 192
# define ASN1_F_ASN1_ITEM_I2D_FP 193
# define ASN1_F_ASN1_ITEM_PACK 198

View file

@ -390,6 +390,8 @@ extern "C" {
# endif
/* Plain simple type */
# define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type)
/* Embedded simple type */
# define ASN1_EMBED(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_EMBED,0, stname, field, type)
/* OPTIONAL simple type */
# define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type)
@ -616,6 +618,9 @@ struct ASN1_ADB_TABLE_st {
# define ASN1_TFLG_NDEF (0x1<<11)
/* Field is embedded and not a pointer */
# define ASN1_TFLG_EMBED (0x1 << 12)
/* This is the actual ASN1 item itself */
struct ASN1_ITEM_st {