From: Dr. Stephen Henson Date: Thu, 3 Oct 2002 12:38:52 +0000 (+0000) Subject: Preliminary streaming ASN1 encode support. X-Git-Tag: OpenSSL_0_9_7-beta4~140^2~33 X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=230fd6b7b66f0b72b1cf7fc300652a1adf94ba1a;hp=20b33a015f1ea8b0927aa5057d2e6abe053b902f Preliminary streaming ASN1 encode support. --- diff --git a/CHANGES b/CHANGES index feba2200e7..ef7d1b55dd 100644 --- 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] diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index 1be3e02298..e870948e8d 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -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); diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c index 0638870ab7..3f7b3aad2a 100644 --- a/crypto/asn1/asn1_lib.c +++ b/crypto/asn1/asn1_lib.c @@ -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) { diff --git a/crypto/asn1/asn1t.h b/crypto/asn1/asn1t.h index ed372f8554..83e8213ea5 100644 --- a/crypto/asn1/asn1t.h +++ b/crypto/asn1/asn1t.h @@ -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. */ diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c index f87c08793a..a9b1d9ef81 100644 --- a/crypto/asn1/tasn_dec.c +++ b/crypto/asn1/tasn_dec.c @@ -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; diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c index f6c8ddef0a..33d6366e02 100644 --- a/crypto/asn1/tasn_enc.c +++ b/crypto/asn1/tasn_enc.c @@ -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 @@ -63,38 +63,57 @@ #include #include -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; diff --git a/crypto/asn1/tasn_fre.c b/crypto/asn1/tasn_fre.c index c7610776f2..910f9b4f26 100644 --- a/crypto/asn1/tasn_fre.c +++ b/crypto/asn1/tasn_fre.c @@ -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) { diff --git a/crypto/asn1/tasn_new.c b/crypto/asn1/tasn_new.c index e33861f864..11a90f739e 100644 --- a/crypto/asn1/tasn_new.c +++ b/crypto/asn1/tasn_new.c @@ -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; } diff --git a/crypto/asn1/tasn_typ.c b/crypto/asn1/tasn_typ.c index 804d2eeba2..6f17f1bec7 100644 --- a/crypto/asn1/tasn_typ.c +++ b/crypto/asn1/tasn_typ.c @@ -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) diff --git a/crypto/asn1/tasn_utl.c b/crypto/asn1/tasn_utl.c index 8996ce8c13..2a3f5db8f3 100644 --- a/crypto/asn1/tasn_utl.c +++ b/crypto/asn1/tasn_utl.c @@ -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); diff --git a/crypto/pkcs7/pk7_asn1.c b/crypto/pkcs7/pk7_asn1.c index 46f0fc9375..77931feeb4 100644 --- a/crypto/pkcs7/pk7_asn1.c +++ b/crypto/pkcs7/pk7_asn1.c @@ -69,30 +69,31 @@ 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)