Preliminary streaming ASN1 encode support.
authorDr. Stephen Henson <steve@openssl.org>
Thu, 3 Oct 2002 12:38:52 +0000 (12:38 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 3 Oct 2002 12:38:52 +0000 (12:38 +0000)
CHANGES
crypto/asn1/asn1.h
crypto/asn1/asn1_lib.c
crypto/asn1/asn1t.h
crypto/asn1/tasn_dec.c
crypto/asn1/tasn_enc.c
crypto/asn1/tasn_fre.c
crypto/asn1/tasn_new.c
crypto/asn1/tasn_typ.c
crypto/asn1/tasn_utl.c
crypto/pkcs7/pk7_asn1.c

diff --git a/CHANGES b/CHANGES
index feba220..ef7d1b5 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,17 @@
 
  Changes between 0.9.7 and 0.9.8  [xx XXX 2002]
 
+  *) Extend ASN1 encoder to support indefinite length constructed
+     encoding. This can output sequences tags and octet strings in
+     this form. Modify pk7_asn1.c to support indefinite length
+     encoding. This is experimental and needs additional code to
+     be useful, such as an ASN1 bio and some enhanced streaming
+     PKCS#7 code.
+
+     Extend template encode functionality so that tagging is passed
+     down to the template encoder.
+     [Steve Henson]
+
   *) Let 'openssl req' fail if an argument to '-newkey' is not
      recognized instead of using RSA as a default.
      [Bodo Moeller]
index 1be3e02..e870948 100644 (file)
@@ -192,6 +192,11 @@ typedef struct asn1_object_st
        } ASN1_OBJECT;
 
 #define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */
+/* This indicates that the ASN1_STRING is not a real value but just a place
+ * holder for the location where indefinite length constructed data should
+ * be inserted in the memory buffer 
+ */
+#define ASN1_STRING_FLAG_NDEF 0x010 
 /* This is the base type that holds just about everything :-) */
 typedef struct asn1_string_st
        {
@@ -280,6 +285,9 @@ typedef struct ASN1_VALUE_st ASN1_VALUE;
        int i2d_##name(const type *a, unsigned char **out); \
        DECLARE_ASN1_ITEM(name)
 
+#define        DECLARE_ASN1_NDEF_FUNCTION(name) \
+       int i2d_##name##_NDEF(name *a, unsigned char **out);
+
 #define DECLARE_ASN1_FUNCTIONS_const(name) \
        name *name##_new(void); \
        void name##_free(name *a);
@@ -793,6 +801,8 @@ DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
 DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
 DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
 
+DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF)
+
 ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t);
 int ASN1_TIME_check(ASN1_TIME *t);
 ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out);
@@ -849,6 +859,7 @@ int ASN1_get_object(unsigned char **pp, long *plength, int *ptag,
 int ASN1_check_infinite_end(unsigned char **p,long len);
 void ASN1_put_object(unsigned char **pp, int constructed, int length,
        int tag, int xclass);
+int ASN1_put_eoc(unsigned char **pp);
 int ASN1_object_size(int constructed, int length, int tag);
 
 /* Used to implement other functions */
@@ -935,6 +946,7 @@ ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
 void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
 ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_ITEM *it);
 int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
+int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
 
 void ASN1_add_oid_module(void);
 
index 0638870..3f7b3aa 100644 (file)
@@ -203,13 +203,22 @@ void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
                        }
                p += ttag;
                }
-       if ((constructed == 2) && (length == 0))
-               *(p++)=0x80; /* der_put_length would output 0 instead */
+       if (constructed == 2)
+               *(p++)=0x80;
        else
                asn1_put_length(&p,length);
        *pp=p;
        }
 
+int ASN1_put_eoc(unsigned char **pp)
+       {
+       unsigned char *p = *pp;
+       *p++ = 0;
+       *p++ = 0;
+       *pp = p;
+       return 2;
+       }
+
 static void asn1_put_length(unsigned char **pp, int length)
        {
        unsigned char *p= *pp;
@@ -247,8 +256,8 @@ int ASN1_object_size(int constructed, int length, int tag)
                        ret++;
                        }
                }
-       if ((length == 0) && (constructed == 2))
-               ret+=2;
+       if (constructed == 2)
+               return ret + 3;
        ret++;
        if (length > 127)
                {
index ed372f8..83e8213 100644 (file)
@@ -166,6 +166,9 @@ extern "C" {
                #stname \
        ASN1_ITEM_end(tname)
 
+#define ASN1_NDEF_SEQUENCE(tname) \
+       ASN1_SEQUENCE(tname)
+
 #define ASN1_SEQUENCE_cb(tname, cb) \
        const static ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
        ASN1_SEQUENCE(tname)
@@ -182,6 +185,18 @@ extern "C" {
        const static ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc)}; \
        ASN1_SEQUENCE(tname)
 
+#define ASN1_NDEF_SEQUENCE_END(tname) \
+       ;\
+       ASN1_ITEM_start(tname) \
+               ASN1_ITYPE_NDEF_SEQUENCE,\
+               V_ASN1_SEQUENCE,\
+               tname##_seq_tt,\
+               sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+               NULL,\
+               sizeof(tname),\
+               #tname \
+       ASN1_ITEM_end(tname)
+
 #define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname)
 
 #define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
@@ -353,6 +368,10 @@ extern "C" {
 #define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \
                        ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
 
+/* EXPLICIT OPTIONAL using indefinite length constructed form */
+#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \
+                       ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF)
+
 /* Macros for the ASN1_ADB structure */
 
 #define ASN1_ADB(name) \
@@ -518,6 +537,13 @@ struct ASN1_ADB_TABLE_st {
 
 #define ASN1_TFLG_COMBINE      (0x1<<10)
 
+/* This flag when present in a SEQUENCE OF, SET OF
+ * or EXPLICIT causes indefinite length constructed
+ * encoding to be used if required.
+ */
+
+#define ASN1_TFLG_NDEF         (0x1<<11)
+
 /* This is the actual ASN1 item itself */
 
 struct ASN1_ITEM_st {
@@ -570,19 +596,25 @@ const char *sname;                /* Structure name */
  * has a special meaning, it is used as a mask
  * of acceptable types using the B_ASN1 constants.
  *
+ * NDEF_SEQUENCE is the same as SEQUENCE except
+ * that it will use indefinite length constructed
+ * encoding if requested.
+ *
  */
 
-#define ASN1_ITYPE_PRIMITIVE   0x0
+#define ASN1_ITYPE_PRIMITIVE           0x0
+
+#define ASN1_ITYPE_SEQUENCE            0x1
 
-#define ASN1_ITYPE_SEQUENCE    0x1
+#define ASN1_ITYPE_CHOICE              0x2
 
-#define ASN1_ITYPE_CHOICE      0x2
+#define ASN1_ITYPE_COMPAT              0x3
 
-#define ASN1_ITYPE_COMPAT      0x3
+#define ASN1_ITYPE_EXTERN              0x4
 
-#define ASN1_ITYPE_EXTERN      0x4
+#define ASN1_ITYPE_MSTRING             0x5
 
-#define ASN1_ITYPE_MSTRING     0x5
+#define ASN1_ITYPE_NDEF_SEQUENCE       0x6
 
 /* Cache for ASN1 tag and length, so we
  * don't keep re-reading it for things
@@ -767,6 +799,12 @@ typedef struct ASN1_AUX_st {
                return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
        } 
 
+#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \
+       int i2d_##stname##_NDEF(stname *a, unsigned char **out) \
+       { \
+               return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\
+       } 
+
 /* This includes evil casts to remove const: they will go away when full
  * ASN1 constification is done.
  */
index f87c087..a9b1d9e 100644 (file)
@@ -289,6 +289,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;
index f6c8dde..33d6366 100644 (file)
@@ -3,7 +3,7 @@
  * project 2000.
  */
 /* ====================================================================
- * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 2000-2002 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <openssl/asn1t.h>
 #include <openssl/objects.h>
 
-static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
-static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *seq, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int isset);
+static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
+                                       const ASN1_ITEM *it,
+                                       int tag, int aclass);
+static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
+                                       int skcontlen, const ASN1_ITEM *item,
+                                       int do_sort, int iclass);
+static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
+                                       const ASN1_TEMPLATE *tt,
+                                       int tag, int aclass);
+static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
+                                       const ASN1_ITEM *it, int flags);
+
+/* Top level i2d equivalents: the 'ndef' variant instructs the encoder
+ * to use indefinite length constructed encoding, where appropriate
+ */
+
+int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
+{
+       return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF);
+}
 
-/* Encode an ASN1 item, this is compatible with the
+int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
+{
+       return asn1_item_flags_i2d(val, out, it, 0);
+}
+
+/* Encode an ASN1 item, this is use by the
  * standard 'i2d' function. 'out' points to 
- * a buffer to output the data to, in future we will
- * have more advanced versions that can output data
- * a piece at a time and this will simply be a special
- * case.
+ * a buffer to output the data to.
  *
  * The new i2d has one additional feature. If the output
  * buffer is NULL (i.e. *out == NULL) then a buffer is
  * allocated and populated with the encoding.
  */
 
-
-int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
+static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it, int flags)
 {
        if(out && !*out) {
                unsigned char *p, *buf;
                int len;
-               len = ASN1_item_ex_i2d(&val, NULL, it, -1, 0);
+               len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
                if(len <= 0) return len;
                buf = OPENSSL_malloc(len);
                if(!buf) return -1;
                p = buf;
-               ASN1_item_ex_i2d(&val, &p, it, -1, 0);
+               ASN1_item_ex_i2d(&val, &p, it, -1, flags);
                *out = buf;
                return len;
        }
-               
-       return ASN1_item_ex_i2d(&val, out, it, -1, 0);
+
+       return ASN1_item_ex_i2d(&val, out, it, -1, flags);
 }
 
 /* Encode an item, taking care of IMPLICIT tagging (if any).
@@ -102,31 +121,34 @@ int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
  * used in external types.
  */
 
-int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass)
+int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
+                       const ASN1_ITEM *it, int tag, int aclass)
 {
        const ASN1_TEMPLATE *tt = NULL;
        unsigned char *p = NULL;
-       int i, seqcontlen, seqlen;
-       ASN1_STRING *strtmp;
+       int i, seqcontlen, seqlen, ndef = 1;
        const ASN1_COMPAT_FUNCS *cf;
        const ASN1_EXTERN_FUNCS *ef;
        const ASN1_AUX *aux = it->funcs;
-       ASN1_aux_cb *asn1_cb;
-       if((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) return 0;
-       if(aux && aux->asn1_cb) asn1_cb = aux->asn1_cb;
-       else asn1_cb = 0;
+       ASN1_aux_cb *asn1_cb = 0;
+
+       if((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval)
+               return 0;
+
+       if(aux && aux->asn1_cb)
+                asn1_cb = aux->asn1_cb;
 
        switch(it->itype) {
 
                case ASN1_ITYPE_PRIMITIVE:
                if(it->templates)
-                       return ASN1_template_i2d(pval, out, it->templates);
+                       return asn1_template_ex_i2d(pval, out, it->templates,
+                                                               tag, aclass);
                return asn1_i2d_ex_primitive(pval, out, it, tag, aclass);
                break;
 
                case ASN1_ITYPE_MSTRING:
-               strtmp = (ASN1_STRING *)*pval;
-               return asn1_i2d_ex_primitive(pval, out, it, -1, 0);
+               return asn1_i2d_ex_primitive(pval, out, it, -1, aclass);
 
                case ASN1_ITYPE_CHOICE:
                if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it))
@@ -137,7 +159,8 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it
                        const ASN1_TEMPLATE *chtt;
                        chtt = it->templates + i;
                        pchval = asn1_get_field_ptr(pval, chtt);
-                       return ASN1_template_i2d(pchval, out, chtt);
+                       return asn1_template_ex_i2d(pchval, out, chtt,
+                                                               -1, aclass);
                } 
                /* Fixme: error condition if selector out of range */
                if(asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it))
@@ -161,6 +184,12 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it
                        *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED);
                return i;
                
+               case ASN1_ITYPE_NDEF_SEQUENCE:
+//fprintf(stderr, "NDEF sequence from %s flags %d\n", it->sname, aclass & ASN1_TFLG_NDEF);
+               /* Use indefinite length constructed if requested */
+               if (aclass & ASN1_TFLG_NDEF) ndef = 2;
+               /* fall through */
+
                case ASN1_ITYPE_SEQUENCE:
                i = asn1_enc_restore(&seqcontlen, out, pval, it);
                /* An error occurred */
@@ -172,7 +201,9 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it
                /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
                if(tag == -1) {
                        tag = V_ASN1_SEQUENCE;
-                       aclass = V_ASN1_UNIVERSAL;
+                       /* Retain any other flags in aclass */
+                       aclass = (aclass & ~ASN1_TFLG_TAG_CLASS)
+                                       | V_ASN1_UNIVERSAL;
                }
                if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it))
                                return 0;
@@ -184,13 +215,13 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it
                        if(!seqtt) return 0;
                        pseqval = asn1_get_field_ptr(pval, seqtt);
                        /* FIXME: check for errors in enhanced version */
-                       /* FIXME: special handling of indefinite length encoding */
-                       seqcontlen += ASN1_template_i2d(pseqval, NULL, seqtt);
+                       seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt,
+                                                               -1, aclass);
                }
-               seqlen = ASN1_object_size(1, seqcontlen, tag);
+               seqlen = ASN1_object_size(ndef, seqcontlen, tag);
                if(!out) return seqlen;
                /* Output SEQUENCE header */
-               ASN1_put_object(out, 1, seqcontlen, tag, aclass);
+               ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
                for(i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
                        const ASN1_TEMPLATE *seqtt;
                        ASN1_VALUE **pseqval;
@@ -198,8 +229,9 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it
                        if(!seqtt) return 0;
                        pseqval = asn1_get_field_ptr(pval, seqtt);
                        /* FIXME: check for errors in enhanced version */
-                       ASN1_template_i2d(pseqval, out, seqtt);
+                       asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass);
                }
+               if (ndef == 2) ASN1_put_eoc(out);
                if(asn1_cb  && !asn1_cb(ASN1_OP_I2D_POST, pval, it))
                                return 0;
                return seqlen;
@@ -210,42 +242,91 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it
        return 0;
 }
 
-int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt)
+static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt, int tag, int iclass)
 {
-       int i, ret, flags, aclass;
+       int i, ret, flags, ttag, tclass, ndef;
        flags = tt->flags;
-       aclass = flags & ASN1_TFLG_TAG_CLASS;
+       /* Work out tag and class to use: tagging may come
+        * either from the template or the arguments, not both
+        * because this would create ambiguity. Additionally
+        * the iclass argument may contain some additional flags
+        * which should be noted and passed down to other levels.
+        */
+       if (flags & ASN1_TFLG_TAG_MASK)
+               {
+               /* Error if argument and template tagging */
+               if (tag != -1)
+                       /* FIXME: error code here */
+                       return -1;
+               /* Get tagging from template */
+               ttag = tt->tag;
+               tclass = flags & ASN1_TFLG_TAG_CLASS;
+               }
+       else if (tag != -1)
+               {
+               /* No template tagging, get from arguments */
+               ttag = tag;
+               tclass = iclass & ASN1_TFLG_TAG_CLASS;
+               }
+       else
+               {
+               ttag = -1;
+               tclass = 0;
+               }
+       /* 
+        * Remove any class mask from iflag.
+        */
+       iclass &= ~ASN1_TFLG_TAG_CLASS;
+
+       /* At this point 'ttag' contains the outer tag to use,
+        * 'tclass' is the class and iclass is any flags passed
+        * to this function.
+        */
+
+       /* if template and arguments require ndef, use it */
+       if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF))
+               ndef = 2;
+       else ndef = 1;
+
        if(flags & ASN1_TFLG_SK_MASK) {
                /* SET OF, SEQUENCE OF */
                STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
                int isset, sktag, skaclass;
                int skcontlen, sklen;
                ASN1_VALUE *skitem;
+
                if(!*pval) return 0;
+
                if(flags & ASN1_TFLG_SET_OF) {
                        isset = 1;
                        /* 2 means we reorder */
                        if(flags & ASN1_TFLG_SEQUENCE_OF) isset = 2;
                } else isset = 0;
-               /* First work out inner tag value */
-               if(flags & ASN1_TFLG_IMPTAG) {
-                       sktag = tt->tag;
-                       skaclass = aclass;
+
+               /* Work out inner tag value: if EXPLICIT
+                * or no tagging use underlying type.
+                */
+               if((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) {
+                       sktag = ttag;
+                       skaclass = tclass;
                } else {
                        skaclass = V_ASN1_UNIVERSAL;
                        if(isset) sktag = V_ASN1_SET;
                        else sktag = V_ASN1_SEQUENCE;
                }
-               /* Now work out length of items */
+
+               /* Determine total length of items */
                skcontlen = 0;
                for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
                        skitem = sk_ASN1_VALUE_value(sk, i);
-                       skcontlen += ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), -1, 0);
+                       skcontlen += ASN1_item_ex_i2d(&skitem, NULL,
+                                                       ASN1_ITEM_ptr(tt->item),
+                                                       -1, iclass);
                }
-               sklen = ASN1_object_size(1, skcontlen, sktag);
+               sklen = ASN1_object_size(ndef, skcontlen, sktag);
                /* If EXPLICIT need length of surrounding tag */
                if(flags & ASN1_TFLG_EXPTAG)
-                       ret = ASN1_object_size(1, sklen, tt->tag);
+                       ret = ASN1_object_size(ndef, sklen, ttag);
                else ret = sklen;
 
                if(!out) return ret;
@@ -253,35 +334,43 @@ int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLAT
                /* Now encode this lot... */
                /* EXPLICIT tag */
                if(flags & ASN1_TFLG_EXPTAG)
-                       ASN1_put_object(out, 1, sklen, tt->tag, aclass);
+                       ASN1_put_object(out, ndef, sklen, ttag, tclass);
                /* SET or SEQUENCE and IMPLICIT tag */
-               ASN1_put_object(out, 1, skcontlen, sktag, skaclass);
-               /* And finally the stuff itself */
-               asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), isset);
+               ASN1_put_object(out, ndef, skcontlen, sktag, skaclass);
+               /* And the stuff itself */
+               asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item),
+                                                               isset, iclass);
+               if (ndef == 2) {
+                       ASN1_put_eoc(out);
+                       if(flags & ASN1_TFLG_EXPTAG)
+                               ASN1_put_eoc(out);
+               }
 
                return ret;
        }
-                       
+
        if(flags & ASN1_TFLG_EXPTAG) {
                /* EXPLICIT tagging */
                /* Find length of tagged item */
-               i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, 0);
+               i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item),
+                                                               -1, iclass);
                if(!i) return 0;
                /* Find length of EXPLICIT tag */
-               ret = ASN1_object_size(1, i, tt->tag);
+               ret = ASN1_object_size(ndef, i, ttag);
                if(out) {
                        /* Output tag and item */
-                       ASN1_put_object(out, 1, i, tt->tag, aclass);
-                       ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, 0);
+                       ASN1_put_object(out, ndef, i, ttag, tclass);
+                       ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
+                                                               -1, iclass);
+                       if (ndef == 2) ASN1_put_eoc(out);
                }
                return ret;
        }
-       if(flags & ASN1_TFLG_IMPTAG) {
-               /* IMPLICIT tagging */
-               return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), tt->tag, aclass);
-       }
-       /* Nothing special: treat as normal */
-       return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, 0);
+
+       /* Either normal or IMPLICIT tagging: combine class and flags */
+       return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
+                                               ttag, tclass | iclass);
+
 }
 
 /* Temporary structure used to hold DER encoding of items for SET OF */
@@ -304,7 +393,9 @@ static int der_cmp(const void *a, const void *b)
 
 /* Output the content octets of SET OF or SEQUENCE OF */
 
-static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int do_sort)
+static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
+                                       int skcontlen, const ASN1_ITEM *item,
+                                       int do_sort, int iclass)
 {
        int i;
        ASN1_VALUE *skitem;
@@ -323,7 +414,7 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, int s
        if(!do_sort) {
                for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
                        skitem = sk_ASN1_VALUE_value(sk, i);
-                       ASN1_item_i2d(skitem, out, item);
+                       ASN1_item_ex_i2d(&skitem, out, item, -1, iclass);
                }
                return 1;
        }
@@ -332,7 +423,7 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, int s
        for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
                skitem = sk_ASN1_VALUE_value(sk, i);
                tder->data = p;
-               tder->length = ASN1_item_i2d(skitem, &p, item);
+               tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass);
                tder->field = skitem;
        }
        /* Now sort them */
@@ -359,6 +450,7 @@ static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const A
        int len;
        int utype;
        int usetag;
+       int ndef = 0;
 
        utype = it->utype;
 
@@ -381,19 +473,27 @@ static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const A
 
        /* -1 means omit type */
 
-       if(len == -1) return 0;
+       if(len == -1)
+               return 0;
+
+       /* -2 return is special meaning use ndef */
+       if (len == -2)
+               {
+               ndef = 2;
+               len = 0;
+               }
 
        /* If not implicitly tagged get tag from underlying type */
        if(tag == -1) tag = utype;
 
        /* Output tag+length followed by content octets */
        if(out) {
-               if(usetag) ASN1_put_object(out, 0, len, tag, aclass);
+               if(usetag) ASN1_put_object(out, ndef, len, tag, aclass);
                asn1_ex_i2c(pval, *out, &utype, it);
                *out += len;
        }
 
-       if(usetag) return ASN1_object_size(0, len, tag);
+       if(usetag) return ASN1_object_size(ndef, len, tag);
        return len;
 }
 
@@ -486,6 +586,19 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_
                default:
                /* All based on ASN1_STRING and handled the same */
                strtmp = (ASN1_STRING *)*pval;
+               /* Special handling for NDEF */
+               if ((it->size == ASN1_TFLG_NDEF)
+                       && (strtmp->flags & ASN1_STRING_FLAG_NDEF))
+                       {
+                       if (cout)
+                               {
+                               strtmp->data = cout;
+                               strtmp->length = 0;
+                               ASN1_put_eoc(&cout);
+                               }
+                       /* Special return code */
+                       return -2;
+                       }
                cont = strtmp->data;
                len = strtmp->length;
 
index c761077..910f9b4 100644 (file)
@@ -130,6 +130,7 @@ static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int c
                if(ef && ef->asn1_ex_free) ef->asn1_ex_free(pval, it);
                break;
 
+               case ASN1_ITYPE_NDEF_SEQUENCE:
                case ASN1_ITYPE_SEQUENCE:
                if(asn1_do_lock(pval, -1, it) > 0) return;
                if(asn1_cb) {
index e33861f..11a90f7 100644 (file)
@@ -155,6 +155,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int
                                goto auxerr;
                break;
 
+               case ASN1_ITYPE_NDEF_SEQUENCE:
                case ASN1_ITYPE_SEQUENCE:
                if(asn1_cb) {
                        i = asn1_cb(ASN1_OP_NEW_PRE, pval, it);
@@ -231,6 +232,7 @@ static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
                case ASN1_ITYPE_COMPAT:
                case ASN1_ITYPE_CHOICE:
                case ASN1_ITYPE_SEQUENCE:
+               case ASN1_ITYPE_NDEF_SEQUENCE:
                *pval = NULL;
                break;
        }
index 804d2ee..6f17f1b 100644 (file)
@@ -131,3 +131,7 @@ IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
 IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1)
 IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1)
 IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0)
+
+/* Special, OCTET STRING with indefinite length constructed support */
+
+IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, ASN1_TFLG_NDEF)
index 8996ce8..2a3f5db 100644 (file)
@@ -102,7 +102,8 @@ int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it)
 {
        const ASN1_AUX *aux;
        int *lck, ret;
-       if(it->itype != ASN1_ITYPE_SEQUENCE) return 0;
+       if((it->itype != ASN1_ITYPE_SEQUENCE)
+          && (it->itype != ASN1_ITYPE_NDEF_SEQUENCE)) return 0;
        aux = it->funcs;
        if(!aux || !(aux->flags & ASN1_AFLG_REFCOUNT)) return 0;
        lck = offset2ptr(*pval, aux->ref_offset);
index 46f0fc9..77931fe 100644 (file)
 ASN1_ADB_TEMPLATE(p7default) = ASN1_EXP_OPT(PKCS7, d.other, ASN1_ANY, 0);
 
 ASN1_ADB(PKCS7) = {
-       ADB_ENTRY(NID_pkcs7_data, ASN1_EXP_OPT(PKCS7, d.data, ASN1_OCTET_STRING, 0)),
-       ADB_ENTRY(NID_pkcs7_signed, ASN1_EXP_OPT(PKCS7, d.sign, PKCS7_SIGNED, 0)),
-       ADB_ENTRY(NID_pkcs7_enveloped, ASN1_EXP_OPT(PKCS7, d.enveloped, PKCS7_ENVELOPE, 0)),
-       ADB_ENTRY(NID_pkcs7_signedAndEnveloped, ASN1_EXP_OPT(PKCS7, d.signed_and_enveloped, PKCS7_SIGN_ENVELOPE, 0)),
-       ADB_ENTRY(NID_pkcs7_digest, ASN1_EXP_OPT(PKCS7, d.digest, PKCS7_DIGEST, 0)),
-       ADB_ENTRY(NID_pkcs7_encrypted, ASN1_EXP_OPT(PKCS7, d.encrypted, PKCS7_ENCRYPT, 0))
+       ADB_ENTRY(NID_pkcs7_data, ASN1_NDEF_EXP_OPT(PKCS7, d.data, ASN1_OCTET_STRING_NDEF, 0)),
+       ADB_ENTRY(NID_pkcs7_signed, ASN1_NDEF_EXP_OPT(PKCS7, d.sign, PKCS7_SIGNED, 0)),
+       ADB_ENTRY(NID_pkcs7_enveloped, ASN1_NDEF_EXP_OPT(PKCS7, d.enveloped, PKCS7_ENVELOPE, 0)),
+       ADB_ENTRY(NID_pkcs7_signedAndEnveloped, ASN1_NDEF_EXP_OPT(PKCS7, d.signed_and_enveloped, PKCS7_SIGN_ENVELOPE, 0)),
+       ADB_ENTRY(NID_pkcs7_digest, ASN1_NDEF_EXP_OPT(PKCS7, d.digest, PKCS7_DIGEST, 0)),
+       ADB_ENTRY(NID_pkcs7_encrypted, ASN1_NDEF_EXP_OPT(PKCS7, d.encrypted, PKCS7_ENCRYPT, 0))
 } ASN1_ADB_END(PKCS7, 0, type, 0, &p7default_tt, NULL);
 
-ASN1_SEQUENCE(PKCS7) = {
+ASN1_NDEF_SEQUENCE(PKCS7) = {
        ASN1_SIMPLE(PKCS7, type, ASN1_OBJECT),
        ASN1_ADB_OBJECT(PKCS7)
-}ASN1_SEQUENCE_END(PKCS7)
+}ASN1_NDEF_SEQUENCE_END(PKCS7)
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7)
+IMPLEMENT_ASN1_NDEF_FUNCTION(PKCS7)
 IMPLEMENT_ASN1_DUP_FUNCTION(PKCS7)
 
-ASN1_SEQUENCE(PKCS7_SIGNED) = {
+ASN1_NDEF_SEQUENCE(PKCS7_SIGNED) = {
        ASN1_SIMPLE(PKCS7_SIGNED, version, ASN1_INTEGER),
        ASN1_SET_OF(PKCS7_SIGNED, md_algs, X509_ALGOR),
        ASN1_SIMPLE(PKCS7_SIGNED, contents, PKCS7),
        ASN1_IMP_SEQUENCE_OF_OPT(PKCS7_SIGNED, cert, X509, 0),
        ASN1_IMP_SET_OF_OPT(PKCS7_SIGNED, crl, X509_CRL, 1),
        ASN1_SET_OF(PKCS7_SIGNED, signer_info, PKCS7_SIGNER_INFO)
-} ASN1_SEQUENCE_END(PKCS7_SIGNED)
+} ASN1_NDEF_SEQUENCE_END(PKCS7_SIGNED)
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_SIGNED)
 
@@ -130,11 +131,11 @@ ASN1_SEQUENCE(PKCS7_ISSUER_AND_SERIAL) = {
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL)
 
-ASN1_SEQUENCE(PKCS7_ENVELOPE) = {
+ASN1_NDEF_SEQUENCE(PKCS7_ENVELOPE) = {
        ASN1_SIMPLE(PKCS7_ENVELOPE, version, ASN1_INTEGER),
        ASN1_SET_OF(PKCS7_ENVELOPE, recipientinfo, PKCS7_RECIP_INFO),
        ASN1_SIMPLE(PKCS7_ENVELOPE, enc_data, PKCS7_ENC_CONTENT)
-} ASN1_SEQUENCE_END(PKCS7_ENVELOPE)
+} ASN1_NDEF_SEQUENCE_END(PKCS7_ENVELOPE)
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ENVELOPE)
 
@@ -157,15 +158,15 @@ ASN1_SEQUENCE_cb(PKCS7_RECIP_INFO, ri_cb) = {
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_RECIP_INFO)
 
-ASN1_SEQUENCE(PKCS7_ENC_CONTENT) = {
+ASN1_NDEF_SEQUENCE(PKCS7_ENC_CONTENT) = {
        ASN1_SIMPLE(PKCS7_ENC_CONTENT, content_type, ASN1_OBJECT),
        ASN1_SIMPLE(PKCS7_ENC_CONTENT, algorithm, X509_ALGOR),
        ASN1_IMP_OPT(PKCS7_ENC_CONTENT, enc_data, ASN1_OCTET_STRING, 0)
-} ASN1_SEQUENCE_END(PKCS7_ENC_CONTENT)
+} ASN1_NDEF_SEQUENCE_END(PKCS7_ENC_CONTENT)
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT)
 
-ASN1_SEQUENCE(PKCS7_SIGN_ENVELOPE) = {
+ASN1_NDEF_SEQUENCE(PKCS7_SIGN_ENVELOPE) = {
        ASN1_SIMPLE(PKCS7_SIGN_ENVELOPE, version, ASN1_INTEGER),
        ASN1_SET_OF(PKCS7_SIGN_ENVELOPE, recipientinfo, PKCS7_RECIP_INFO),
        ASN1_SET_OF(PKCS7_SIGN_ENVELOPE, md_algs, X509_ALGOR),
@@ -173,23 +174,23 @@ ASN1_SEQUENCE(PKCS7_SIGN_ENVELOPE) = {
        ASN1_IMP_SET_OF_OPT(PKCS7_SIGN_ENVELOPE, cert, X509, 0),
        ASN1_IMP_SET_OF_OPT(PKCS7_SIGN_ENVELOPE, crl, X509_CRL, 1),
        ASN1_SET_OF(PKCS7_SIGN_ENVELOPE, signer_info, PKCS7_SIGNER_INFO)
-} ASN1_SEQUENCE_END(PKCS7_SIGN_ENVELOPE)
+} ASN1_NDEF_SEQUENCE_END(PKCS7_SIGN_ENVELOPE)
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE)
 
-ASN1_SEQUENCE(PKCS7_ENCRYPT) = {
+ASN1_NDEF_SEQUENCE(PKCS7_ENCRYPT) = {
        ASN1_SIMPLE(PKCS7_ENCRYPT, version, ASN1_INTEGER),
        ASN1_SIMPLE(PKCS7_ENCRYPT, enc_data, PKCS7_ENC_CONTENT)
-} ASN1_SEQUENCE_END(PKCS7_ENCRYPT)
+} ASN1_NDEF_SEQUENCE_END(PKCS7_ENCRYPT)
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ENCRYPT)
 
-ASN1_SEQUENCE(PKCS7_DIGEST) = {
+ASN1_NDEF_SEQUENCE(PKCS7_DIGEST) = {
        ASN1_SIMPLE(PKCS7_DIGEST, version, ASN1_INTEGER),
        ASN1_SIMPLE(PKCS7_DIGEST, md, X509_ALGOR),
        ASN1_SIMPLE(PKCS7_DIGEST, contents, PKCS7),
        ASN1_SIMPLE(PKCS7_DIGEST, digest, ASN1_OCTET_STRING)
-} ASN1_SEQUENCE_END(PKCS7_DIGEST)
+} ASN1_NDEF_SEQUENCE_END(PKCS7_DIGEST)
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_DIGEST)