Bug in crypto/x509v3/v3_addr.c, discovered by Frank Ellermann.  Under
certain conditions, the code for constructing RFC 3779 IPAddrBlocks
extensions (v2i_IPAddrBlocks() and the functions it calls) will allow
an inverted range (range end before range start), which is a violation
of RFC 3779 canonical form.

The attached patch was written against OpenSSL 1.0.0b, but should
apply to all supported versions.


Index: crypto/x509v3/v3_addr.c
--- crypto/x509v3/v3_addr.c.~1~ 2009-03-15 15:04:42.000000000 +0100
+++ crypto/x509v3/v3_addr.c     2011-03-30 12:01:04.000000000 +0200
@@ -377,6 +377,7 @@
   unsigned char mask;
   int i, j;
 
+  OPENSSL_assert(memcmp(min, max, length) <= 0);
   for (i = 0; i < length && min[i] == max[i]; i++)
     ;
   for (j = length - 1; j >= 0 && min[j] == 0x00 && max[j] == 0xFF; j--)
@@ -794,14 +795,16 @@
     }
 
     /*
-     * Check final range to see if it should be a prefix.
+     * Check range to see if it's inverted or should be a
+     * prefix.
      */
     j = sk_IPAddressOrRange_num(aors) - 1;
     {
       IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
-      if (a->type == IPAddressOrRange_addressRange) {
+      if (a != NULL && a->type == IPAddressOrRange_addressRange) {
        extract_min_max(a, a_min, a_max, length);
-       if (range_should_be_prefix(a_min, a_max, length) >= 0)
+       if (memcmp(a_min, a_max, length) > 0 ||
+           range_should_be_prefix(a_min, a_max, length) >= 0)
          return 0;
       }
     }
@@ -839,6 +842,13 @@
     extract_min_max(b, b_min, b_max, length);
 
     /*
+     * Punt inverted ranges.
+     */
+    if (memcmp(a_min, a_max, length) > 0 ||
+       memcmp(b_min, b_max, length) > 0)
+      return 0;
+
+    /*
      * Punt overlaps.
      */
     if (memcmp(a_max, b_min, length) >= 0)
@@ -863,6 +873,20 @@
     }
   }
 
+  /*
+   * Check for inverted final range.
+   */
+  j = sk_IPAddressOrRange_num(aors) - 1;
+  {
+    IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
+    if (a != NULL && a->type == IPAddressOrRange_addressRange) {
+      unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
+      extract_min_max(a, a_min, a_max, length);
+      if (memcmp(a_min, a_max, length) > 0)
+       return 0;
+    }
+  }
+
   return 1;
 }
 
@@ -1011,6 +1035,11 @@
        X509V3_conf_err(val);
        goto err;
       }
+      if (memcmp(min, max, length_from_afi(afi)) > 0) {
+       X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_EXTENSION_VALUE_ERROR);
+       X509V3_conf_err(val);
+       goto err;
+      }
       if (!v3_addr_add_range(addr, afi, safi, min, max)) {
        X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE);
        goto err;

Reply via email to