Prevent malformed RFC3779 data triggering an assertion failure (CVE-2011-4577)
This commit is contained in:
parent
0c214e0153
commit
0e3a930fb4
2 changed files with 50 additions and 29 deletions
5
CHANGES
5
CHANGES
|
@ -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)]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue