Index: openssl/crypto/asn1/tasn_dec.c |
diff --git a/openssl/crypto/asn1/tasn_dec.c b/openssl/crypto/asn1/tasn_dec.c |
deleted file mode 100644 |
index 87d7dfdf5c374dfed46b64f3d9b2c27dfcf72265..0000000000000000000000000000000000000000 |
--- a/openssl/crypto/asn1/tasn_dec.c |
+++ /dev/null |
@@ -1,1347 +0,0 @@ |
-/* tasn_dec.c */ |
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
- * project 2000. |
- */ |
-/* ==================================================================== |
- * Copyright (c) 2000-2005 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 |
- * are met: |
- * |
- * 1. Redistributions of source code must retain the above copyright |
- * 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 |
- * the documentation and/or other materials provided with the |
- * distribution. |
- * |
- * 3. All advertising materials mentioning features or use of this |
- * software must display the following acknowledgment: |
- * "This product includes software developed by the OpenSSL Project |
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
- * |
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
- * endorse or promote products derived from this software without |
- * prior written permission. For written permission, please contact |
- * licensing@OpenSSL.org. |
- * |
- * 5. Products derived from this software may not be called "OpenSSL" |
- * nor may "OpenSSL" appear in their names without prior written |
- * permission of the OpenSSL Project. |
- * |
- * 6. Redistributions of any form whatsoever must retain the following |
- * acknowledgment: |
- * "This product includes software developed by the OpenSSL Project |
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
- * OF THE POSSIBILITY OF SUCH DAMAGE. |
- * ==================================================================== |
- * |
- * This product includes cryptographic software written by Eric Young |
- * (eay@cryptsoft.com). This product includes software written by Tim |
- * Hudson (tjh@cryptsoft.com). |
- * |
- */ |
- |
- |
-#include <stddef.h> |
-#include <string.h> |
-#include <openssl/asn1.h> |
-#include <openssl/asn1t.h> |
-#include <openssl/objects.h> |
-#include <openssl/buffer.h> |
-#include <openssl/err.h> |
- |
-static int asn1_check_eoc(const unsigned char **in, long len); |
-static int asn1_find_end(const unsigned char **in, long len, char inf); |
- |
-static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, |
- char inf, int tag, int aclass, int depth); |
- |
-static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen); |
- |
-static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, |
- char *inf, char *cst, |
- const unsigned char **in, long len, |
- int exptag, int expclass, char opt, |
- ASN1_TLC *ctx); |
- |
-static int asn1_template_ex_d2i(ASN1_VALUE **pval, |
- const unsigned char **in, long len, |
- const ASN1_TEMPLATE *tt, char opt, |
- ASN1_TLC *ctx); |
-static int asn1_template_noexp_d2i(ASN1_VALUE **val, |
- const unsigned char **in, long len, |
- const ASN1_TEMPLATE *tt, char opt, |
- ASN1_TLC *ctx); |
-static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, |
- const unsigned char **in, long len, |
- const ASN1_ITEM *it, |
- int tag, int aclass, char opt, ASN1_TLC *ctx); |
- |
-/* Table to convert tags to bit values, used for MSTRING type */ |
-static const unsigned long tag2bit[32] = { |
-0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */ |
-B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,/* tags 4- 7 */ |
-B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags 8-11 */ |
-B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */ |
-B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */ |
-B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING, /* tags 20-22 */ |
-B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME, /* tags 23-24 */ |
-B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING, /* tags 25-27 */ |
-B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */ |
- }; |
- |
-unsigned long ASN1_tag2bit(int tag) |
- { |
- if ((tag < 0) || (tag > 30)) return 0; |
- return tag2bit[tag]; |
- } |
- |
-/* Macro to initialize and invalidate the cache */ |
- |
-#define asn1_tlc_clear(c) if (c) (c)->valid = 0 |
-/* Version to avoid compiler warning about 'c' always non-NULL */ |
-#define asn1_tlc_clear_nc(c) (c)->valid = 0 |
- |
-/* Decode an ASN1 item, this currently behaves just |
- * like a standard 'd2i' function. 'in' points to |
- * a buffer to read the data from, in future we will |
- * have more advanced versions that can input data |
- * a piece at a time and this will simply be a special |
- * case. |
- */ |
- |
-ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, |
- const unsigned char **in, long len, const ASN1_ITEM *it) |
- { |
- ASN1_TLC c; |
- ASN1_VALUE *ptmpval = NULL; |
- if (!pval) |
- pval = &ptmpval; |
- asn1_tlc_clear_nc(&c); |
- if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0) |
- return *pval; |
- return NULL; |
- } |
- |
-int ASN1_template_d2i(ASN1_VALUE **pval, |
- const unsigned char **in, long len, const ASN1_TEMPLATE *tt) |
- { |
- ASN1_TLC c; |
- asn1_tlc_clear_nc(&c); |
- return asn1_template_ex_d2i(pval, in, len, tt, 0, &c); |
- } |
- |
- |
-/* Decode an item, taking care of IMPLICIT tagging, if any. |
- * If 'opt' set and tag mismatch return -1 to handle OPTIONAL |
- */ |
- |
-int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, |
- const ASN1_ITEM *it, |
- int tag, int aclass, char opt, ASN1_TLC *ctx) |
- { |
- const ASN1_TEMPLATE *tt, *errtt = NULL; |
- const ASN1_COMPAT_FUNCS *cf; |
- const ASN1_EXTERN_FUNCS *ef; |
- const ASN1_AUX *aux = it->funcs; |
- ASN1_aux_cb *asn1_cb; |
- const unsigned char *p = NULL, *q; |
- unsigned char *wp=NULL; /* BIG FAT WARNING! BREAKS CONST WHERE USED */ |
- unsigned char imphack = 0, oclass; |
- char seq_eoc, seq_nolen, cst, isopt; |
- long tmplen; |
- int i; |
- int otag; |
- int ret = 0; |
- ASN1_VALUE **pchptr, *ptmpval; |
- if (!pval) |
- return 0; |
- if (aux && aux->asn1_cb) |
- asn1_cb = aux->asn1_cb; |
- else asn1_cb = 0; |
- |
- switch(it->itype) |
- { |
- case ASN1_ITYPE_PRIMITIVE: |
- if (it->templates) |
- { |
- /* tagging or OPTIONAL is currently illegal on an item |
- * template because the flags can't get passed down. |
- * In practice this isn't a problem: we include the |
- * relevant flags from the item template in the |
- * template itself. |
- */ |
- if ((tag != -1) || opt) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); |
- goto err; |
- } |
- return asn1_template_ex_d2i(pval, in, len, |
- it->templates, opt, ctx); |
- } |
- return asn1_d2i_ex_primitive(pval, in, len, it, |
- tag, aclass, opt, ctx); |
- break; |
- |
- case ASN1_ITYPE_MSTRING: |
- p = *in; |
- /* Just read in tag and class */ |
- ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, |
- &p, len, -1, 0, 1, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- |
- /* Must be UNIVERSAL class */ |
- if (oclass != V_ASN1_UNIVERSAL) |
- { |
- /* If OPTIONAL, assume this is OK */ |
- if (opt) return -1; |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_MSTRING_NOT_UNIVERSAL); |
- goto err; |
- } |
- /* Check tag matches bit map */ |
- if (!(ASN1_tag2bit(otag) & it->utype)) |
- { |
- /* If OPTIONAL, assume this is OK */ |
- if (opt) |
- return -1; |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_MSTRING_WRONG_TAG); |
- goto err; |
- } |
- return asn1_d2i_ex_primitive(pval, in, len, |
- it, otag, 0, 0, ctx); |
- |
- case ASN1_ITYPE_EXTERN: |
- /* Use new style d2i */ |
- ef = it->funcs; |
- return ef->asn1_ex_d2i(pval, in, len, |
- it, tag, aclass, opt, ctx); |
- |
- case ASN1_ITYPE_COMPAT: |
- /* we must resort to old style evil hackery */ |
- cf = it->funcs; |
- |
- /* If OPTIONAL see if it is there */ |
- if (opt) |
- { |
- int exptag; |
- p = *in; |
- if (tag == -1) |
- exptag = it->utype; |
- else exptag = tag; |
- /* Don't care about anything other than presence |
- * of expected tag */ |
- |
- ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, |
- &p, len, exptag, aclass, 1, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- if (ret == -1) |
- return -1; |
- } |
- |
- /* This is the old style evil hack IMPLICIT handling: |
- * since the underlying code is expecting a tag and |
- * class other than the one present we change the |
- * buffer temporarily then change it back afterwards. |
- * This doesn't and never did work for tags > 30. |
- * |
- * Yes this is *horrible* but it is only needed for |
- * old style d2i which will hopefully not be around |
- * for much longer. |
- * FIXME: should copy the buffer then modify it so |
- * the input buffer can be const: we should *always* |
- * copy because the old style d2i might modify the |
- * buffer. |
- */ |
- |
- if (tag != -1) |
- { |
- wp = *(unsigned char **)in; |
- imphack = *wp; |
- if (p == NULL) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED) |
- | it->utype); |
- } |
- |
- ptmpval = cf->asn1_d2i(pval, in, len); |
- |
- if (tag != -1) |
- *wp = imphack; |
- |
- if (ptmpval) |
- return 1; |
- |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- |
- |
- case ASN1_ITYPE_CHOICE: |
- if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) |
- goto auxerr; |
- |
- /* Allocate structure */ |
- if (!*pval && !ASN1_item_ex_new(pval, it)) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- /* CHOICE type, try each possibility in turn */ |
- p = *in; |
- for (i = 0, tt=it->templates; i < it->tcount; i++, tt++) |
- { |
- pchptr = asn1_get_field_ptr(pval, tt); |
- /* We mark field as OPTIONAL so its absence |
- * can be recognised. |
- */ |
- ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx); |
- /* If field not present, try the next one */ |
- if (ret == -1) |
- continue; |
- /* If positive return, read OK, break loop */ |
- if (ret > 0) |
- break; |
- /* Otherwise must be an ASN1 parsing error */ |
- errtt = tt; |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- |
- /* Did we fall off the end without reading anything? */ |
- if (i == it->tcount) |
- { |
- /* If OPTIONAL, this is OK */ |
- if (opt) |
- { |
- /* Free and zero it */ |
- ASN1_item_ex_free(pval, it); |
- return -1; |
- } |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_NO_MATCHING_CHOICE_TYPE); |
- goto err; |
- } |
- |
- asn1_set_choice_selector(pval, i, it); |
- *in = p; |
- if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) |
- goto auxerr; |
- return 1; |
- |
- case ASN1_ITYPE_NDEF_SEQUENCE: |
- case ASN1_ITYPE_SEQUENCE: |
- p = *in; |
- tmplen = len; |
- |
- /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ |
- if (tag == -1) |
- { |
- tag = V_ASN1_SEQUENCE; |
- aclass = V_ASN1_UNIVERSAL; |
- } |
- /* Get SEQUENCE length and update len, p */ |
- ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, |
- &p, len, tag, aclass, opt, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- else if (ret == -1) |
- return -1; |
- if (aux && (aux->flags & ASN1_AFLG_BROKEN)) |
- { |
- len = tmplen - (p - *in); |
- seq_nolen = 1; |
- } |
- /* If indefinite we don't do a length check */ |
- else seq_nolen = seq_eoc; |
- if (!cst) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_SEQUENCE_NOT_CONSTRUCTED); |
- goto err; |
- } |
- |
- if (!*pval && !ASN1_item_ex_new(pval, it)) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- |
- if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) |
- goto auxerr; |
- |
- /* Get each field entry */ |
- for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) |
- { |
- const ASN1_TEMPLATE *seqtt; |
- ASN1_VALUE **pseqval; |
- seqtt = asn1_do_adb(pval, tt, 1); |
- if (!seqtt) |
- goto err; |
- pseqval = asn1_get_field_ptr(pval, seqtt); |
- /* Have we ran out of data? */ |
- if (!len) |
- break; |
- q = p; |
- if (asn1_check_eoc(&p, len)) |
- { |
- if (!seq_eoc) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_UNEXPECTED_EOC); |
- goto err; |
- } |
- len -= p - q; |
- seq_eoc = 0; |
- q = p; |
- break; |
- } |
- /* This determines the OPTIONAL flag value. The field |
- * cannot be omitted if it is the last of a SEQUENCE |
- * and there is still data to be read. This isn't |
- * strictly necessary but it increases efficiency in |
- * some cases. |
- */ |
- if (i == (it->tcount - 1)) |
- isopt = 0; |
- else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); |
- /* attempt to read in field, allowing each to be |
- * OPTIONAL */ |
- |
- ret = asn1_template_ex_d2i(pseqval, &p, len, |
- seqtt, isopt, ctx); |
- if (!ret) |
- { |
- errtt = seqtt; |
- goto err; |
- } |
- else if (ret == -1) |
- { |
- /* OPTIONAL component absent. |
- * Free and zero the field. |
- */ |
- ASN1_template_free(pseqval, seqtt); |
- continue; |
- } |
- /* Update length */ |
- len -= p - q; |
- } |
- |
- /* Check for EOC if expecting one */ |
- if (seq_eoc && !asn1_check_eoc(&p, len)) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC); |
- goto err; |
- } |
- /* Check all data read */ |
- if (!seq_nolen && len) |
- { |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_SEQUENCE_LENGTH_MISMATCH); |
- goto err; |
- } |
- |
- /* If we get here we've got no more data in the SEQUENCE, |
- * however we may not have read all fields so check all |
- * remaining are OPTIONAL and clear any that are. |
- */ |
- for (; i < it->tcount; tt++, i++) |
- { |
- const ASN1_TEMPLATE *seqtt; |
- seqtt = asn1_do_adb(pval, tt, 1); |
- if (!seqtt) |
- goto err; |
- if (seqtt->flags & ASN1_TFLG_OPTIONAL) |
- { |
- ASN1_VALUE **pseqval; |
- pseqval = asn1_get_field_ptr(pval, seqtt); |
- ASN1_template_free(pseqval, seqtt); |
- } |
- else |
- { |
- errtt = seqtt; |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, |
- ASN1_R_FIELD_MISSING); |
- goto err; |
- } |
- } |
- /* Save encoding */ |
- if (!asn1_enc_save(pval, *in, p - *in, it)) |
- goto auxerr; |
- *in = p; |
- if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) |
- goto auxerr; |
- return 1; |
- |
- default: |
- return 0; |
- } |
- auxerr: |
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR); |
- err: |
- ASN1_item_ex_free(pval, it); |
- if (errtt) |
- ERR_add_error_data(4, "Field=", errtt->field_name, |
- ", Type=", it->sname); |
- else |
- ERR_add_error_data(2, "Type=", it->sname); |
- return 0; |
- } |
- |
-/* Templates are handled with two separate functions. |
- * One handles any EXPLICIT tag and the other handles the rest. |
- */ |
- |
-static int asn1_template_ex_d2i(ASN1_VALUE **val, |
- const unsigned char **in, long inlen, |
- const ASN1_TEMPLATE *tt, char opt, |
- ASN1_TLC *ctx) |
- { |
- int flags, aclass; |
- int ret; |
- long len; |
- const unsigned char *p, *q; |
- char exp_eoc; |
- if (!val) |
- return 0; |
- flags = tt->flags; |
- aclass = flags & ASN1_TFLG_TAG_CLASS; |
- |
- p = *in; |
- |
- /* Check if EXPLICIT tag expected */ |
- if (flags & ASN1_TFLG_EXPTAG) |
- { |
- char cst; |
- /* Need to work out amount of data available to the inner |
- * content and where it starts: so read in EXPLICIT header to |
- * get the info. |
- */ |
- ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, |
- &p, inlen, tt->tag, aclass, opt, ctx); |
- q = p; |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- return 0; |
- } |
- else if (ret == -1) |
- return -1; |
- if (!cst) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, |
- ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); |
- return 0; |
- } |
- /* We've found the field so it can't be OPTIONAL now */ |
- ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- return 0; |
- } |
- /* We read the field in OK so update length */ |
- len -= p - q; |
- if (exp_eoc) |
- { |
- /* If NDEF we must have an EOC here */ |
- if (!asn1_check_eoc(&p, len)) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, |
- ASN1_R_MISSING_EOC); |
- goto err; |
- } |
- } |
- else |
- { |
- /* Otherwise we must hit the EXPLICIT tag end or its |
- * an error */ |
- if (len) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, |
- ASN1_R_EXPLICIT_LENGTH_MISMATCH); |
- goto err; |
- } |
- } |
- } |
- else |
- return asn1_template_noexp_d2i(val, in, inlen, |
- tt, opt, ctx); |
- |
- *in = p; |
- return 1; |
- |
- err: |
- ASN1_template_free(val, tt); |
- return 0; |
- } |
- |
-static int asn1_template_noexp_d2i(ASN1_VALUE **val, |
- const unsigned char **in, long len, |
- const ASN1_TEMPLATE *tt, char opt, |
- ASN1_TLC *ctx) |
- { |
- int flags, aclass; |
- int ret; |
- const unsigned char *p, *q; |
- if (!val) |
- return 0; |
- flags = tt->flags; |
- aclass = flags & ASN1_TFLG_TAG_CLASS; |
- |
- p = *in; |
- q = p; |
- |
- if (flags & ASN1_TFLG_SK_MASK) |
- { |
- /* SET OF, SEQUENCE OF */ |
- int sktag, skaclass; |
- char sk_eoc; |
- /* First work out expected inner tag value */ |
- if (flags & ASN1_TFLG_IMPTAG) |
- { |
- sktag = tt->tag; |
- skaclass = aclass; |
- } |
- else |
- { |
- skaclass = V_ASN1_UNIVERSAL; |
- if (flags & ASN1_TFLG_SET_OF) |
- sktag = V_ASN1_SET; |
- else |
- sktag = V_ASN1_SEQUENCE; |
- } |
- /* Get the tag */ |
- ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, |
- &p, len, sktag, skaclass, opt, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- return 0; |
- } |
- else if (ret == -1) |
- return -1; |
- if (!*val) |
- *val = (ASN1_VALUE *)sk_new_null(); |
- else |
- { |
- /* We've got a valid STACK: free up any items present */ |
- STACK_OF(ASN1_VALUE) *sktmp |
- = (STACK_OF(ASN1_VALUE) *)*val; |
- ASN1_VALUE *vtmp; |
- while(sk_ASN1_VALUE_num(sktmp) > 0) |
- { |
- vtmp = sk_ASN1_VALUE_pop(sktmp); |
- ASN1_item_ex_free(&vtmp, |
- ASN1_ITEM_ptr(tt->item)); |
- } |
- } |
- |
- if (!*val) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, |
- ERR_R_MALLOC_FAILURE); |
- goto err; |
- } |
- |
- /* Read as many items as we can */ |
- while(len > 0) |
- { |
- ASN1_VALUE *skfield; |
- q = p; |
- /* See if EOC found */ |
- if (asn1_check_eoc(&p, len)) |
- { |
- if (!sk_eoc) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, |
- ASN1_R_UNEXPECTED_EOC); |
- goto err; |
- } |
- len -= p - q; |
- sk_eoc = 0; |
- break; |
- } |
- skfield = NULL; |
- if (!ASN1_item_ex_d2i(&skfield, &p, len, |
- ASN1_ITEM_ptr(tt->item), |
- -1, 0, 0, ctx)) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- len -= p - q; |
- if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, |
- skfield)) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, |
- ERR_R_MALLOC_FAILURE); |
- goto err; |
- } |
- } |
- if (sk_eoc) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_MISSING_EOC); |
- goto err; |
- } |
- } |
- else if (flags & ASN1_TFLG_IMPTAG) |
- { |
- /* IMPLICIT tagging */ |
- ret = ASN1_item_ex_d2i(val, &p, len, |
- ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- else if (ret == -1) |
- return -1; |
- } |
- else |
- { |
- /* Nothing special */ |
- ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), |
- -1, 0, opt, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, |
- ERR_R_NESTED_ASN1_ERROR); |
- goto err; |
- } |
- else if (ret == -1) |
- return -1; |
- } |
- |
- *in = p; |
- return 1; |
- |
- err: |
- ASN1_template_free(val, tt); |
- return 0; |
- } |
- |
-static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, |
- const unsigned char **in, long inlen, |
- const ASN1_ITEM *it, |
- int tag, int aclass, char opt, ASN1_TLC *ctx) |
- { |
- int ret = 0, utype; |
- long plen; |
- char cst, inf, free_cont = 0; |
- const unsigned char *p; |
- BUF_MEM buf; |
- const unsigned char *cont = NULL; |
- long len; |
- if (!pval) |
- { |
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL); |
- return 0; /* Should never happen */ |
- } |
- |
- if (it->itype == ASN1_ITYPE_MSTRING) |
- { |
- utype = tag; |
- tag = -1; |
- } |
- else |
- utype = it->utype; |
- |
- if (utype == V_ASN1_ANY) |
- { |
- /* If type is ANY need to figure out type from tag */ |
- unsigned char oclass; |
- if (tag >= 0) |
- { |
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, |
- ASN1_R_ILLEGAL_TAGGED_ANY); |
- return 0; |
- } |
- if (opt) |
- { |
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, |
- ASN1_R_ILLEGAL_OPTIONAL_ANY); |
- return 0; |
- } |
- p = *in; |
- ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, |
- &p, inlen, -1, 0, 0, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, |
- ERR_R_NESTED_ASN1_ERROR); |
- return 0; |
- } |
- if (oclass != V_ASN1_UNIVERSAL) |
- utype = V_ASN1_OTHER; |
- } |
- if (tag == -1) |
- { |
- tag = utype; |
- aclass = V_ASN1_UNIVERSAL; |
- } |
- p = *in; |
- /* Check header */ |
- ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, |
- &p, inlen, tag, aclass, opt, ctx); |
- if (!ret) |
- { |
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); |
- return 0; |
- } |
- else if (ret == -1) |
- return -1; |
- ret = 0; |
- /* SEQUENCE, SET and "OTHER" are left in encoded form */ |
- if ((utype == V_ASN1_SEQUENCE) |
- || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) |
- { |
- /* Clear context cache for type OTHER because the auto clear |
- * when we have a exact match wont work |
- */ |
- if (utype == V_ASN1_OTHER) |
- { |
- asn1_tlc_clear(ctx); |
- } |
- /* SEQUENCE and SET must be constructed */ |
- else if (!cst) |
- { |
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, |
- ASN1_R_TYPE_NOT_CONSTRUCTED); |
- return 0; |
- } |
- |
- cont = *in; |
- /* If indefinite length constructed find the real end */ |
- if (inf) |
- { |
- if (!asn1_find_end(&p, plen, inf)) |
- goto err; |
- len = p - cont; |
- } |
- else |
- { |
- len = p - cont + plen; |
- p += plen; |
- buf.data = NULL; |
- } |
- } |
- else if (cst) |
- { |
- buf.length = 0; |
- buf.max = 0; |
- buf.data = NULL; |
- /* Should really check the internal tags are correct but |
- * some things may get this wrong. The relevant specs |
- * say that constructed string types should be OCTET STRINGs |
- * internally irrespective of the type. So instead just check |
- * for UNIVERSAL class and ignore the tag. |
- */ |
- if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) |
- { |
- free_cont = 1; |
- goto err; |
- } |
- len = buf.length; |
- /* Append a final null to string */ |
- if (!BUF_MEM_grow_clean(&buf, len + 1)) |
- { |
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, |
- ERR_R_MALLOC_FAILURE); |
- return 0; |
- } |
- buf.data[len] = 0; |
- cont = (const unsigned char *)buf.data; |
- free_cont = 1; |
- } |
- else |
- { |
- cont = p; |
- len = plen; |
- p += plen; |
- } |
- |
- /* We now have content length and type: translate into a structure */ |
- if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) |
- goto err; |
- |
- *in = p; |
- ret = 1; |
- err: |
- if (free_cont && buf.data) OPENSSL_free(buf.data); |
- return ret; |
- } |
- |
-/* Translate ASN1 content octets into a structure */ |
- |
-int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, |
- int utype, char *free_cont, const ASN1_ITEM *it) |
- { |
- ASN1_VALUE **opval = NULL; |
- ASN1_STRING *stmp; |
- ASN1_TYPE *typ = NULL; |
- int ret = 0; |
- const ASN1_PRIMITIVE_FUNCS *pf; |
- ASN1_INTEGER **tint; |
- pf = it->funcs; |
- |
- if (pf && pf->prim_c2i) |
- return pf->prim_c2i(pval, cont, len, utype, free_cont, it); |
- /* If ANY type clear type and set pointer to internal value */ |
- if (it->utype == V_ASN1_ANY) |
- { |
- if (!*pval) |
- { |
- typ = ASN1_TYPE_new(); |
- if (typ == NULL) |
- goto err; |
- *pval = (ASN1_VALUE *)typ; |
- } |
- else |
- typ = (ASN1_TYPE *)*pval; |
- |
- if (utype != typ->type) |
- ASN1_TYPE_set(typ, utype, NULL); |
- opval = pval; |
- pval = &typ->value.asn1_value; |
- } |
- switch(utype) |
- { |
- case V_ASN1_OBJECT: |
- if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) |
- goto err; |
- break; |
- |
- case V_ASN1_NULL: |
- if (len) |
- { |
- ASN1err(ASN1_F_ASN1_EX_C2I, |
- ASN1_R_NULL_IS_WRONG_LENGTH); |
- goto err; |
- } |
- *pval = (ASN1_VALUE *)1; |
- break; |
- |
- case V_ASN1_BOOLEAN: |
- if (len != 1) |
- { |
- ASN1err(ASN1_F_ASN1_EX_C2I, |
- ASN1_R_BOOLEAN_IS_WRONG_LENGTH); |
- goto err; |
- } |
- else |
- { |
- ASN1_BOOLEAN *tbool; |
- tbool = (ASN1_BOOLEAN *)pval; |
- *tbool = *cont; |
- } |
- break; |
- |
- case V_ASN1_BIT_STRING: |
- if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) |
- goto err; |
- break; |
- |
- case V_ASN1_INTEGER: |
- case V_ASN1_NEG_INTEGER: |
- case V_ASN1_ENUMERATED: |
- case V_ASN1_NEG_ENUMERATED: |
- tint = (ASN1_INTEGER **)pval; |
- if (!c2i_ASN1_INTEGER(tint, &cont, len)) |
- goto err; |
- /* Fixup type to match the expected form */ |
- (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG); |
- 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_OTHER: |
- case V_ASN1_SET: |
- case V_ASN1_SEQUENCE: |
- default: |
- if (utype == V_ASN1_BMPSTRING && (len & 1)) |
- { |
- ASN1err(ASN1_F_ASN1_EX_C2I, |
- ASN1_R_BMPSTRING_IS_WRONG_LENGTH); |
- goto err; |
- } |
- if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) |
- { |
- ASN1err(ASN1_F_ASN1_EX_C2I, |
- ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); |
- goto err; |
- } |
- /* All based on ASN1_STRING and handled the same */ |
- if (!*pval) |
- { |
- stmp = ASN1_STRING_type_new(utype); |
- if (!stmp) |
- { |
- ASN1err(ASN1_F_ASN1_EX_C2I, |
- ERR_R_MALLOC_FAILURE); |
- goto err; |
- } |
- *pval = (ASN1_VALUE *)stmp; |
- } |
- else |
- { |
- stmp = (ASN1_STRING *)*pval; |
- stmp->type = utype; |
- } |
- /* If we've already allocated a buffer use it */ |
- if (*free_cont) |
- { |
- if (stmp->data) |
- OPENSSL_free(stmp->data); |
- stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */ |
- stmp->length = len; |
- *free_cont = 0; |
- } |
- else |
- { |
- if (!ASN1_STRING_set(stmp, cont, len)) |
- { |
- ASN1err(ASN1_F_ASN1_EX_C2I, |
- ERR_R_MALLOC_FAILURE); |
- ASN1_STRING_free(stmp); |
- *pval = NULL; |
- goto err; |
- } |
- } |
- break; |
- } |
- /* If ASN1_ANY and NULL type fix up value */ |
- if (typ && (utype == V_ASN1_NULL)) |
- typ->value.ptr = NULL; |
- |
- ret = 1; |
- err: |
- if (!ret) |
- { |
- ASN1_TYPE_free(typ); |
- if (opval) |
- *opval = NULL; |
- } |
- return ret; |
- } |
- |
- |
-/* This function finds the end of an ASN1 structure when passed its maximum |
- * length, whether it is indefinite length and a pointer to the content. |
- * This is more efficient than calling asn1_collect because it does not |
- * recurse on each indefinite length header. |
- */ |
- |
-static int asn1_find_end(const unsigned char **in, long len, char inf) |
- { |
- int expected_eoc; |
- long plen; |
- const unsigned char *p = *in, *q; |
- /* If not indefinite length constructed just add length */ |
- if (inf == 0) |
- { |
- *in += len; |
- return 1; |
- } |
- expected_eoc = 1; |
- /* Indefinite length constructed form. Find the end when enough EOCs |
- * are found. If more indefinite length constructed headers |
- * are encountered increment the expected eoc count otherwise just |
- * skip to the end of the data. |
- */ |
- while (len > 0) |
- { |
- if(asn1_check_eoc(&p, len)) |
- { |
- expected_eoc--; |
- if (expected_eoc == 0) |
- break; |
- len -= 2; |
- continue; |
- } |
- q = p; |
- /* Just read in a header: only care about the length */ |
- if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, |
- -1, 0, 0, NULL)) |
- { |
- ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR); |
- return 0; |
- } |
- if (inf) |
- expected_eoc++; |
- else |
- p += plen; |
- len -= p - q; |
- } |
- if (expected_eoc) |
- { |
- ASN1err(ASN1_F_ASN1_FIND_END, ASN1_R_MISSING_EOC); |
- return 0; |
- } |
- *in = p; |
- return 1; |
- } |
-/* This function collects the asn1 data from a constructred string |
- * type into a buffer. The values of 'in' and 'len' should refer |
- * to the contents of the constructed type and 'inf' should be set |
- * if it is indefinite length. |
- */ |
- |
-#ifndef ASN1_MAX_STRING_NEST |
-/* This determines how many levels of recursion are permitted in ASN1 |
- * string types. If it is not limited stack overflows can occur. If set |
- * to zero no recursion is allowed at all. Although zero should be adequate |
- * examples exist that require a value of 1. So 5 should be more than enough. |
- */ |
-#define ASN1_MAX_STRING_NEST 5 |
-#endif |
- |
- |
-static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, |
- char inf, int tag, int aclass, int depth) |
- { |
- const unsigned char *p, *q; |
- long plen; |
- char cst, ininf; |
- p = *in; |
- inf &= 1; |
- /* If no buffer and not indefinite length constructed just pass over |
- * the encoded data */ |
- if (!buf && !inf) |
- { |
- *in += len; |
- return 1; |
- } |
- while(len > 0) |
- { |
- q = p; |
- /* Check for EOC */ |
- if (asn1_check_eoc(&p, len)) |
- { |
- /* EOC is illegal outside indefinite length |
- * constructed form */ |
- if (!inf) |
- { |
- ASN1err(ASN1_F_ASN1_COLLECT, |
- ASN1_R_UNEXPECTED_EOC); |
- return 0; |
- } |
- inf = 0; |
- break; |
- } |
- |
- if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, |
- len, tag, aclass, 0, NULL)) |
- { |
- ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR); |
- return 0; |
- } |
- |
- /* If indefinite length constructed update max length */ |
- if (cst) |
- { |
- if (depth >= ASN1_MAX_STRING_NEST) |
- { |
- ASN1err(ASN1_F_ASN1_COLLECT, |
- ASN1_R_NESTED_ASN1_STRING); |
- return 0; |
- } |
- if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, |
- depth + 1)) |
- return 0; |
- } |
- else if (plen && !collect_data(buf, &p, plen)) |
- return 0; |
- len -= p - q; |
- } |
- if (inf) |
- { |
- ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC); |
- return 0; |
- } |
- *in = p; |
- return 1; |
- } |
- |
-static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen) |
- { |
- int len; |
- if (buf) |
- { |
- len = buf->length; |
- if (!BUF_MEM_grow_clean(buf, len + plen)) |
- { |
- ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE); |
- return 0; |
- } |
- memcpy(buf->data + len, *p, plen); |
- } |
- *p += plen; |
- return 1; |
- } |
- |
-/* Check for ASN1 EOC and swallow it if found */ |
- |
-static int asn1_check_eoc(const unsigned char **in, long len) |
- { |
- const unsigned char *p; |
- if (len < 2) return 0; |
- p = *in; |
- if (!p[0] && !p[1]) |
- { |
- *in += 2; |
- return 1; |
- } |
- return 0; |
- } |
- |
-/* Check an ASN1 tag and length: a bit like ASN1_get_object |
- * but it sets the length for indefinite length constructed |
- * form, we don't know the exact length but we can set an |
- * upper bound to the amount of data available minus the |
- * header length just read. |
- */ |
- |
-static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, |
- char *inf, char *cst, |
- const unsigned char **in, long len, |
- int exptag, int expclass, char opt, |
- ASN1_TLC *ctx) |
- { |
- int i; |
- int ptag, pclass; |
- long plen; |
- const unsigned char *p, *q; |
- p = *in; |
- q = p; |
- |
- if (ctx && ctx->valid) |
- { |
- i = ctx->ret; |
- plen = ctx->plen; |
- pclass = ctx->pclass; |
- ptag = ctx->ptag; |
- p += ctx->hdrlen; |
- } |
- else |
- { |
- i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); |
- if (ctx) |
- { |
- ctx->ret = i; |
- ctx->plen = plen; |
- ctx->pclass = pclass; |
- ctx->ptag = ptag; |
- ctx->hdrlen = p - q; |
- ctx->valid = 1; |
- /* If definite length, and no error, length + |
- * header can't exceed total amount of data available. |
- */ |
- if (!(i & 0x81) && ((plen + ctx->hdrlen) > len)) |
- { |
- ASN1err(ASN1_F_ASN1_CHECK_TLEN, |
- ASN1_R_TOO_LONG); |
- asn1_tlc_clear(ctx); |
- return 0; |
- } |
- } |
- } |
- |
- if (i & 0x80) |
- { |
- ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER); |
- asn1_tlc_clear(ctx); |
- return 0; |
- } |
- if (exptag >= 0) |
- { |
- if ((exptag != ptag) || (expclass != pclass)) |
- { |
- /* If type is OPTIONAL, not an error: |
- * indicate missing type. |
- */ |
- if (opt) return -1; |
- asn1_tlc_clear(ctx); |
- ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG); |
- return 0; |
- } |
- /* We have a tag and class match: |
- * assume we are going to do something with it */ |
- asn1_tlc_clear(ctx); |
- } |
- |
- if (i & 1) |
- plen = len - (p - q); |
- |
- if (inf) |
- *inf = i & 1; |
- |
- if (cst) |
- *cst = i & V_ASN1_CONSTRUCTED; |
- |
- if (olen) |
- *olen = plen; |
- |
- if (oclass) |
- *oclass = pclass; |
- |
- if (otag) |
- *otag = ptag; |
- |
- *in = p; |
- return 1; |
- } |