Constify d2i, s2i, c2i and r2i functions and other associated
[openssl.git] / crypto / asn1 / tasn_dec.c
index 7237f7e..aa26a44 100644 (file)
 #include <openssl/buffer.h>
 #include <openssl/err.h>
 
-static int asn1_check_eoc(unsigned char **in, long len);
-static int asn1_collect(BUF_MEM *buf, unsigned char **in, long len, char inf, int tag, int aclass);
-static int collect_data(BUF_MEM *buf, unsigned char **p, long plen);
+static int asn1_check_eoc(const unsigned char **in, long len);
+static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass);
+static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen);
 static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst,
-                       unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx);
-static int asn1_template_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
-static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
-static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long len,
+                       const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx);
+static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
+static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
+static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long len,
                                        const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx);
 
+/* Table to convert tags to bit values, used for MSTRING type */
+static unsigned long tag2bit[32]={
+0,     0,      0,      B_ASN1_BIT_STRING,      /* tags  0 -  3 */
+B_ASN1_OCTET_STRING,   0,      0,              B_ASN1_UNKNOWN,/* tags  4- 7 */
+B_ASN1_UNKNOWN,        B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags  8-11 */
+B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */
+0,     0,      B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING,   /* tags 16-19 */
+B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING,       /* tags 20-22 */
+B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME,                               /* tags 23-24 */ 
+B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING,  /* tags 25-27 */
+B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */
+       };
+
+unsigned long ASN1_tag2bit(int tag)
+{
+       if((tag < 0) || (tag > 30)) return 0;
+       return tag2bit[tag];
+}
+
 /* Macro to initialize and invalidate the cache */
 
 #define asn1_tlc_clear(c)      if(c) (c)->valid = 0
@@ -87,7 +106,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long len
  * case.
  */
 
-ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_ITEM *it)
+ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it)
 {
        ASN1_TLC c;
        ASN1_VALUE *ptmpval = NULL;
@@ -98,7 +117,7 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const
        return NULL;
 }
 
-int ASN1_template_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_TEMPLATE *tt)
+int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt)
 {
        ASN1_TLC c;
        asn1_tlc_clear(&c);
@@ -110,7 +129,7 @@ int ASN1_template_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN
  * If 'opt' set and tag mismatch return -1 to handle OPTIONAL
  */
 
-int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_ITEM *it,
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it,
                                int tag, int aclass, char opt, ASN1_TLC *ctx)
 {
        const ASN1_TEMPLATE *tt, *errtt = NULL;
@@ -118,7 +137,9 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1
        const ASN1_EXTERN_FUNCS *ef;
        const ASN1_AUX *aux = it->funcs;
        ASN1_aux_cb *asn1_cb;
-       unsigned char *p, *q, imphack = 0, oclass;
+       const unsigned char *p, *q;
+       unsigned char *wp=NULL; /* BIG FAT WARNING!  BREAKS CONST WHERE USED */
+       unsigned char imphack = 0, oclass;
        char seq_eoc, seq_nolen, cst, isopt;
        long tmplen;
        int i;
@@ -210,14 +231,14 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1
                 */
 
                if(tag != -1) {
-                       p = *in;
-                       imphack = *p;
-                       *p = (unsigned char)((*p & V_ASN1_CONSTRUCTED) | it->utype);
+                       wp = *(unsigned char **)in;
+                       imphack = *wp;
+                       *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED) | it->utype);
                }
 
                ptmpval = cf->asn1_d2i(pval, in, len);
 
-               if(tag != -1) *p = imphack;
+               if(tag != -1) *wp = imphack;
 
                if(ptmpval) return 1;
                ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
@@ -270,6 +291,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1
                                goto auxerr;
                return 1;
 
+               case ASN1_ITYPE_NDEF_SEQUENCE:
                case ASN1_ITYPE_SEQUENCE:
                p = *in;
                tmplen = len;
@@ -396,12 +418,12 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1
  * rest.
  */
 
-int asn1_template_ex_d2i(ASN1_VALUE **val, unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
+static int asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
 {
        int flags, aclass;
        int ret;
        long len;
-       unsigned char *p, *q;
+       const unsigned char *p, *q;
        char exp_eoc;
        if(!val) return 0;
        flags = tt->flags;
@@ -458,11 +480,11 @@ int asn1_template_ex_d2i(ASN1_VALUE **val, unsigned char **in, long inlen, const
        return 0;
 }
 
-static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
+static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
 {
        int flags, aclass;
        int ret;
-       unsigned char *p, *q;
+       const unsigned char *p, *q;
        if(!val) return 0;
        flags = tt->flags;
        aclass = flags & ASN1_TFLG_TAG_CLASS;
@@ -558,16 +580,16 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long le
        return 0;
 }
 
-static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long inlen, 
+static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, 
                                                const ASN1_ITEM *it,
                                                int tag, int aclass, char opt, ASN1_TLC *ctx)
 {
        int ret = 0, utype;
        long plen;
        char cst, inf, free_cont = 0;
-       unsigned char *p;
+       const unsigned char *p;
        BUF_MEM buf;
-       unsigned char *cont = NULL;
+       const unsigned char *cont = NULL;
        long len; 
        if(!pval) {
                ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL);
@@ -611,8 +633,13 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long inl
        } else if(ret == -1) return -1;
        /* SEQUENCE, SET and "OTHER" are left in encoded form */
        if((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) {
+               /* Clear context cache for type OTHER because the auto clear when
+                * we have a exact match wont work
+                */
+               if(utype == V_ASN1_OTHER) {
+                       asn1_tlc_clear(ctx);
                /* SEQUENCE and SET must be constructed */
-               if((utype != V_ASN1_OTHER) && !cst) {
+               } else if(!cst) {
                        ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_CONSTRUCTED);
                        return 0;
                }
@@ -640,12 +667,12 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long inl
                if(!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL)) goto err;
                len = buf.length;
                /* Append a final null to string */
-               if(!BUF_MEM_grow(&buf, len + 1)) {
+               if(!BUF_MEM_grow_clean(&buf, len + 1)) {
                        ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE);
                        return 0;
                }
                buf.data[len] = 0;
-               cont = (unsigned char *)buf.data;
+               cont = (const unsigned char *)buf.data;
                free_cont = 1;
        } else {
                cont = p;
@@ -665,8 +692,9 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long inl
 
 /* Translate ASN1 content octets into a structure */
 
-int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it)
+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;
        ASN1_TYPE *typ = NULL;
        int ret = 0;
@@ -681,6 +709,7 @@ int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char
                        *pval = (ASN1_VALUE *)typ;
                } else typ = (ASN1_TYPE *)*pval;
                if(utype != typ->type) ASN1_TYPE_set(typ, utype, NULL);
+               opval = pval;
                pval = (ASN1_VALUE **)&typ->value.ptr;
        }
        switch(utype) {
@@ -754,7 +783,7 @@ int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char
                /* If we've already allocated a buffer use it */
                if(*free_cont) {
                        if(stmp->data) OPENSSL_free(stmp->data);
-                       stmp->data = cont;
+                       stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */
                        stmp->length = len;
                        *free_cont = 0;
                } else {
@@ -772,7 +801,12 @@ int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char
 
        ret = 1;
        err:
-       if(!ret) ASN1_TYPE_free(typ);
+       if(!ret)
+               {
+               ASN1_TYPE_free(typ);
+               if (opval)
+                       *opval = NULL;
+               }
        return ret;
 }
 
@@ -784,9 +818,9 @@ int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char
  * length constructed stuff.
  */
 
-static int asn1_collect(BUF_MEM *buf, unsigned char **in, long len, char inf, int tag, int aclass)
+static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, char inf, int tag, int aclass)
 {
-       unsigned char *p, *q;
+       const unsigned char *p, *q;
        long plen;
        char cst, ininf;
        p = *in;
@@ -828,12 +862,12 @@ static int asn1_collect(BUF_MEM *buf, unsigned char **in, long len, char inf, in
        return 1;
 }
 
-static int collect_data(BUF_MEM *buf, unsigned char **p, long plen)
+static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen)
 {
                int len;
                if(buf) {
                        len = buf->length;
-                       if(!BUF_MEM_grow(buf, len + plen)) {
+                       if(!BUF_MEM_grow_clean(buf, len + plen)) {
                                ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE);
                                return 0;
                        }
@@ -845,9 +879,9 @@ static int collect_data(BUF_MEM *buf, unsigned char **p, long plen)
 
 /* Check for ASN1 EOC and swallow it if found */
 
-static int asn1_check_eoc(unsigned char **in, long len)
+static int asn1_check_eoc(const unsigned char **in, long len)
 {
-       unsigned char *p;
+       const unsigned char *p;
        if(len < 2) return 0;
        p = *in;
        if(!p[0] && !p[1]) {
@@ -865,12 +899,12 @@ static int asn1_check_eoc(unsigned char **in, long len)
  */
 
 static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst,
-               unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx)
+               const unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx)
 {
        int i;
        int ptag, pclass;
        long plen;
-       unsigned char *p, *q;
+       const unsigned char *p, *q;
        p = *in;
        q = p;
 
@@ -889,17 +923,17 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *i
                        ctx->ptag = ptag;
                        ctx->hdrlen = p - q;
                        ctx->valid = 1;
-                       /* If definite length, length + header can't exceed total
-                        * amount of data available.
+                       /* If definite length, and no error, length +
+                        * header can't exceed total amount of data available. 
                         */
-                       if(!(i & 1) && ((plen + ctx->hdrlen) > len)) {
+                       if(!(i & 0x81) && ((plen + ctx->hdrlen) > len)) {
                                ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG);
                                asn1_tlc_clear(ctx);
                                return 0;
                        }
                }
        }
-               
+
        if(i & 0x80) {
                ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER);
                asn1_tlc_clear(ctx);