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

This commit is contained in:
Dr. Stephen Henson 2005-04-30 13:06:45 +00:00
parent c1a8a5de13
commit e1cc0671ac
3 changed files with 61 additions and 4 deletions

View file

@ -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

View file

@ -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"},

View file

@ -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,