Prevent malformed RFC3779 data triggering an assertion failure (CVE-2011-4577)

This commit is contained in:
Dr. Stephen Henson 2012-01-04 18:44:20 +00:00
parent 0c214e0153
commit 0e3a930fb4
2 changed files with 50 additions and 29 deletions

View file

@ -3,6 +3,11 @@
_______________ _______________
Changes between 0.9.8r and 0.9.8s [xx XXX xxxx] Changes between 0.9.8r and 0.9.8s [xx XXX xxxx]
*) Prevent malformed RFC3779 data triggering an assertion failure.
Thanks to Andrew Chi, BBN Technologies, for discovering the flaw
and Rob Austein <sra@hactrn.net> for fixing it. (CVE-2011-4577)
[Rob Austein <sra@hactrn.net>]
*) Fix ssl_ciph.c set-up race. *) Fix ssl_ciph.c set-up race.
[Adam Langley (Google)] [Adam Langley (Google)]

View file

@ -142,12 +142,13 @@ unsigned int v3_addr_get_afi(const IPAddressFamily *f)
* Expand the bitstring form of an address into a raw byte array. * Expand the bitstring form of an address into a raw byte array.
* At the moment this is coded for simplicity, not speed. * At the moment this is coded for simplicity, not speed.
*/ */
static void addr_expand(unsigned char *addr, static int addr_expand(unsigned char *addr,
const ASN1_BIT_STRING *bs, const ASN1_BIT_STRING *bs,
const int length, const int length,
const unsigned char fill) const unsigned char fill)
{ {
OPENSSL_assert(bs->length >= 0 && bs->length <= length); if (bs->length < 0 || bs->length > length)
return 0;
if (bs->length > 0) { if (bs->length > 0) {
memcpy(addr, bs->data, bs->length); memcpy(addr, bs->data, bs->length);
if ((bs->flags & 7) != 0) { if ((bs->flags & 7) != 0) {
@ -159,6 +160,7 @@ static void addr_expand(unsigned char *addr,
} }
} }
memset(addr + bs->length, fill, length - bs->length); memset(addr + bs->length, fill, length - bs->length);
return 1;
} }
/* /*
@ -181,15 +183,13 @@ static int i2r_address(BIO *out,
return 0; return 0;
switch (afi) { switch (afi) {
case IANA_AFI_IPV4: case IANA_AFI_IPV4:
if (bs->length > 4) if (!addr_expand(addr, bs, 4, fill))
return 0; return 0;
addr_expand(addr, bs, 4, fill);
BIO_printf(out, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); BIO_printf(out, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
break; break;
case IANA_AFI_IPV6: case IANA_AFI_IPV6:
if (bs->length > 16) if (!addr_expand(addr, bs, 16, fill))
return 0; return 0;
addr_expand(addr, bs, 16, fill);
for (n = 16; n > 1 && addr[n-1] == 0x00 && addr[n-2] == 0x00; n -= 2) for (n = 16; n > 1 && addr[n-1] == 0x00 && addr[n-2] == 0x00; n -= 2)
; ;
for (i = 0; i < n; i += 2) for (i = 0; i < n; i += 2)
@ -315,6 +315,12 @@ static int i2r_IPAddrBlocks(X509V3_EXT_METHOD *method,
/* /*
* Sort comparison function for a sequence of IPAddressOrRange * Sort comparison function for a sequence of IPAddressOrRange
* elements. * elements.
*
* There's no sane answer we can give if addr_expand() fails, and an
* assertion failure on externally supplied data is seriously uncool,
* so we just arbitrarily declare that if given invalid inputs this
* function returns -1. If this messes up your preferred sort order
* for garbage input, tough noogies.
*/ */
static int IPAddressOrRange_cmp(const IPAddressOrRange *a, static int IPAddressOrRange_cmp(const IPAddressOrRange *a,
const IPAddressOrRange *b, const IPAddressOrRange *b,
@ -327,22 +333,26 @@ static int IPAddressOrRange_cmp(const IPAddressOrRange *a,
switch (a->type) { switch (a->type) {
case IPAddressOrRange_addressPrefix: case IPAddressOrRange_addressPrefix:
addr_expand(addr_a, a->u.addressPrefix, length, 0x00); if (!addr_expand(addr_a, a->u.addressPrefix, length, 0x00))
return -1;
prefixlen_a = addr_prefixlen(a->u.addressPrefix); prefixlen_a = addr_prefixlen(a->u.addressPrefix);
break; break;
case IPAddressOrRange_addressRange: case IPAddressOrRange_addressRange:
addr_expand(addr_a, a->u.addressRange->min, length, 0x00); if (!addr_expand(addr_a, a->u.addressRange->min, length, 0x00))
return -1;
prefixlen_a = length * 8; prefixlen_a = length * 8;
break; break;
} }
switch (b->type) { switch (b->type) {
case IPAddressOrRange_addressPrefix: case IPAddressOrRange_addressPrefix:
addr_expand(addr_b, b->u.addressPrefix, length, 0x00); if (!addr_expand(addr_b, b->u.addressPrefix, length, 0x00))
return -1;
prefixlen_b = addr_prefixlen(b->u.addressPrefix); prefixlen_b = addr_prefixlen(b->u.addressPrefix);
break; break;
case IPAddressOrRange_addressRange: case IPAddressOrRange_addressRange:
addr_expand(addr_b, b->u.addressRange->min, length, 0x00); if (!addr_expand(addr_b, b->u.addressRange->min, length, 0x00))
return -1;
prefixlen_b = length * 8; prefixlen_b = length * 8;
break; break;
} }
@ -658,22 +668,22 @@ int v3_addr_add_range(IPAddrBlocks *addr,
/* /*
* Extract min and max values from an IPAddressOrRange. * Extract min and max values from an IPAddressOrRange.
*/ */
static void extract_min_max(IPAddressOrRange *aor, static int extract_min_max(IPAddressOrRange *aor,
unsigned char *min, unsigned char *min,
unsigned char *max, unsigned char *max,
int length) int length)
{ {
OPENSSL_assert(aor != NULL && min != NULL && max != NULL); if (aor == NULL || min == NULL || max == NULL)
return 0;
switch (aor->type) { switch (aor->type) {
case IPAddressOrRange_addressPrefix: case IPAddressOrRange_addressPrefix:
addr_expand(min, aor->u.addressPrefix, length, 0x00); return (addr_expand(min, aor->u.addressPrefix, length, 0x00) &&
addr_expand(max, aor->u.addressPrefix, length, 0xFF); addr_expand(max, aor->u.addressPrefix, length, 0xFF));
return;
case IPAddressOrRange_addressRange: case IPAddressOrRange_addressRange:
addr_expand(min, aor->u.addressRange->min, length, 0x00); return (addr_expand(min, aor->u.addressRange->min, length, 0x00) &&
addr_expand(max, aor->u.addressRange->max, length, 0xFF); addr_expand(max, aor->u.addressRange->max, length, 0xFF));
return;
} }
return 0;
} }
/* /*
@ -689,9 +699,10 @@ int v3_addr_get_range(IPAddressOrRange *aor,
if (aor == NULL || min == NULL || max == NULL || if (aor == NULL || min == NULL || max == NULL ||
afi_length == 0 || length < afi_length || afi_length == 0 || length < afi_length ||
(aor->type != IPAddressOrRange_addressPrefix && (aor->type != IPAddressOrRange_addressPrefix &&
aor->type != IPAddressOrRange_addressRange)) aor->type != IPAddressOrRange_addressRange) ||
!extract_min_max(aor, min, max, afi_length))
return 0; return 0;
extract_min_max(aor, min, max, afi_length);
return afi_length; return afi_length;
} }
@ -773,8 +784,9 @@ int v3_addr_is_canonical(IPAddrBlocks *addr)
IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j); IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, j + 1); IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, j + 1);
extract_min_max(a, a_min, a_max, length); if (!extract_min_max(a, a_min, a_max, length) ||
extract_min_max(b, b_min, b_max, length); !extract_min_max(b, b_min, b_max, length))
return 0;
/* /*
* Punt misordered list, overlapping start, or inverted range. * Punt misordered list, overlapping start, or inverted range.
@ -809,7 +821,8 @@ int v3_addr_is_canonical(IPAddrBlocks *addr)
{ {
IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j); IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
if (a != NULL && a->type == IPAddressOrRange_addressRange) { if (a != NULL && a->type == IPAddressOrRange_addressRange) {
extract_min_max(a, a_min, a_max, length); if (!extract_min_max(a, a_min, a_max, length))
return 0;
if (memcmp(a_min, a_max, length) > 0 || if (memcmp(a_min, a_max, length) > 0 ||
range_should_be_prefix(a_min, a_max, length) >= 0) range_should_be_prefix(a_min, a_max, length) >= 0)
return 0; return 0;
@ -845,8 +858,9 @@ static int IPAddressOrRanges_canonize(IPAddressOrRanges *aors,
unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN]; unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN]; unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN];
extract_min_max(a, a_min, a_max, length); if (!extract_min_max(a, a_min, a_max, length) ||
extract_min_max(b, b_min, b_max, length); !extract_min_max(b, b_min, b_max, length))
return 0;
/* /*
* Punt inverted ranges. * Punt inverted ranges.
@ -1132,13 +1146,15 @@ static int addr_contains(IPAddressOrRanges *parent,
p = 0; p = 0;
for (c = 0; c < sk_IPAddressOrRange_num(child); c++) { for (c = 0; c < sk_IPAddressOrRange_num(child); c++) {
extract_min_max(sk_IPAddressOrRange_value(child, c), if (!extract_min_max(sk_IPAddressOrRange_value(child, c),
c_min, c_max, length); c_min, c_max, length))
return -1;
for (;; p++) { for (;; p++) {
if (p >= sk_IPAddressOrRange_num(parent)) if (p >= sk_IPAddressOrRange_num(parent))
return 0; return 0;
extract_min_max(sk_IPAddressOrRange_value(parent, p), if (!extract_min_max(sk_IPAddressOrRange_value(parent, p),
p_min, p_max, length); p_min, p_max, length))
return 0;
if (memcmp(p_max, c_max, length) < 0) if (memcmp(p_max, c_max, length) < 0)
continue; continue;
if (memcmp(p_min, c_min, length) > 0) if (memcmp(p_min, c_min, length) > 0)