Add intelligence to asn1_d2i_read_bio for reading entire header without blocking for extra data

Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/30401)
This commit is contained in:
Daniel Sands 2026-03-12 11:59:13 -06:00 committed by Dmitry Belyavskiy
parent 674c23d265
commit 35852da1d9
2 changed files with 50 additions and 4 deletions

View file

@ -104,7 +104,7 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
}
#endif
#define HEADER_SIZE 8
#define HEADER_SIZE 2
#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
{
@ -140,7 +140,7 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
}
i = BIO_read(in, &(b->data[len]), (int)want);
if (i <= 0 && diff == 0) {
if (i <= 0) {
ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA);
goto err;
}
@ -157,11 +157,57 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
}
/* else data already loaded */
/* make sure there is enough data for a complete header */
p = (unsigned char *)&(b->data[off]);
q = p;
diff = len - off;
if (diff == 0)
if (diff < 2) {
/* Failed sanity check */
ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA);
goto err;
}
diff--;
if ((*(q++) & V_ASN1_PRIMITIVE_TAG) == V_ASN1_PRIMITIVE_TAG) {
/* Multi-byte tag. See if we have the whole thing yet */
do {
diff--;
} while (diff > 0 && *(q++) & 0x80);
if (diff == 0) {
/*
* End of current data, will need at least 1 more byte for
* length. 2 if the tag is still incomplete
*/
want = q - p + 2;
if (*q & 0x80) {
want++;
}
continue;
}
}
/* Check the length. This should also work for indefinite length */
diff--;
if (*q & 0x80) {
unsigned int i = *q & 0x7f;
if (i > sizeof(long)) {
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
goto err;
}
if (i > diff) {
want = q - p + i + 1;
continue;
}
}
/*
* We have a complete header now, assuming we didn't hit EOF. Parse the
* tag and length
*/
q = p;
diff = len - off;
inf = ASN1_get_object(&q, &slen, &tag, &xclass, (int)diff);
if (inf & 0x80) {
unsigned long e;

View file

@ -129,7 +129,7 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
*inf = 0;
i = *p & 0x7f;
if (*p++ & 0x80) {
if (max < i + 1)
if (max < i)
return 0;
/* Skip leading zeroes */
while (i > 0 && *p == 0) {