Commit e1cc0671 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Use more efficient way to locate end of an ASN1 structure.

parent c1a8a5de
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1035,6 +1035,7 @@ void ERR_load_ASN1_strings(void);
#define ASN1_F_ASN1_DUP					 111
#define ASN1_F_ASN1_ENUMERATED_SET			 112
#define ASN1_F_ASN1_ENUMERATED_TO_BN			 113
#define ASN1_F_ASN1_FIND_END				 190
#define ASN1_F_ASN1_GENERALIZEDTIME_SET			 185
#define ASN1_F_ASN1_GENERATE_V3				 178
#define ASN1_F_ASN1_GET_OBJECT				 114
+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ static ERR_STRING_DATA ASN1_str_functs[]=
{ERR_FUNC(ASN1_F_ASN1_DUP),	"ASN1_dup"},
{ERR_FUNC(ASN1_F_ASN1_ENUMERATED_SET),	"ASN1_ENUMERATED_set"},
{ERR_FUNC(ASN1_F_ASN1_ENUMERATED_TO_BN),	"ASN1_ENUMERATED_to_BN"},
{ERR_FUNC(ASN1_F_ASN1_FIND_END),	"ASN1_FIND_END"},
{ERR_FUNC(ASN1_F_ASN1_GENERALIZEDTIME_SET),	"ASN1_GENERALIZEDTIME_set"},
{ERR_FUNC(ASN1_F_ASN1_GENERATE_V3),	"ASN1_generate_v3"},
{ERR_FUNC(ASN1_F_ASN1_GET_OBJECT),	"ASN1_get_object"},
+59 −4
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@
#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);
@@ -848,7 +849,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
		/* 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;
			}
@@ -1053,12 +1054,66 @@ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
	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,