Fix buffer overrun in ASN1_parse().

Backport of commits:

        79c7f74d6c
	bdcd660e33

from master.

Reviewed-by: Matt Caswell <matt@openssl.org>
This commit is contained in:
Viktor Dukhovni 2016-04-19 22:23:24 -04:00
parent 3d411057a5
commit 697283ba41
2 changed files with 20 additions and 15 deletions

View File

@ -63,7 +63,7 @@
#include <openssl/asn1_mac.h> #include <openssl/asn1_mac.h>
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
int max); long max);
static void asn1_put_length(unsigned char **pp, int length); static void asn1_put_length(unsigned char **pp, int length);
const char ASN1_version[] = "ASN.1" OPENSSL_VERSION_PTEXT; const char ASN1_version[] = "ASN.1" OPENSSL_VERSION_PTEXT;
@ -131,7 +131,7 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
} }
*ptag = tag; *ptag = tag;
*pclass = xclass; *pclass = xclass;
if (!asn1_get_length(&p, &inf, plength, (int)max)) if (!asn1_get_length(&p, &inf, plength, max))
goto err; goto err;
if (inf && !(ret & V_ASN1_CONSTRUCTED)) if (inf && !(ret & V_ASN1_CONSTRUCTED))
@ -159,14 +159,14 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
} }
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
int max) long max)
{ {
const unsigned char *p = *pp; const unsigned char *p = *pp;
unsigned long ret = 0; unsigned long ret = 0;
unsigned int i; unsigned long i;
if (max-- < 1) if (max-- < 1)
return (0); return 0;
if (*p == 0x80) { if (*p == 0x80) {
*inf = 1; *inf = 1;
ret = 0; ret = 0;
@ -175,15 +175,11 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
*inf = 0; *inf = 0;
i = *p & 0x7f; i = *p & 0x7f;
if (*(p++) & 0x80) { if (*(p++) & 0x80) {
if (i > sizeof(long)) if (i > sizeof(ret) || max < i)
return 0; return 0;
if (max-- == 0)
return (0);
while (i-- > 0) { while (i-- > 0) {
ret <<= 8L; ret <<= 8L;
ret |= *(p++); ret |= *(p++);
if (max-- == 0)
return (0);
} }
} else } else
ret = i; ret = i;
@ -192,7 +188,7 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
return 0; return 0;
*pp = p; *pp = p;
*rl = (long)ret; *rl = (long)ret;
return (1); return 1;
} }
/* /*

View File

@ -173,6 +173,8 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0)) if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0))
goto end; goto end;
if (j & V_ASN1_CONSTRUCTED) { if (j & V_ASN1_CONSTRUCTED) {
const unsigned char *sp;
ep = p + len; ep = p + len;
if (BIO_write(bp, "\n", 1) <= 0) if (BIO_write(bp, "\n", 1) <= 0)
goto end; goto end;
@ -182,6 +184,7 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
goto end; goto end;
} }
if ((j == 0x21) && (len == 0)) { if ((j == 0x21) && (len == 0)) {
sp = p;
for (;;) { for (;;) {
r = asn1_parse2(bp, &p, (long)(tot - p), r = asn1_parse2(bp, &p, (long)(tot - p),
offset + (p - *pp), depth + 1, offset + (p - *pp), depth + 1,
@ -190,19 +193,25 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
ret = 0; ret = 0;
goto end; goto end;
} }
if ((r == 2) || (p >= tot)) if ((r == 2) || (p >= tot)) {
len = p - sp;
break; break;
}
} }
} else } else {
long tmp = len;
while (p < ep) { while (p < ep) {
r = asn1_parse2(bp, &p, (long)len, sp = p;
offset + (p - *pp), depth + 1, r = asn1_parse2(bp, &p, tmp, offset + (p - *pp), depth + 1,
indent, dump); indent, dump);
if (r == 0) { if (r == 0) {
ret = 0; ret = 0;
goto end; goto end;
} }
tmp -= p - sp;
} }
}
} else if (xclass != 0) { } else if (xclass != 0) {
p += len; p += len;
if (BIO_write(bp, "\n", 1) <= 0) if (BIO_write(bp, "\n", 1) <= 0)