-/* crypto/asn1/a_d2i_fp.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
#include <stdio.h>
#include <limits.h>
-#include "cryptlib.h"
+#include "internal/cryptlib.h"
#include <openssl/buffer.h>
#include <openssl/asn1.h>
p = (unsigned char *)b->data;
ret = d2i(x, &p, len);
err:
- if (b != NULL)
- BUF_MEM_free(b);
+ BUF_MEM_free(b);
return (ret);
}
p = (const unsigned char *)b->data;
ret = ASN1_item_d2i(x, &p, len, it);
err:
- if (b != NULL)
- BUF_MEM_free(b);
+ BUF_MEM_free(b);
return (ret);
}
#endif
#define HEADER_SIZE 8
+#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
{
BUF_MEM *b;
unsigned char *p;
int i;
- ASN1_const_CTX c;
size_t want = HEADER_SIZE;
int eos = 0;
size_t off = 0;
size_t len = 0;
+ const unsigned char *q;
+ long slen;
+ int inf, tag, xclass;
+
b = BUF_MEM_new();
if (b == NULL) {
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
/* else data already loaded */
p = (unsigned char *)&(b->data[off]);
- c.p = p;
- c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag), &(c.xclass),
- len - off);
- if (c.inf & 0x80) {
+ q = p;
+ inf = ASN1_get_object(&q, &slen, &tag, &xclass, len - off);
+ if (inf & 0x80) {
unsigned long e;
e = ERR_GET_REASON(ERR_peek_error());
else
ERR_clear_error(); /* clear error */
}
- i = c.p - p; /* header length */
+ i = q - p; /* header length */
off += i; /* end of data */
- if (c.inf & 1) {
+ if (inf & 1) {
/* no data body so go round again */
eos++;
if (eos < 0) {
goto err;
}
want = HEADER_SIZE;
- } else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) {
+ } else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) {
/* eos value, so go back and read another header */
eos--;
if (eos <= 0)
else
want = HEADER_SIZE;
} else {
- /* suck in c.slen bytes of data */
- want = c.slen;
+ /* suck in slen bytes of data */
+ want = slen;
if (want > (len - off)) {
+ size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
+
want -= (len - off);
if (want > INT_MAX /* BIO_read takes an int length */ ||
len + want < len) {
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
goto err;
}
- if (!BUF_MEM_grow_clean(b, len + want)) {
- ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
- goto err;
- }
while (want > 0) {
- i = BIO_read(in, &(b->data[len]), want);
- if (i <= 0) {
- ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
- ASN1_R_NOT_ENOUGH_DATA);
+ /*
+ * Read content in chunks of increasing size
+ * so we can return an error for EOF without
+ * having to allocate the entire content length
+ * in one go.
+ */
+ size_t chunk = want > chunk_max ? chunk_max : want;
+
+ if (!BUF_MEM_grow_clean(b, len + chunk)) {
+ ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
goto err;
}
+ want -= chunk;
+ while (chunk > 0) {
+ i = BIO_read(in, &(b->data[len]), chunk);
+ if (i <= 0) {
+ ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
+ ASN1_R_NOT_ENOUGH_DATA);
+ goto err;
+ }
/*
* This can't overflow because |len+want| didn't
* overflow.
*/
- len += i;
- want -= i;
+ len += i;
+ chunk -= i;
+ }
+ if (chunk_max < INT_MAX/2)
+ chunk_max *= 2;
}
}
- if (off + c.slen < off) {
+ if (off + slen < off) {
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
goto err;
}
- off += c.slen;
+ off += slen;
if (eos <= 0) {
break;
} else
*pb = b;
return off;
err:
- if (b != NULL)
- BUF_MEM_free(b);
+ BUF_MEM_free(b);
return -1;
}