Add and use OPENSSL_zalloc
[openssl.git] / crypto / asn1 / tasn_dec.c
index abdeba4ce4300ca0de38d94cca97a4bee90eb5bb..7a6414ad04761b5b355869c4fd8d095ce5ddbe6c 100644 (file)
@@ -64,6 +64,7 @@
 #include <openssl/objects.h>
 #include <openssl/buffer.h>
 #include <openssl/err.h>
+#include "asn1_locl.h"
 
 static int asn1_check_eoc(const unsigned char **in, long len);
 static int asn1_find_end(const unsigned char **in, long len, char inf);
@@ -91,6 +92,8 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
                                  const ASN1_ITEM *it,
                                  int tag, int aclass, char opt,
                                  ASN1_TLC *ctx);
+static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+                       int utype, char *free_cont, const ASN1_ITEM *it);
 
 /* Table to convert tags to bit values, used for MSTRING type */
 static const unsigned long tag2bit[32] = {
@@ -148,15 +151,6 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
     return NULL;
 }
 
-int ASN1_template_d2i(ASN1_VALUE **pval,
-                      const unsigned char **in, long len,
-                      const ASN1_TEMPLATE *tt)
-{
-    ASN1_TLC c;
-    asn1_tlc_clear_nc(&c);
-    return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
-}
-
 /*
  * Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and
  * tag mismatch return -1 to handle OPTIONAL
@@ -167,19 +161,17 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
                      int tag, int aclass, char opt, ASN1_TLC *ctx)
 {
     const ASN1_TEMPLATE *tt, *errtt = NULL;
-    const ASN1_COMPAT_FUNCS *cf;
     const ASN1_EXTERN_FUNCS *ef;
     const ASN1_AUX *aux = it->funcs;
     ASN1_aux_cb *asn1_cb;
     const unsigned char *p = NULL, *q;
-    unsigned char *wp = NULL;   /* BIG FAT WARNING! BREAKS CONST WHERE USED */
-    unsigned char imphack = 0, oclass;
+    unsigned char oclass;
     char seq_eoc, seq_nolen, cst, isopt;
     long tmplen;
     int i;
     int otag;
     int ret = 0;
-    ASN1_VALUE **pchptr, *ptmpval;
+    ASN1_VALUE **pchptr;
     if (!pval)
         return 0;
     if (aux && aux->asn1_cb)
@@ -240,72 +232,19 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
         ef = it->funcs;
         return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx);
 
-    case ASN1_ITYPE_COMPAT:
-        /* we must resort to old style evil hackery */
-        cf = it->funcs;
-
-        /* If OPTIONAL see if it is there */
-        if (opt) {
-            int exptag;
-            p = *in;
-            if (tag == -1)
-                exptag = it->utype;
-            else
-                exptag = tag;
-            /*
-             * Don't care about anything other than presence of expected tag
-             */
-
-            ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL,
-                                  &p, len, exptag, aclass, 1, ctx);
-            if (!ret) {
-                ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
-                goto err;
-            }
-            if (ret == -1)
-                return -1;
-        }
-
-        /*
-         * This is the old style evil hack IMPLICIT handling: since the
-         * underlying code is expecting a tag and class other than the one
-         * present we change the buffer temporarily then change it back
-         * afterwards. This doesn't and never did work for tags > 30. Yes
-         * this is *horrible* but it is only needed for old style d2i which
-         * will hopefully not be around for much longer. FIXME: should copy
-         * the buffer then modify it so the input buffer can be const: we
-         * should *always* copy because the old style d2i might modify the
-         * buffer.
-         */
-
-        if (tag != -1) {
-            wp = *(unsigned char **)in;
-            imphack = *wp;
-            if (p == NULL) {
-                ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
-                goto err;
-            }
-            *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED)
-                                  | it->utype);
-        }
-
-        ptmpval = cf->asn1_d2i(pval, in, len);
-
-        if (tag != -1)
-            *wp = imphack;
-
-        if (ptmpval)
-            return 1;
-
-        ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
-        goto err;
-
     case ASN1_ITYPE_CHOICE:
         if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL))
             goto auxerr;
-
-        /* Allocate structure */
-        if (!*pval && !ASN1_item_ex_new(pval, it)) {
+        if (*pval) {
+            /* Free up and zero CHOICE value if initialised */
+            i = asn1_get_choice_selector(pval, it);
+            if ((i >= 0) && (i < it->tcount)) {
+                tt = it->templates + i;
+                pchptr = asn1_get_field_ptr(pval, tt);
+                asn1_template_free(pchptr, tt);
+                asn1_set_choice_selector(pval, -1, it);
+            }
+        } else if (!ASN1_item_ex_new(pval, it)) {
             ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
             goto err;
         }
@@ -385,6 +324,17 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
         if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL))
             goto auxerr;
 
+        /* Free up and zero any ADB found */
+        for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
+            if (tt->flags & ASN1_TFLG_ADB_MASK) {
+                const ASN1_TEMPLATE *seqtt;
+                ASN1_VALUE **pseqval;
+                seqtt = asn1_do_adb(pval, tt, 1);
+                pseqval = asn1_get_field_ptr(pval, seqtt);
+                asn1_template_free(pseqval, seqtt);
+            }
+        }
+
         /* Get each field entry */
         for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
             const ASN1_TEMPLATE *seqtt;
@@ -429,7 +379,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
                 /*
                  * OPTIONAL component absent. Free and zero the field.
                  */
-                ASN1_template_free(pseqval, seqtt);
+                asn1_template_free(pseqval, seqtt);
                 continue;
             }
             /* Update length */
@@ -460,7 +410,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
             if (seqtt->flags & ASN1_TFLG_OPTIONAL) {
                 ASN1_VALUE **pseqval;
                 pseqval = asn1_get_field_ptr(pval, seqtt);
-                ASN1_template_free(pseqval, seqtt);
+                asn1_template_free(pseqval, seqtt);
             } else {
                 errtt = seqtt;
                 ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_FIELD_MISSING);
@@ -563,7 +513,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
     return 1;
 
  err:
-    ASN1_template_free(val, tt);
+    asn1_template_free(val, tt);
     return 0;
 }
 
@@ -682,7 +632,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
     return 1;
 
  err:
-    ASN1_template_free(val, tt);
+    asn1_template_free(val, tt);
     return 0;
 }
 
@@ -695,7 +645,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
     long plen;
     char cst, inf, free_cont = 0;
     const unsigned char *p;
-    BUF_MEM buf;
+    BUF_MEM buf = { 0 };
     const unsigned char *cont = NULL;
     long len;
     if (!pval) {
@@ -815,15 +765,15 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
     *in = p;
     ret = 1;
  err:
-    if (free_cont && buf.data)
+    if (free_cont)
         OPENSSL_free(buf.data);
     return ret;
 }
 
 /* Translate ASN1 content octets into a structure */
 
-int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
-                int utype, char *free_cont, const ASN1_ITEM *it)
+static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+                       int utype, char *free_cont, const ASN1_ITEM *it)
 {
     ASN1_VALUE **opval = NULL;
     ASN1_STRING *stmp;
@@ -932,8 +882,7 @@ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
         }
         /* If we've already allocated a buffer use it */
         if (*free_cont) {
-            if (stmp->data)
-                OPENSSL_free(stmp->data);
+            OPENSSL_free(stmp->data);
             stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */
             stmp->length = len;
             *free_cont = 0;