* project 2000.
*/
/* ====================================================================
- * Copyright (c) 2000-2004 The OpenSSL Project. All rights reserved.
+ * 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
#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);
/* CHOICE type, try each possibility in turn */
pchval = NULL;
p = *in;
- for(i = 0, tt=it->templates; i < it->tcount; i++, tt++)
+ 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
goto err;
}
- if (!*pval && !!ASN1_item_ex_new(pval, it))
+ if (!*pval && !ASN1_item_ex_new(pval, it))
{
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
ERR_R_NESTED_ASN1_ERROR);
/* If NDEF we must have an EOC here */
if (!asn1_check_eoc(&p, len))
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
ASN1_R_MISSING_EOC);
goto err;
}
* an error */
if (len)
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
ASN1_R_EXPLICIT_LENGTH_MISMATCH);
goto err;
}
&p, len, sktag, skaclass, opt, ctx);
if (!ret)
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_NESTED_ASN1_ERROR);
return 0;
}
if (!*val)
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_MALLOC_FAILURE);
goto err;
}
{
if (!sk_eoc)
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ASN1_R_UNEXPECTED_EOC);
goto err;
}
ASN1_ITEM_ptr(tt->item),
-1, 0, 0, ctx))
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_NESTED_ASN1_ERROR);
goto err;
}
len -= p - q;
if (!sk_push((STACK *)*val, (char *)skfield))
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_MALLOC_FAILURE);
goto err;
}
}
if (sk_eoc)
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ASN1_R_MISSING_EOC);
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_MISSING_EOC);
goto err;
}
}
ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx);
if (!ret)
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_NESTED_ASN1_ERROR);
goto err;
}
-1, 0, opt, ctx);
if (!ret)
{
- ASN1err(ASN1_F_ASN1_TEMPLATE_D2I,
+ ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
ERR_R_NESTED_ASN1_ERROR);
goto err;
}
/* If indefinite length constructed find the real end */
if (inf)
{
- if (!asn1_collect(NULL, &p, plen, inf, -1, -1))
+ if (!asn1_find_end(&p, plen, inf))
goto err;
len = p - cont;
}
case V_ASN1_NULL:
if (len)
{
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+ ASN1err(ASN1_F_ASN1_EX_C2I,
ASN1_R_NULL_IS_WRONG_LENGTH);
goto err;
}
case V_ASN1_BOOLEAN:
if (len != 1)
{
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+ ASN1err(ASN1_F_ASN1_EX_C2I,
ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
goto err;
}
stmp = ASN1_STRING_type_new(utype);
if (!stmp)
{
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+ ASN1err(ASN1_F_ASN1_EX_C2I,
ERR_R_MALLOC_FAILURE);
goto err;
}
{
if (!ASN1_STRING_set(stmp, cont, len))
{
- ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+ ASN1err(ASN1_F_ASN1_EX_C2I,
ERR_R_MALLOC_FAILURE);
ASN1_STRING_free(stmp);
*pval = 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. If 'buf' is NULL then we just want
- * to find the end of the current structure: useful for indefinite
- * length constructed stuff.
+ * if it is indefinite length.
*/
static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len,
/* If indefinite length constructed update max length */
if (cst)
{
+#ifdef OPENSSL_ALLOW_NESTED_ASN1_STRINGS
if (!asn1_collect(buf, &p, plen, ininf, tag, aclass))
return 0;
+#else
+ ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING);
+ return 0;
+#endif
}
else if (!collect_data(buf, &p, plen))
return 0;