Added support for CRL Issuers to x509 and OpenSSL plugins
authorMartin Willi <martin@revosec.ch>
Fri, 3 Dec 2010 09:28:46 +0000 (09:28 +0000)
committerMartin Willi <martin@revosec.ch>
Wed, 5 Jan 2011 15:45:55 +0000 (16:45 +0100)
src/libstrongswan/credentials/builder.c
src/libstrongswan/credentials/builder.h
src/libstrongswan/credentials/certificates/x509.h
src/libstrongswan/plugins/openssl/openssl_x509.c
src/libstrongswan/plugins/revocation/revocation_validator.c
src/libstrongswan/plugins/x509/x509_cert.c
src/pki/commands/print.c
src/pluto/crl.c

index c43e5fd..2323f6c 100644 (file)
@@ -41,6 +41,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
        "BUILD_CA_CERT",
        "BUILD_CERT",
        "BUILD_CRL_DISTRIBUTION_POINTS",
+       "BUILD_CRL_ISSUER",
        "BUILD_OCSP_ACCESS_LOCATIONS",
        "BUILD_PATHLEN",
        "BUILD_X509_FLAG",
index dc87da2..390c314 100644 (file)
@@ -89,6 +89,8 @@ enum builder_part_t {
        BUILD_CERT,
        /** CRL distribution point URIs, linked_list_t* containing char* */
        BUILD_CRL_DISTRIBUTION_POINTS,
+       /** CRL issuer for all distribution points follow up, identification_t* */
+       BUILD_CRL_ISSUER,
        /** OCSP AuthorityInfoAccess locations, linked_list_t* containing char* */
        BUILD_OCSP_ACCESS_LOCATIONS,
        /** certificate path length constraint */
index 6e0a500..3f1c4b7 100644 (file)
@@ -112,9 +112,9 @@ struct x509_t {
        enumerator_t* (*create_subjectAltName_enumerator)(x509_t *this);
 
        /**
-        * Create an enumerator over all CRL URIs.
+        * Create an enumerator over all CRL URIs and CRL Issuers.
         *
-        * @return                      enumerator over URIs as char*
+        * @return                      enumerator over URIs (char*, identificiation_t*)
         */
        enumerator_t* (*create_crl_uri_enumerator)(x509_t *this);
 
index aa39bc9..1630d8f 100644 (file)
@@ -137,7 +137,7 @@ struct private_openssl_x509_t {
        linked_list_t *issuerAltNames;
 
        /**
-        * List of CRL URIs
+        * List of CRL URIs, as crl_uri_t
         */
        linked_list_t *crl_uris;
 
@@ -153,6 +153,37 @@ struct private_openssl_x509_t {
 };
 
 /**
+ * CRL URIs with associated issuer
+ */
+typedef struct {
+       identification_t *issuer;
+       linked_list_t *uris;
+} crl_uri_t;
+
+/**
+ * Create a new issuer entry
+ */
+static crl_uri_t *crl_uri_create()
+{
+       crl_uri_t *this;
+
+       INIT(this,
+               .uris = linked_list_create(),
+       );
+       return this;
+}
+
+/**
+ * Destroy a CRL URI struct
+ */
+static void crl_uri_destroy(crl_uri_t *this)
+{
+       this->uris->destroy_function(this->uris, free);
+       DESTROY_IF(this->issuer);
+       free(this);
+}
+
+/**
  * Convert a GeneralName to an identification_t.
  */
 static identification_t *general_name2id(GENERAL_NAME *name)
@@ -252,10 +283,36 @@ METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*,
        return this->subjectAltNames->create_enumerator(this->subjectAltNames);
 }
 
+/**
+ * Convert enumerator value from entry to (uri, issuer)
+ */
+static bool crl_enum_filter(identification_t *issuer_in,
+                                                       char **uri_in, char **uri_out,
+                                                       void *none_in, identification_t **issuer_out)
+{
+       *uri_out = *uri_in;
+       if (issuer_out)
+       {
+               *issuer_out = issuer_in;
+       }
+       return TRUE;
+}
+
+/**
+ * Create inner enumerator over URIs
+ */
+static enumerator_t *crl_enum_create(crl_uri_t *entry)
+{
+       return enumerator_create_filter(entry->uris->create_enumerator(entry->uris),
+                                                               (void*)crl_enum_filter, entry->issuer, NULL);
+}
+
 METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*,
        private_openssl_x509_t *this)
 {
-       return this->crl_uris->create_enumerator(this->crl_uris);
+       return enumerator_create_nested(
+                                                       this->crl_uris->create_enumerator(this->crl_uris),
+                                                       (void*)crl_enum_create, NULL, NULL);
 }
 
 METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*,
@@ -483,7 +540,7 @@ METHOD(certificate_t, destroy, void,
                                                                                offsetof(identification_t, destroy));
                this->issuerAltNames->destroy_offset(this->issuerAltNames,
                                                                                offsetof(identification_t, destroy));
-               this->crl_uris->destroy_function(this->crl_uris, free);
+               this->crl_uris->destroy_function(this->crl_uris, (void*)crl_uri_destroy);
                this->ocsp_uris->destroy_function(this->ocsp_uris, free);
                free(this);
        }
@@ -615,6 +672,11 @@ static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
                cdp = sk_DIST_POINT_value(cdps, i);
                if (cdp)
                {
+                       crl_uri_t *entry;
+
+                       entry = crl_uri_create();
+                       this->crl_uris->insert_last(this->crl_uris, entry);
+
                        if (cdp->distpoint && cdp->distpoint->type == 0 &&
                                cdp->distpoint->name.fullname)
                        {
@@ -627,12 +689,25 @@ static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
                                        {
                                                if (asprintf(&uri, "%Y", id) > 0)
                                                {
-                                                       this->crl_uris->insert_first(this->crl_uris, uri);
+                                                       entry->uris->insert_last(entry->uris, uri);
                                                }
                                                id->destroy(id);
                                        }
                                }
                        }
+                       if (cdp->CRLissuer)
+                       {
+                               name_num = sk_GENERAL_NAME_num(cdp->CRLissuer);
+                               for (j = 0; j < name_num; j++)
+                               {
+                                       id = general_name2id(sk_GENERAL_NAME_value(cdp->CRLissuer, j));
+                                       if (id)
+                                       {       /* get only one */
+                                               entry->issuer = id;
+                                               break;
+                                       }
+                               }
+                       }
                        DIST_POINT_free(cdp);
                }
        }
index 29d2bc1..511a04a 100644 (file)
@@ -476,8 +476,7 @@ static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
        if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
        {
                enumerator = subject->create_crl_uri_enumerator(subject);
-
-               while (enumerator->enumerate(enumerator, &uri))
+               while (enumerator->enumerate(enumerator, &uri, NULL))
                {
                        current = fetch_crl(uri);
                        if (current)
index 559090a..6fcd9f0 100644 (file)
@@ -117,7 +117,7 @@ struct private_x509_cert_t {
        linked_list_t *subjectAltNames;
 
        /**
-        * List of crlDistributionPoints as allocated char*
+        * List of crlDistributionPoints as crl_uri_t
         */
        linked_list_t *crl_uris;
 
@@ -187,6 +187,38 @@ static const chunk_t ASN1_subjectAltName_oid = chunk_from_chars(
 );
 
 /**
+ * CRL URIs with associated issuer
+ */
+typedef struct {
+       identification_t *issuer;
+       linked_list_t *uris;
+} crl_uri_t;
+
+/**
+ * Create a new issuer entry
+ */
+static crl_uri_t *crl_uri_create(identification_t *issuer)
+{
+       crl_uri_t *this;
+
+       INIT(this,
+               .issuer = issuer ? issuer->clone(issuer) : NULL,
+               .uris = linked_list_create(),
+       );
+       return this;
+}
+
+/**
+ * Destroy a CRL URI struct
+ */
+static void crl_uri_destroy(crl_uri_t *this)
+{
+       this->uris->destroy_function(this->uris, free);
+       DESTROY_IF(this->issuer);
+       free(this);
+}
+
+/**
  * ASN.1 definition of a basicConstraints extension
  */
 static const asn1Object_t basicConstraintsObjects[] = {
@@ -649,12 +681,14 @@ static const asn1Object_t crlDistributionPointsObjects[] = {
        { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /*  7 */
        { 2,     "reasons",                             ASN1_CONTEXT_C_1,       ASN1_OPT|ASN1_BODY      }, /*  8 */
        { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /*  9 */
-       { 2,     "crlIssuer",                   ASN1_CONTEXT_C_2,       ASN1_OPT|ASN1_BODY      }, /* 10 */
+       { 2,     "crlIssuer",                   ASN1_CONTEXT_C_2,       ASN1_OPT|ASN1_OBJ       }, /* 10 */
        { 2,     "end opt",                             ASN1_EOC,                       ASN1_END                        }, /* 11 */
        { 0, "end loop",                                ASN1_EOC,                       ASN1_END                        }, /* 12 */
        { 0, "exit",                                    ASN1_EOC,                       ASN1_EXIT                       }
 };
+#define CRL_DIST_POINTS                                 1
 #define CRL_DIST_POINTS_FULLNAME        3
+#define CRL_DIST_POINTS_ISSUER         10
 
 /**
  * Extracts one or several crlDistributionPoints into a list
@@ -665,6 +699,9 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0,
        asn1_parser_t *parser;
        chunk_t object;
        int objectID;
+       crl_uri_t *entry = NULL;
+       identification_t *id;
+       char *uri;
        linked_list_t *list = linked_list_create();
 
        parser = asn1_parser_create(crlDistributionPointsObjects, blob);
@@ -672,24 +709,45 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0,
 
        while (parser->iterate(parser, &objectID, &object))
        {
-               if (objectID == CRL_DIST_POINTS_FULLNAME)
+               switch (objectID)
                {
-                       identification_t *id;
-
-                       /* append extracted generalNames to existing chained list */
-                       x509_parse_generalNames(object, parser->get_level(parser)+1,
-                                                                       TRUE, list);
-
-                       while (list->remove_last(list, (void**)&id) == SUCCESS)
-                       {
-                               char *uri;
-
-                               if (asprintf(&uri, "%Y", id) > 0)
+                       case CRL_DIST_POINTS:
+                               entry = crl_uri_create(NULL);
+                               this->crl_uris->insert_last(this->crl_uris, entry);
+                               break;
+                       case CRL_DIST_POINTS_FULLNAME:
+                               if (entry)
                                {
-                                       this->crl_uris->insert_last(this->crl_uris, uri);
+                                       x509_parse_generalNames(object, parser->get_level(parser)+1,
+                                                                                       TRUE, list);
+                                       while (list->remove_last(list, (void**)&id) == SUCCESS)
+                                       {
+                                               if (asprintf(&uri, "%Y", id) > 0)
+                                               {
+                                                       entry->uris->insert_last(entry->uris, uri);
+                                               }
+                                               id->destroy(id);
+                                       }
                                }
-                               id->destroy(id);
-                       }
+                               break;
+                       case CRL_DIST_POINTS_ISSUER:
+                               if (entry)
+                               {
+                                       x509_parse_generalNames(object, parser->get_level(parser)+1,
+                                                                                       TRUE, list);
+                                       while (list->remove_last(list, (void**)&id) == SUCCESS)
+                                       {
+                                               if (!entry->issuer)
+                                               {
+                                                       entry->issuer = id;
+                                               }
+                                               else
+                                               {
+                                                       id->destroy(id);
+                                               }
+                                       }
+                               }
+                               break;
                }
        }
        parser->destroy(parser);
@@ -1356,11 +1414,37 @@ static enumerator_t* create_ocsp_uri_enumerator(private_x509_cert_t *this)
 }
 
 /**
+ * Convert enumerator value from entry to (uri, issuer)
+ */
+static bool crl_enum_filter(identification_t *issuer_in,
+                                                       char **uri_in, char **uri_out,
+                                                       void *none_in, identification_t **issuer_out)
+{
+       *uri_out = *uri_in;
+       if (issuer_out)
+       {
+               *issuer_out = issuer_in;
+       }
+       return TRUE;
+}
+
+/**
+ * Create inner enumerator over URIs
+ */
+static enumerator_t *crl_enum_create(crl_uri_t *entry)
+{
+       return enumerator_create_filter(entry->uris->create_enumerator(entry->uris),
+                                                               (void*)crl_enum_filter, entry->issuer, NULL);
+}
+
+/**
  * Implementation of x509_cert_t.create_crl_uri_enumerator.
  */
 static enumerator_t* create_crl_uri_enumerator(private_x509_cert_t *this)
 {
-       return this->crl_uris->create_enumerator(this->crl_uris);
+       return enumerator_create_nested(
+                                                       this->crl_uris->create_enumerator(this->crl_uris),
+                                                       (void*)crl_enum_create, NULL, NULL);
 }
 
 /**
@@ -1380,7 +1464,7 @@ static void destroy(private_x509_cert_t *this)
        {
                this->subjectAltNames->destroy_offset(this->subjectAltNames,
                                                                        offsetof(identification_t, destroy));
-               this->crl_uris->destroy_function(this->crl_uris, free);
+               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));
                DESTROY_IF(this->issuer);
@@ -1456,11 +1540,41 @@ static private_x509_cert_t* create_empty(void)
 }
 
 /**
+ * Build a generalName from an id
+ */
+chunk_t build_generalName(identification_t *id)
+{
+       int context;
+
+       switch (id->get_type(id))
+       {
+               case ID_RFC822_ADDR:
+                       context = ASN1_CONTEXT_S_1;
+                       break;
+               case ID_FQDN:
+                       context = ASN1_CONTEXT_S_2;
+                       break;
+               case ID_DER_ASN1_DN:
+                       context = ASN1_CONTEXT_C_4;
+                       break;
+               case ID_IPV4_ADDR:
+               case ID_IPV6_ADDR:
+                       context = ASN1_CONTEXT_S_7;
+                       break;
+               default:
+                       DBG1(DBG_LIB, "encoding %N as generalName not supported",
+                                id_type_names, id->get_type(id));
+                       return chunk_empty;
+       }
+       return asn1_wrap(context, "c", id->get_encoding(id));
+}
+
+/**
  * Encode a linked list of subjectAltNames
  */
 chunk_t x509_build_subjectAltNames(linked_list_t *list)
 {
-       chunk_t subjectAltNames = chunk_empty;
+       chunk_t subjectAltNames = chunk_empty, name;
        enumerator_t *enumerator;
        identification_t *id;
 
@@ -1472,29 +1586,7 @@ chunk_t x509_build_subjectAltNames(linked_list_t *list)
        enumerator = list->create_enumerator(list);
        while (enumerator->enumerate(enumerator, &id))
        {
-               int context;
-               chunk_t name;
-
-               switch (id->get_type(id))
-               {
-                       case ID_RFC822_ADDR:
-                               context = ASN1_CONTEXT_S_1;
-                               break;
-                       case ID_FQDN:
-                               context = ASN1_CONTEXT_S_2;
-                               break;
-                       case ID_IPV4_ADDR:
-                       case ID_IPV6_ADDR:
-                               context = ASN1_CONTEXT_S_7;
-                               break;
-                       default:
-                               DBG1(DBG_LIB, "encoding %N as subjectAltName not supported",
-                                        id_type_names, id->get_type(id));
-                               enumerator->destroy(enumerator);
-                               free(subjectAltNames.ptr);
-                               return chunk_empty;
-               }
-               name = asn1_wrap(context, "c", id->get_encoding(id));
+               name = build_generalName(id);
                subjectAltNames = chunk_cat("mm", subjectAltNames, name);
        }
        enumerator->destroy(enumerator);
@@ -1522,10 +1614,11 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
        chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty;
        chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty;
        identification_t *issuer, *subject;
+       crl_uri_t *entry;
        chunk_t key_info;
        signature_scheme_t scheme;
        hasher_t *hasher;
-       enumerator_t *enumerator;
+       enumerator_t *enumerator, *uris;
        char *uri;
 
        subject = cert->subject;
@@ -1576,16 +1669,28 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
 
        /* encode CRL distribution points extension */
        enumerator = cert->crl_uris->create_enumerator(cert->crl_uris);
-       while (enumerator->enumerate(enumerator, &uri))
+       while (enumerator->enumerate(enumerator, &entry))
        {
-               chunk_t distributionPoint;
+               chunk_t distributionPoint, gn;
+               chunk_t crlIssuer = chunk_empty, gns = chunk_empty;
 
-               distributionPoint = asn1_wrap(ASN1_SEQUENCE, "m",
-                                                               asn1_wrap(ASN1_CONTEXT_C_0, "m",
-                                                                       asn1_wrap(ASN1_CONTEXT_C_0, "m",
-                                                                               asn1_wrap(ASN1_CONTEXT_S_6, "c",
-                                                                                       chunk_create(uri, strlen(uri))))));
+               if (entry->issuer)
+               {
+                       crlIssuer = asn1_wrap(ASN1_CONTEXT_C_2, "m",
+                                                       build_generalName(entry->issuer));
+               }
+               uris = entry->uris->create_enumerator(entry->uris);
+               while (uris->enumerate(uris, &uri))
+               {
+                       gn = asn1_wrap(ASN1_CONTEXT_S_6, "c", chunk_create(uri, strlen(uri)));
+                       gns = chunk_cat("mm", gns, gn);
+               }
+               uris->destroy(uris);
 
+               distributionPoint = asn1_wrap(ASN1_SEQUENCE, "mm",
+                                                               asn1_wrap(ASN1_CONTEXT_C_0, "m",
+                                                                       asn1_wrap(ASN1_CONTEXT_C_0, "m", gns)),
+                                                               crlIssuer);
                crlDistributionPoints = chunk_cat("mm", crlDistributionPoints,
                                                                                  distributionPoint);
        }
@@ -1594,8 +1699,8 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
        {
                crlDistributionPoints = asn1_wrap(ASN1_SEQUENCE, "mm",
                                        asn1_build_known_oid(OID_CRL_DISTRIBUTION_POINTS),
-                                       asn1_wrap(ASN1_OCTET_STRING, "m",
-                                               asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints)));
+                                               asn1_wrap(ASN1_OCTET_STRING, "m",
+                                                       asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints)));
        }
 
        /* encode OCSP URIs in authorityInfoAccess extension */
@@ -1793,6 +1898,7 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
        private_x509_cert_t *cert;
        certificate_t *sign_cert = NULL;
        private_key_t *sign_key = NULL;
+       identification_t *crl_issuer = NULL;
        hash_algorithm_t digest_alg = HASH_SHA1;
 
        cert = create_empty();
@@ -1837,15 +1943,26 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
                        {
                                enumerator_t *enumerator;
                                linked_list_t *list;
+                               crl_uri_t *entry;
                                char *uri;
 
                                list = va_arg(args, linked_list_t*);
-                               enumerator = list->create_enumerator(list);
-                               while (enumerator->enumerate(enumerator, &uri))
+                               if (list->get_count(list))
                                {
-                                       cert->crl_uris->insert_last(cert->crl_uris, strdup(uri));
+                                       entry = crl_uri_create(crl_issuer);
+                                       enumerator = list->create_enumerator(list);
+                                       while (enumerator->enumerate(enumerator, &uri))
+                                       {
+                                               entry->uris->insert_last(entry->uris, strdup(uri));
+                                       }
+                                       enumerator->destroy(enumerator);
+                                       cert->crl_uris->insert_last(cert->crl_uris, entry);
                                }
-                               enumerator->destroy(enumerator);
+                               continue;
+                       }
+                       case BUILD_CRL_ISSUER:
+                       {
+                               crl_issuer = va_arg(args, identification_t*);
                                continue;
                        }
                        case BUILD_OCSP_ACCESS_LOCATIONS:
index 870dca9..4dcc471 100644 (file)
@@ -133,17 +133,22 @@ static void print_x509(x509_t *x509)
 
        first = TRUE;
        enumerator = x509->create_crl_uri_enumerator(x509);
-       while (enumerator->enumerate(enumerator, &uri))
+       while (enumerator->enumerate(enumerator, &uri, &id))
        {
                if (first)
                {
-                       printf("CRL URIs:  %s\n", uri);
+                       printf("CRL URIs:  %s", uri);
                        first = FALSE;
                }
                else
                {
-                       printf("           %s\n", uri);
+                       printf("           %s", uri);
                }
+               if (id)
+               {
+                       printf(" (CRL issuer: %Y)", id);
+               }
+               printf("\n");
        }
        enumerator->destroy(enumerator);
 
index c8fb107..7b14e5f 100644 (file)
@@ -376,7 +376,7 @@ cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate,
                }
 
                enumerator = x509->create_crl_uri_enumerator(x509);
-               while (enumerator->enumerate(enumerator, &point))
+               while (enumerator->enumerate(enumerator, &point, NULL))
                {
                        add_distribution_point(crluris, point);
                }
@@ -416,7 +416,7 @@ cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate,
                }
 
                enumerator = x509->create_crl_uri_enumerator(x509);
-               while (enumerator->enumerate(enumerator, &point))
+               while (enumerator->enumerate(enumerator, &point, NULL))
                {
                        add_distribution_point(x509crl->distributionPoints, point);
                }