aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/asn1/tasn_dec.c
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2005-04-30 13:06:45 +0000
committerDr. Stephen Henson <steve@openssl.org>2005-04-30 13:06:45 +0000
commite1cc0671ac5814b71867abde28ec03bca51df171 (patch)
tree51f823e8a4c75b0428ea847bae5433cf391199c4 /crypto/asn1/tasn_dec.c
parentc1a8a5de13776c1a7b1bdbef574dd47948f77372 (diff)
downloadopenssl-e1cc0671ac5814b71867abde28ec03bca51df171.tar.gz
Use more efficient way to locate end of an ASN1 structure.
Diffstat (limited to 'crypto/asn1/tasn_dec.c')
-rw-r--r--crypto/asn1/tasn_dec.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
index 46df79519f..39a9d5a9aa 100644
--- a/crypto/asn1/tasn_dec.c
+++ b/crypto/asn1/tasn_dec.c
@@ -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,