aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/asn1/tasn_enc.c
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2002-10-03 12:38:52 +0000
committerDr. Stephen Henson <steve@openssl.org>2002-10-03 12:38:52 +0000
commit230fd6b7b66f0b72b1cf7fc300652a1adf94ba1a (patch)
tree0b44fcc6a6e1bd9cb4de4fb5d5a9939b3768b4c5 /crypto/asn1/tasn_enc.c
parent20b33a015f1ea8b0927aa5057d2e6abe053b902f (diff)
downloadopenssl-230fd6b7b66f0b72b1cf7fc300652a1adf94ba1a.tar.gz
Preliminary streaming ASN1 encode support.
Diffstat (limited to 'crypto/asn1/tasn_enc.c')
-rw-r--r--crypto/asn1/tasn_enc.c239
1 files changed, 176 insertions, 63 deletions
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 <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;