New ASN.1 embed macro.
authorDr. Stephen Henson <steve@openssl.org>
Tue, 15 Sep 2015 14:54:19 +0000 (15:54 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 16 Sep 2015 21:17:39 +0000 (22:17 +0100)
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>
crypto/asn1/asn1_err.c
crypto/asn1/tasn_dec.c
crypto/asn1/tasn_enc.c
crypto/asn1/tasn_fre.c
crypto/asn1/tasn_new.c
include/openssl/asn1.h
include/openssl/asn1t.h

index 5dfd21b..0d1cf0c 100644 (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"},
index 732b425..939ee20 100644 (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;
index 35860e4..e2feee0 100644 (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
index e846561..e219e2c 100644 (file)
 #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);
     }
 }
 
index e7ceda3..294912c 100644 (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)
index 5b3b7d3..3a67d61 100644 (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
index 4a4e1ef..68f6264 100644 (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 {