summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2015-09-15 15:54:19 +0100
committerDr. Stephen Henson <steve@openssl.org>2015-09-16 22:17:39 +0100
commitde17bd5d7f8286d8b1f0a04a3f8f5782033f5ebd (patch)
tree5fab90b0d760d271e1fe90cde99271f2407f96ed
parent05e97f1d4f940c765e5c93771fe20820acca4438 (diff)
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>
-rw-r--r--crypto/asn1/asn1_err.c2
-rw-r--r--crypto/asn1/tasn_dec.c10
-rw-r--r--crypto/asn1/tasn_enc.c10
-rw-r--r--crypto/asn1/tasn_fre.c27
-rw-r--r--crypto/asn1/tasn_new.c29
-rw-r--r--include/openssl/asn1.h2
-rw-r--r--include/openssl/asn1t.h5
7 files changed, 72 insertions, 13 deletions
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,15 +63,24 @@
#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;
const ASN1_AUX *aux = it->funcs;
@@ -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 <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);
@@ -83,6 +85,11 @@ ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it)
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;
const ASN1_AUX *aux = it->funcs;
@@ -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)
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 5b3b7d3bbb..3a67d61f7b 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -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
diff --git a/include/openssl/asn1t.h b/include/openssl/asn1t.h
index 4a4e1ef255..68f62641ca 100644
--- a/include/openssl/asn1t.h
+++ b/include/openssl/asn1t.h
@@ -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 {