tasn_dec.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/* tasn_dec.c */
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
* project 2000.
*/
/* ====================================================================
* Copyright (c) 2000 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
* 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>
static int asn1_template_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
/* Table to convert tags to bit values, used for MSTRING type */
static unsigned long tag2bit[32]={
0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */
};
unsigned long ASN1_tag2bit(int tag)
{
}
/* Macro to initialize and invalidate the cache */
#define asn1_tlc_clear(c) if(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_TLC c;
asn1_tlc_clear(&c);
return *pval;
return NULL;
}
{
ASN1_TLC c;
asn1_tlc_clear(&c);
}
/* Decode an item, taking care of IMPLICIT tagging, if any.
* If 'opt' set and tag mismatch return -1 to handle OPTIONAL
*/
{
const ASN1_COMPAT_FUNCS *cf;
const ASN1_EXTERN_FUNCS *ef;
long tmplen;
int i;
int otag;
int ret = 0;
if(!pval) return 0;
else asn1_cb = 0;
case ASN1_ITYPE_PRIMITIVE:
/* 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.
*/
goto err;
}
}
break;
case ASN1_ITYPE_MSTRING:
p = *in;
/* Just read in tag and class */
if(!ret) {
goto err;
}
/* Must be UNIVERSAL class */
if(oclass != V_ASN1_UNIVERSAL) {
/* If OPTIONAL, assume this is OK */
if(opt) return -1;
goto err;
}
/* Check tag matches bit map */
/* If OPTIONAL, assume this is OK */
if(opt) return -1;
goto err;
}
case ASN1_ITYPE_EXTERN:
/* Use new style d2i */
case ASN1_ITYPE_COMPAT:
/* we must resort to old style evil hackery */
/* If OPTIONAL see if it is there */
if(opt) {
int exptag;
p = *in;
/* Don't care about anything other than presence of expected tag */
if(!ret) {
goto err;
}
}
/* 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) {
p = *in;
imphack = *p;
}
if(ptmpval) return 1;
goto err;
case ASN1_ITYPE_CHOICE:
goto auxerr;
/* Allocate structure */
if(!*pval) {
goto err;
}
}
/* CHOICE type, try each possibility in turn */
p = *in;
/* We mark field as OPTIONAL so its absence
* can be recognised.
*/
/* 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 */
goto err;
}
/* Did we fall off the end without reading anything? */
/* If OPTIONAL, this is OK */
if(opt) {
/* Free and zero it */
return -1;
}
goto err;
}
*in = p;
goto auxerr;
return 1;
case ASN1_ITYPE_SEQUENCE:
p = *in;
/* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
if(tag == -1) {
}
/* Get SEQUENCE length and update len, p */
if(!ret) {
goto err;
seq_nolen = 1;
if(!cst) {
goto err;
}
if(!*pval) {
goto err;
}
}
goto auxerr;
/* Get each field entry */
const ASN1_TEMPLATE *seqtt;
/* Have we ran out of data? */
if(!len) break;
q = p;
if(asn1_check_eoc(&p, len)) {
if(!seq_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.
*/
/* attempt to read in field, allowing each to be OPTIONAL */
if(!ret) {
goto err;
} else if(ret == -1) {
/* OPTIONAL component absent. Free and zero the field
*/
continue;
}
/* Update length */
len -= p - q;
}
/* Check for EOC if expecting one */
goto err;
}
/* Check all data read */
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.
*/
const ASN1_TEMPLATE *seqtt;
} else {
goto err;
}
}
/* Save encoding */
*in = p;
goto auxerr;
return 1;
default:
return 0;
}
err:
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, unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
{
int ret;
long len;
unsigned char *p, *q;
char exp_eoc;
if(!val) return 0;
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.
*/
q = p;
if(!ret) {
return 0;
if(!cst) {
return 0;
}
/* We've found the field so it can't be OPTIONAL now */
if(!ret) {
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)) {
goto err;
}
} else {
/* Otherwise we must hit the EXPLICIT tag end or its an error */
if(len) {
goto err;
}
}
} else
*in = p;
return 1;
err:
return 0;
}
static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
{
int ret;
unsigned char *p, *q;
if(!val) return 0;
p = *in;
q = p;
if(flags & ASN1_TFLG_SK_MASK) {
/* SET OF, SEQUENCE OF */
char sk_eoc;
/* First work out expected inner tag value */
if(flags & ASN1_TFLG_IMPTAG) {
} else {
else sktag = V_ASN1_SEQUENCE;
}
/* Get the tag */
if(!ret) {
return 0;
else {
/* We've got a valid STACK: free up any items present */
}
}
if(!*val) {
goto err;
}
/* Read as many items as we can */
while(len > 0) {
q = p;
/* See if EOC found */
if(asn1_check_eoc(&p, len)) {
if(!sk_eoc) {
goto err;
}
len -= p - q;
sk_eoc = 0;
break;
}
goto err;
}
len -= p - q;
goto err;
}
}
if(sk_eoc) {
goto err;
}
} else if(flags & ASN1_TFLG_IMPTAG) {
/* IMPLICIT tagging */
if(!ret) {
goto err;
} else {
/* Nothing special */
if(!ret) {
goto err;
}
*in = p;
return 1;
err:
return 0;
}
{
long plen;
unsigned char *p;
long len;
if(!pval) {
return 0; /* Should never happen */
}
tag = -1;
if(utype == V_ASN1_ANY) {
/* If type is ANY need to figure out type from tag */
unsigned char oclass;
if(tag >= 0) {
return 0;
}
if(opt) {
return 0;
}
p = *in;
if(!ret) {
return 0;
}
}
if(tag == -1) {
}
p = *in;
/* Check header */
if(!ret) {
return 0;
/* SEQUENCE, SET and "OTHER" are left in encoded form */
/* Clear context cache for type OTHER because the auto clear when
* we have a exact match wont work
*/
if(utype == V_ASN1_OTHER) {
/* SEQUENCE and SET must be constructed */
} else if(!cst) {
return 0;
}
/* If indefinite length constructed find the real end */
if(inf) {
} else {
p += plen;
}
} else if(cst) {
/* 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.
*/
/* Append a final null to string */
return 0;
}
free_cont = 1;
} else {
cont = p;
p += plen;
}
/* We now have content length and type: translate into a structure */
*in = p;
ret = 1;
err:
return ret;
}
/* Translate ASN1 content octets into a structure */
int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it)
{
int ret = 0;
const ASN1_PRIMITIVE_FUNCS *pf;
ASN1_INTEGER **tint;
/* If ANY type clear type and set pointer to internal value */
if(!*pval) {
typ = ASN1_TYPE_new();
}
switch(utype) {
case V_ASN1_OBJECT:
break;
case V_ASN1_NULL:
if(len) {
goto err;
}
break;
case V_ASN1_BOOLEAN:
if(len != 1) {
goto err;
} else {
}
break;
case V_ASN1_BIT_STRING:
break;
case V_ASN1_INTEGER:
case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
case V_ASN1_NEG_ENUMERATED:
/* Fixup type to match the expected form */
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:
/* All based on ASN1_STRING and handled the same */
if(!*pval) {
if(!stmp) {
goto err;
}
} else {
}
/* If we've already allocated a buffer use it */
if(*free_cont) {
*free_cont = 0;
} else {
goto err;
}
}
break;
}
/* If ASN1_ANY and NULL type fix up value */
ret = 1;
err:
if(!ret)
{
if (opval)
}
return ret;
}
/* 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. If 'buf' is NULL then we just want
* to find the end of the current structure: useful for indefinite
* length constructed stuff.
*/
{
unsigned char *p, *q;
long plen;
p = *in;
inf &= 1;
/* If no buffer and not indefinite length constructed just pass over the encoded data */
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) {
return 0;
}
inf = 0;
break;
}
return 0;
}
/* If indefinite length constructed update max length */
if(cst) {
} else {
}
len -= p - q;
}
if(inf) {
return 0;
}
*in = p;
return 1;
}
{
int len;
if(buf) {
return 0;
}
}
*p += plen;
return 1;
}
/* Check for ASN1 EOC and swallow it if found */
{
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.
*/
{
int i;
long plen;
unsigned char *p, *q;
p = *in;
q = p;
} else {
if(ctx) {
/* If definite length, and no error, length +
* header can't exceed total amount of data available.
*/
return 0;
}
}
}
if(i & 0x80) {
return 0;
}
if(exptag >= 0) {
/* If type is OPTIONAL, not an error, but indicate missing
* type.
*/
if(opt) return -1;
return 0;
}
/* We have a tag and class match, so assume we are going to do something with it */
}
*in = p;
return 1;
}