X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fasn1%2Ftasn_enc.c;h=1d1f838078289cc4b1d57370254e4af305c13fa1;hp=685401e163e982a777a053aed1e3ee37fbe4bbfa;hb=2e430277578d3dd586cd005682a54a59d6158146;hpb=25a58453ff5b73e7b4d5e2764d7924424694a82a diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c index 685401e163..1d1f838078 100644 --- a/crypto/asn1/tasn_enc.c +++ b/crypto/asn1/tasn_enc.c @@ -1,6 +1,7 @@ /* tasn_enc.c */ -/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL - * project 2000. +/* + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project + * 2000. */ /* ==================================================================== * Copyright (c) 2000-2004 The OpenSSL Project. All rights reserved. @@ -10,7 +11,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -56,635 +57,587 @@ * */ - #include #include #include "cryptlib.h" #include #include #include +#include "internal/asn1_int.h" static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, - const ASN1_ITEM *it, - int tag, int aclass); + 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); + 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); + 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); + const ASN1_ITEM *it, int flags); -/* Top level i2d equivalents: the 'ndef' variant instructs the encoder - * to use indefinite length constructed encoding, where appropriate +/* + * 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); - } + const ASN1_ITEM *it) +{ + return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); +} int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) - { - return asn1_item_flags_i2d(val, out, it, 0); - } +{ + 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. - * - * The new i2d has one additional feature. If the output - * buffer is NULL (i.e. *out == NULL) then a buffer is +/* + * Encode an ASN1 item, this is use by the standard 'i2d' function. 'out' + * points to 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. */ 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, flags); - if (len <= 0) - return len; - buf = OPENSSL_malloc(len); - if (!buf) - return -1; - p = buf; - ASN1_item_ex_i2d(&val, &p, it, -1, flags); - *out = buf; - return len; - } - - return ASN1_item_ex_i2d(&val, out, it, -1, flags); - } - -/* Encode an item, taking care of IMPLICIT tagging (if any). - * This function performs the normal item handling: it can be - * used in external types. + const ASN1_ITEM *it, int flags) +{ + if (out && !*out) { + unsigned char *p, *buf; + int len; + 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, flags); + *out = buf; + return len; + } + + return ASN1_item_ex_i2d(&val, out, it, -1, flags); +} + +/* + * Encode an item, taking care of IMPLICIT tagging (if any). This function + * performs the normal item handling: it can be used in external types. */ 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, ndef = 1; - const ASN1_COMPAT_FUNCS *cf; - const ASN1_EXTERN_FUNCS *ef; - const ASN1_AUX *aux = it->funcs; - 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_ex_i2d(pval, out, it->templates, - tag, aclass); - return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); - break; - - case ASN1_ITYPE_MSTRING: - 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, NULL)) - return 0; - i = asn1_get_choice_selector(pval, it); - if ((i >= 0) && (i < it->tcount)) - { - ASN1_VALUE **pchval; - const ASN1_TEMPLATE *chtt; - chtt = it->templates + i; - pchval = asn1_get_field_ptr(pval, 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, NULL)) - return 0; - break; - - case ASN1_ITYPE_EXTERN: - /* If new style i2d it does all the work */ - ef = it->funcs; - return ef->asn1_ex_i2d(pval, out, it, tag, aclass); - - case ASN1_ITYPE_COMPAT: - /* old style hackery... */ - cf = it->funcs; - if (out) - p = *out; - i = cf->asn1_i2d(*pval, out); - /* Fixup for IMPLICIT tag: note this messes up for tags > 30, - * but so did the old code. Tags > 30 are very rare anyway. - */ - if (out && (tag != -1)) - *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED); - return i; - - case ASN1_ITYPE_NDEF_SEQUENCE: - /* 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 */ - if (i < 0) - return 0; - /* We have a valid cached encoding... */ - if (i > 0) - return seqcontlen; - /* Otherwise carry on */ - seqcontlen = 0; - /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ - if (tag == -1) - { - tag = V_ASN1_SEQUENCE; - /* 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, NULL)) - return 0; - /* First work out sequence content length */ - for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) - { - const ASN1_TEMPLATE *seqtt; - ASN1_VALUE **pseqval; - seqtt = asn1_do_adb(pval, tt, 1); - if (!seqtt) - return 0; - pseqval = asn1_get_field_ptr(pval, seqtt); - /* FIXME: check for errors in enhanced version */ - seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, - -1, aclass); - } - - seqlen = ASN1_object_size(ndef, seqcontlen, tag); - if (!out) - return seqlen; - /* Output SEQUENCE header */ - 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; - seqtt = asn1_do_adb(pval, tt, 1); - if (!seqtt) - return 0; - pseqval = asn1_get_field_ptr(pval, seqtt); - /* FIXME: check for errors in enhanced version */ - 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, NULL)) - return 0; - return seqlen; - - default: - return 0; - - } - return 0; - } + const ASN1_ITEM *it, int tag, int aclass) +{ + const ASN1_TEMPLATE *tt = NULL; + int i, seqcontlen, seqlen, ndef = 1; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_AUX *aux = it->funcs; + 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_ex_i2d(pval, out, it->templates, + tag, aclass); + return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); + + case ASN1_ITYPE_MSTRING: + 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, NULL)) + return 0; + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) { + ASN1_VALUE **pchval; + const ASN1_TEMPLATE *chtt; + chtt = it->templates + i; + pchval = asn1_get_field_ptr(pval, 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, NULL)) + return 0; + break; + + case ASN1_ITYPE_EXTERN: + /* If new style i2d it does all the work */ + ef = it->funcs; + return ef->asn1_ex_i2d(pval, out, it, tag, aclass); + + case ASN1_ITYPE_NDEF_SEQUENCE: + /* 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 */ + if (i < 0) + return 0; + /* We have a valid cached encoding... */ + if (i > 0) + return seqcontlen; + /* Otherwise carry on */ + seqcontlen = 0; + /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ + if (tag == -1) { + tag = V_ASN1_SEQUENCE; + /* 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, NULL)) + return 0; + /* First work out sequence content length */ + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + return 0; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* FIXME: check for errors in enhanced version */ + seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, + -1, aclass); + } + + seqlen = ASN1_object_size(ndef, seqcontlen, tag); + if (!out) + return seqlen; + /* Output SEQUENCE header */ + 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; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + return 0; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* FIXME: check for errors in enhanced version */ + 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, NULL)) + return 0; + return seqlen; + + default: + return 0; + + } + return 0; +} int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, - const ASN1_TEMPLATE *tt) - { - return asn1_template_ex_i2d(pval, out, tt, -1, 0); - } + const ASN1_TEMPLATE *tt) +{ + return asn1_template_ex_i2d(pval, out, tt, -1, 0); +} static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, - const ASN1_TEMPLATE *tt, int tag, int iclass) - { - int i, ret, flags, ttag, tclass, ndef; - flags = tt->flags; - /* 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; - - /* 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; - } - - /* 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, iclass); - } - sklen = ASN1_object_size(ndef, skcontlen, sktag); - /* If EXPLICIT need length of surrounding tag */ - if (flags & ASN1_TFLG_EXPTAG) - ret = ASN1_object_size(ndef, sklen, ttag); - else ret = sklen; - - if (!out) - return ret; - - /* Now encode this lot... */ - /* EXPLICIT tag */ - if (flags & ASN1_TFLG_EXPTAG) - ASN1_put_object(out, ndef, sklen, ttag, tclass); - /* SET or SEQUENCE and IMPLICIT tag */ - 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, iclass); - if (!i) - return 0; - /* Find length of EXPLICIT tag */ - ret = ASN1_object_size(ndef, i, ttag); - if (out) - { - /* Output tag and item */ - 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; - } - - /* Either normal or IMPLICIT tagging: combine class and flags */ - return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), - ttag, tclass | iclass); + const ASN1_TEMPLATE *tt, int tag, int iclass) +{ + int i, ret, flags, ttag, tclass, ndef; + flags = tt->flags; + /* + * 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; + + /* + * 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; + } + + /* 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, iclass); + } + sklen = ASN1_object_size(ndef, skcontlen, sktag); + /* If EXPLICIT need length of surrounding tag */ + if (flags & ASN1_TFLG_EXPTAG) + ret = ASN1_object_size(ndef, sklen, ttag); + else + ret = sklen; + + if (!out) + return ret; + + /* Now encode this lot... */ + /* EXPLICIT tag */ + if (flags & ASN1_TFLG_EXPTAG) + ASN1_put_object(out, ndef, sklen, ttag, tclass); + /* SET or SEQUENCE and IMPLICIT tag */ + 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, iclass); + if (!i) + return 0; + /* Find length of EXPLICIT tag */ + ret = ASN1_object_size(ndef, i, ttag); + if (out) { + /* Output tag and item */ + 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; + } + + /* 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 */ -typedef struct { - unsigned char *data; - int length; - ASN1_VALUE *field; +typedef struct { + unsigned char *data; + int length; + ASN1_VALUE *field; } DER_ENC; static int der_cmp(const void *a, const void *b) - { - const DER_ENC *d1 = a, *d2 = b; - int cmplen, i; - cmplen = (d1->length < d2->length) ? d1->length : d2->length; - i = memcmp(d1->data, d2->data, cmplen); - if (i) - return i; - return d1->length - d2->length; - } +{ + const DER_ENC *d1 = a, *d2 = b; + int cmplen, i; + cmplen = (d1->length < d2->length) ? d1->length : d2->length; + i = memcmp(d1->data, d2->data, cmplen); + if (i) + return i; + return d1->length - d2->length; +} /* 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, int iclass) - { - int i; - ASN1_VALUE *skitem; - unsigned char *tmpdat = NULL, *p = NULL; - DER_ENC *derlst = NULL, *tder; - if (do_sort) - { - /* Don't need to sort less than 2 items */ - if (sk_ASN1_VALUE_num(sk) < 2) - do_sort = 0; - else - { - derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) - * sizeof(*derlst)); - tmpdat = OPENSSL_malloc(skcontlen); - if (!derlst || !tmpdat) - return 0; - } - } - /* If not sorting just output each item */ - if (!do_sort) - { - for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) - { - skitem = sk_ASN1_VALUE_value(sk, i); - ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); - } - return 1; - } - p = tmpdat; - - /* Doing sort: build up a list of each member's DER encoding */ - 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_ex_i2d(&skitem, &p, item, -1, iclass); - tder->field = skitem; - } - - /* Now sort them */ - qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); - /* Output sorted DER encoding */ - p = *out; - for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) - { - memcpy(p, tder->data, tder->length); - p += tder->length; - } - *out = p; - /* If do_sort is 2 then reorder the STACK */ - if (do_sort == 2) - { - for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); - i++, tder++) - sk_ASN1_VALUE_set(sk, i, tder->field); - } - OPENSSL_free(derlst); - OPENSSL_free(tmpdat); - return 1; - } + int skcontlen, const ASN1_ITEM *item, + int do_sort, int iclass) +{ + int i; + ASN1_VALUE *skitem; + unsigned char *tmpdat = NULL, *p = NULL; + DER_ENC *derlst = NULL, *tder; + if (do_sort) { + /* Don't need to sort less than 2 items */ + if (sk_ASN1_VALUE_num(sk) < 2) + do_sort = 0; + else { + derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) + * sizeof(*derlst)); + if (!derlst) + return 0; + tmpdat = OPENSSL_malloc(skcontlen); + if (!tmpdat) { + OPENSSL_free(derlst); + return 0; + } + } + } + /* If not sorting just output each item */ + if (!do_sort) { + for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { + skitem = sk_ASN1_VALUE_value(sk, i); + ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); + } + return 1; + } + p = tmpdat; + + /* Doing sort: build up a list of each member's DER encoding */ + 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_ex_i2d(&skitem, &p, item, -1, iclass); + tder->field = skitem; + } + + /* Now sort them */ + qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); + /* Output sorted DER encoding */ + p = *out; + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { + memcpy(p, tder->data, tder->length); + p += tder->length; + } + *out = p; + /* If do_sort is 2 then reorder the STACK */ + if (do_sort == 2) { + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) + (void)sk_ASN1_VALUE_set(sk, i, tder->field); + } + OPENSSL_free(derlst); + OPENSSL_free(tmpdat); + return 1; +} static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, - const ASN1_ITEM *it, int tag, int aclass) - { - int len; - int utype; - int usetag; - int ndef = 0; - - utype = it->utype; - - /* Get length of content octets and maybe find - * out the underlying type. - */ - - len = asn1_ex_i2c(pval, NULL, &utype, it); - - /* If SEQUENCE, SET or OTHER then header is - * included in pseudo content octets so don't - * include tag+length. We need to check here - * because the call to asn1_ex_i2c() could change - * utype. - */ - if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || - (utype == V_ASN1_OTHER)) - usetag = 0; - else usetag = 1; - - /* -1 means omit type */ - - 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, ndef, len, tag, aclass); - asn1_ex_i2c(pval, *out, &utype, it); - if (ndef) - ASN1_put_eoc(out); - else - *out += len; - } - - if (usetag) - return ASN1_object_size(ndef, len, tag); - return len; - } + const ASN1_ITEM *it, int tag, int aclass) +{ + int len; + int utype; + int usetag; + int ndef = 0; + + utype = it->utype; + + /* + * Get length of content octets and maybe find out the underlying type. + */ + + len = asn1_ex_i2c(pval, NULL, &utype, it); + + /* + * If SEQUENCE, SET or OTHER then header is included in pseudo content + * octets so don't include tag+length. We need to check here because the + * call to asn1_ex_i2c() could change utype. + */ + if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || + (utype == V_ASN1_OTHER)) + usetag = 0; + else + usetag = 1; + + /* -1 means omit type */ + + 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, ndef, len, tag, aclass); + asn1_ex_i2c(pval, *out, &utype, it); + if (ndef) + ASN1_put_eoc(out); + else + *out += len; + } + + if (usetag) + return ASN1_object_size(ndef, len, tag); + return len; +} /* Produce content octets from a structure */ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, - const ASN1_ITEM *it) - { - ASN1_BOOLEAN *tbool = NULL; - ASN1_STRING *strtmp; - ASN1_OBJECT *otmp; - int utype; - unsigned char *cont, c; - int len; - const ASN1_PRIMITIVE_FUNCS *pf; - pf = it->funcs; - if (pf && pf->prim_i2c) - return pf->prim_i2c(pval, cout, putype, it); - - /* Should type be omitted? */ - if ((it->itype != ASN1_ITYPE_PRIMITIVE) - || (it->utype != V_ASN1_BOOLEAN)) - { - if (!*pval) return -1; - } - - if (it->itype == ASN1_ITYPE_MSTRING) - { - /* If MSTRING type set the underlying type */ - strtmp = (ASN1_STRING *)*pval; - utype = strtmp->type; - *putype = utype; - } - else if (it->utype == V_ASN1_ANY) - { - /* If ANY set type and pointer to value */ - ASN1_TYPE *typ; - typ = (ASN1_TYPE *)*pval; - utype = typ->type; - *putype = utype; - pval = (ASN1_VALUE **)&typ->value.ptr; - } - else utype = *putype; - - switch(utype) - { - case V_ASN1_OBJECT: - otmp = (ASN1_OBJECT *)*pval; - cont = otmp->data; - len = otmp->length; - break; - - case V_ASN1_NULL: - cont = NULL; - len = 0; - break; - - case V_ASN1_BOOLEAN: - tbool = (ASN1_BOOLEAN *)pval; - if (*tbool == -1) - return -1; - if (it->utype != V_ASN1_ANY) - { - /* Default handling if value == size field then omit */ - if (*tbool && (it->size > 0)) - return -1; - if (!*tbool && !it->size) - return -1; - } - c = (unsigned char)*tbool; - cont = &c; - len = 1; - break; - - case V_ASN1_BIT_STRING: - return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, - cout ? &cout : NULL); - break; - - case V_ASN1_INTEGER: - case V_ASN1_NEG_INTEGER: - case V_ASN1_ENUMERATED: - case V_ASN1_NEG_ENUMERATED: - /* These are all have the same content format - * as ASN1_INTEGER - */ - return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, - cout ? &cout : NULL); - break; - - case V_ASN1_OCTET_STRING: - case V_ASN1_NUMERICSTRING: - case V_ASN1_PRINTABLESTRING: - case V_ASN1_T61STRING: - case V_ASN1_VIDEOTEXSTRING: - case V_ASN1_IA5STRING: - case V_ASN1_UTCTIME: - case V_ASN1_GENERALIZEDTIME: - case V_ASN1_GRAPHICSTRING: - case V_ASN1_VISIBLESTRING: - case V_ASN1_GENERALSTRING: - case V_ASN1_UNIVERSALSTRING: - case V_ASN1_BMPSTRING: - case V_ASN1_UTF8STRING: - case V_ASN1_SEQUENCE: - case V_ASN1_SET: - 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; - } - /* Special return code */ - return -2; - } - cont = strtmp->data; - len = strtmp->length; - - break; - - } - if (cout && len) - memcpy(cout, cont, len); - return len; - } + const ASN1_ITEM *it) +{ + ASN1_BOOLEAN *tbool = NULL; + ASN1_STRING *strtmp; + ASN1_OBJECT *otmp; + int utype; + const unsigned char *cont; + unsigned char c; + int len; + const ASN1_PRIMITIVE_FUNCS *pf; + pf = it->funcs; + if (pf && pf->prim_i2c) + return pf->prim_i2c(pval, cout, putype, it); + + /* Should type be omitted? */ + if ((it->itype != ASN1_ITYPE_PRIMITIVE) + || (it->utype != V_ASN1_BOOLEAN)) { + if (!*pval) + return -1; + } + + if (it->itype == ASN1_ITYPE_MSTRING) { + /* If MSTRING type set the underlying type */ + strtmp = (ASN1_STRING *)*pval; + utype = strtmp->type; + *putype = utype; + } else if (it->utype == V_ASN1_ANY) { + /* If ANY set type and pointer to value */ + ASN1_TYPE *typ; + typ = (ASN1_TYPE *)*pval; + utype = typ->type; + *putype = utype; + pval = &typ->value.asn1_value; + } else + utype = *putype; + + switch (utype) { + case V_ASN1_OBJECT: + otmp = (ASN1_OBJECT *)*pval; + cont = otmp->data; + len = otmp->length; + break; + + case V_ASN1_NULL: + cont = NULL; + len = 0; + break; + + case V_ASN1_BOOLEAN: + tbool = (ASN1_BOOLEAN *)pval; + if (*tbool == -1) + return -1; + if (it->utype != V_ASN1_ANY) { + /* + * Default handling if value == size field then omit + */ + if (*tbool && (it->size > 0)) + return -1; + if (!*tbool && !it->size) + return -1; + } + c = (unsigned char)*tbool; + cont = &c; + len = 1; + break; + + case V_ASN1_BIT_STRING: + return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, + cout ? &cout : NULL); + + case V_ASN1_INTEGER: + case V_ASN1_NEG_INTEGER: + case V_ASN1_ENUMERATED: + case V_ASN1_NEG_ENUMERATED: + /* + * These are all have the same content format as ASN1_INTEGER + */ + return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL); + + case V_ASN1_OCTET_STRING: + case V_ASN1_NUMERICSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_VIDEOTEXSTRING: + case V_ASN1_IA5STRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_BMPSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_SEQUENCE: + case V_ASN1_SET: + 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; + } + /* Special return code */ + return -2; + } + cont = strtmp->data; + len = strtmp->length; + + break; + + } + if (cout && len) + memcpy(cout, cont, len); + return len; +}