openssl: add support for IP addr blocks in X.509 certificates
authorMichael Rossberg <michael.rossberg@tu-ilmenau.de>
Wed, 22 May 2013 07:51:10 +0000 (09:51 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 24 May 2013 13:09:47 +0000 (15:09 +0200)
src/libstrongswan/plugins/openssl/openssl_x509.c

index 676b97f..c98e805 100644 (file)
@@ -17,6 +17,9 @@
  */
 
 /*
+ * Copyright (C) 2013 Michael Rossberg
+ * Copyright (C) 2013 Technische Universit├Ąt Ilmenau
+ *
  * Copyright (C) 2010 secunet Security Networks AG
  * Copyright (C) 2010 Thomas Egerer
  *
 #include <utils/debug.h>
 #include <asn1/oid.h>
 #include <collections/linked_list.h>
+#include <selectors/traffic_selector.h>
 
+/* IP Addr block extension support was introduced with 0.9.8e */
+#if OPENSSL_VERSION_NUMBER < 0x0090805fL
+#define OPENSSL_NO_RFC3779
+#endif
 
 typedef struct private_openssl_x509_t private_openssl_x509_t;
 
@@ -150,6 +158,12 @@ struct private_openssl_x509_t {
        linked_list_t *ocsp_uris;
 
        /**
+        * List of ipAddrBlocks as traffic_selector_t
+        */
+       linked_list_t *ipAddrBlocks;
+
+
+       /**
         * References to this cert
         */
        refcount_t ref;
@@ -283,6 +297,12 @@ METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*,
        return this->ocsp_uris->create_enumerator(this->ocsp_uris);
 }
 
+METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*,
+       private_openssl_x509_t *this)
+{
+       return this->ipAddrBlocks->create_enumerator(this->ipAddrBlocks);
+}
+
 METHOD(certificate_t, get_type, certificate_type_t,
        private_openssl_x509_t *this)
 {
@@ -506,6 +526,8 @@ METHOD(certificate_t, destroy, void,
                                                                                offsetof(identification_t, destroy));
                this->crl_uris->destroy_function(this->crl_uris, (void*)crl_uri_destroy);
                this->ocsp_uris->destroy_function(this->ocsp_uris, free);
+               this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks,
+                                                                               offsetof(traffic_selector_t, destroy));
                free(this);
        }
 }
@@ -542,7 +564,7 @@ static private_openssl_x509_t *create_empty()
                                .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
                                .create_crl_uri_enumerator = _create_crl_uri_enumerator,
                                .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator,
-                               .create_ipAddrBlock_enumerator = (void*)enumerator_create_empty,
+                               .create_ipAddrBlock_enumerator = _create_ipAddrBlock_enumerator,
                                .create_name_constraint_enumerator = (void*)enumerator_create_empty,
                                .create_cert_policy_enumerator = (void*)enumerator_create_empty,
                                .create_policy_mapping_enumerator = (void*)enumerator_create_empty,
@@ -552,6 +574,7 @@ static private_openssl_x509_t *create_empty()
                .issuerAltNames = linked_list_create(),
                .crl_uris = linked_list_create(),
                .ocsp_uris = linked_list_create(),
+               .ipAddrBlocks = linked_list_create(),
                .pathlen = X509_NO_CONSTRAINT,
                .ref = 1,
        );
@@ -772,6 +795,92 @@ static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this,
        return TRUE;
 }
 
+#ifndef OPENSSL_NO_RFC3779
+
+/**
+ * Parse a single block of ipAddrBlock extension
+ */
+static void parse_ipAddrBlock_ext_fam(private_openssl_x509_t *this,
+                                                                         IPAddressFamily *fam)
+{
+       const IPAddressOrRanges *list;
+       IPAddressOrRange *aor;
+       traffic_selector_t *ts;
+       ts_type_t type;
+       chunk_t from, to;
+       int i, afi;
+
+       if (fam->ipAddressChoice->type != IPAddressChoice_addressesOrRanges)
+       {
+               return;
+       }
+
+       afi = v3_addr_get_afi(fam);
+       switch (afi)
+       {
+               case IANA_AFI_IPV4:
+                       from = chunk_alloca(4);
+                       to = chunk_alloca(4);
+                       type = TS_IPV4_ADDR_RANGE;
+                       break;
+               case IANA_AFI_IPV6:
+                       from = chunk_alloca(16);
+                       to = chunk_alloca(16);
+                       type = TS_IPV6_ADDR_RANGE;
+                       break;
+               default:
+                       return;
+       }
+
+       list = fam->ipAddressChoice->u.addressesOrRanges;
+       for (i = 0; i < sk_IPAddressOrRange_num(list); i++)
+       {
+               aor = sk_IPAddressOrRange_value(list, i);
+               if (v3_addr_get_range(aor, afi, from.ptr, to.ptr, from.len) > 0)
+               {
+                       ts = traffic_selector_create_from_bytes(0, type, from, 0, to, 65535);
+                       if (ts)
+                       {
+                               this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts);
+                       }
+               }
+       }
+}
+
+/**
+ * Parse ipAddrBlock extension
+ */
+static bool parse_ipAddrBlock_ext(private_openssl_x509_t *this,
+                                                                 X509_EXTENSION *ext)
+{
+       STACK_OF(IPAddressFamily) *blocks;
+       IPAddressFamily *fam;
+
+       blocks = (STACK_OF(IPAddressFamily)*)X509V3_EXT_d2i(ext);
+       if (!blocks)
+       {
+               return FALSE;
+       }
+
+       if (!v3_addr_is_canonical(blocks))
+       {
+               sk_IPAddressFamily_free(blocks);
+               return FALSE;
+       }
+
+       while (sk_IPAddressFamily_num(blocks) > 0)
+       {
+               fam = sk_IPAddressFamily_pop(blocks);
+               parse_ipAddrBlock_ext_fam(this, fam);
+               IPAddressFamily_free(fam);
+       }
+       sk_IPAddressFamily_free(blocks);
+
+       this->flags |= X509_IP_ADDR_BLOCKS;
+       return TRUE;
+}
+#endif /* !OPENSSL_NO_RFC3779 */
+
 /**
  * Parse authorityKeyIdentifier extension
  */
@@ -857,6 +966,11 @@ static bool parse_extensions(private_openssl_x509_t *this)
                                case NID_crl_distribution_points:
                                        ok = parse_crlDistributionPoints_ext(this, ext);
                                        break;
+#ifndef OPENSSL_NO_RFC3779
+                               case NID_sbgp_ipAddrBlock:
+                                       ok = parse_ipAddrBlock_ext(this, ext);
+                                       break;
+#endif /* !OPENSSL_NO_RFC3779 */
                                default:
                                        ok = X509_EXTENSION_get_critical(ext) == 0 ||
                                                 !lib->settings->get_bool(lib->settings,