diff options
-rw-r--r-- | src/libstrongswan/credentials/builder.c | 1 | ||||
-rw-r--r-- | src/libstrongswan/credentials/builder.h | 2 | ||||
-rw-r--r-- | src/libstrongswan/credentials/certificates/x509.h | 4 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_x509.c | 83 | ||||
-rw-r--r-- | src/libstrongswan/plugins/revocation/revocation_validator.c | 3 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_cert.c | 231 | ||||
-rw-r--r-- | src/pki/commands/print.c | 11 | ||||
-rw-r--r-- | src/pluto/crl.c | 4 |
8 files changed, 269 insertions, 70 deletions
diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index c43e5fd5d..2323f6ce5 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -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", diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index dc87da2a4..390c314a6 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -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 */ diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h index 6e0a5002a..3f1c4b738 100644 --- a/src/libstrongswan/credentials/certificates/x509.h +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -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); diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c index aa39bc93d..1630d8faf 100644 --- a/src/libstrongswan/plugins/openssl/openssl_x509.c +++ b/src/libstrongswan/plugins/openssl/openssl_x509.c @@ -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); } } diff --git a/src/libstrongswan/plugins/revocation/revocation_validator.c b/src/libstrongswan/plugins/revocation/revocation_validator.c index 29d2bc128..511a04a3e 100644 --- a/src/libstrongswan/plugins/revocation/revocation_validator.c +++ b/src/libstrongswan/plugins/revocation/revocation_validator.c @@ -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) diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 559090aa0..6fcd9f033 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -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: diff --git a/src/pki/commands/print.c b/src/pki/commands/print.c index 870dca920..4dcc4718e 100644 --- a/src/pki/commands/print.c +++ b/src/pki/commands/print.c @@ -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); diff --git a/src/pluto/crl.c b/src/pluto/crl.c index c8fb107d5..7b14e5ff1 100644 --- a/src/pluto/crl.c +++ b/src/pluto/crl.c @@ -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); } |