From dab7c893a600cdb8526f852ee1d13108b4fc037d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 30 Oct 2023 17:34:51 +0100 Subject: [PATCH 01/10] library: Add manager for OCSP responders Registered OCSP responders should return VALIDATION_SKIPPED for issuer certificates they are not responsible for. However, VALIDATION_FAILED is currently treated the same way, so that's fine as well. --- src/libstrongswan/Android.mk | 2 +- src/libstrongswan/Makefile.am | 11 +- .../credentials/certificates/ocsp_responder.h | 6 +- .../credentials/ocsp_responders.c | 119 ++++++++++++++++++ .../credentials/ocsp_responders.h | 76 +++++++++++ src/libstrongswan/library.c | 2 + src/libstrongswan/library.h | 6 + 7 files changed, 214 insertions(+), 8 deletions(-) create mode 100644 src/libstrongswan/credentials/ocsp_responders.c create mode 100644 src/libstrongswan/credentials/ocsp_responders.h diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 3ce05d9319..1f2d0af521 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -28,7 +28,7 @@ credentials/certificates/ocsp_response.c credentials/certificates/x509.c \ credentials/certificates/ocsp_single_response.c \ credentials/certificates/certificate_printer.c \ credentials/containers/container.c credentials/containers/pkcs12.c \ -credentials/credential_manager.c \ +credentials/credential_manager.c credentials/ocsp_responders.c \ credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \ credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index cc00d43f75..0597afad96 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -26,7 +26,7 @@ credentials/certificates/ocsp_response.c credentials/certificates/x509.c \ credentials/certificates/ocsp_single_response.c \ credentials/certificates/certificate_printer.c \ credentials/containers/container.c credentials/containers/pkcs12.c \ -credentials/credential_manager.c \ +credentials/credential_manager.c credentials/ocsp_responders.c \ credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \ credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \ @@ -99,10 +99,11 @@ credentials/certificates/pgp_certificate.h \ credentials/certificates/certificate_printer.h \ credentials/containers/container.h credentials/containers/pkcs7.h \ credentials/containers/pkcs12.h \ -credentials/credential_manager.h credentials/sets/auth_cfg_wrapper.h \ -credentials/sets/ocsp_response_wrapper.h credentials/sets/cert_cache.h \ -credentials/sets/mem_cred.h credentials/sets/callback_cred.h \ -credentials/auth_cfg.h credentials/credential_set.h credentials/cert_validator.h \ +credentials/credential_manager.h credentials/ocsp_responders.h \ +credentials/sets/auth_cfg_wrapper.h credentials/sets/ocsp_response_wrapper.h \ +credentials/sets/cert_cache.h credentials/sets/mem_cred.h \ +credentials/sets/callback_cred.h credentials/auth_cfg.h \ +credentials/credential_set.h credentials/cert_validator.h \ database/database.h database/database_factory.h fetcher/fetcher.h \ fetcher/fetcher_manager.h eap/eap.h pen/pen.h ipsec/ipsec_types.h \ metadata/metadata.h metadata/metadata_factory.h metadata/metadata_int.h \ diff --git a/src/libstrongswan/credentials/certificates/ocsp_responder.h b/src/libstrongswan/credentials/certificates/ocsp_responder.h index e7644dda9e..57896ace1b 100644 --- a/src/libstrongswan/credentials/certificates/ocsp_responder.h +++ b/src/libstrongswan/credentials/certificates/ocsp_responder.h @@ -22,10 +22,10 @@ #ifndef OCSP_RESPONDER_H_ #define OCSP_RESPONDER_H_ -#include - typedef struct ocsp_responder_t ocsp_responder_t; +#include + /** * OCSP responder object. */ @@ -34,6 +34,8 @@ struct ocsp_responder_t { /** * Check the status of a certificate given by its serial number * + * @note Return VALIDATION_SKIPPED if not responsible for the given CA + * * @param cacert X.509 certificate of issuer CA * @param serial_number serial number of the certificate to be checked * @param revocation_time receives time of revocation, if revoked diff --git a/src/libstrongswan/credentials/ocsp_responders.c b/src/libstrongswan/credentials/ocsp_responders.c new file mode 100644 index 0000000000..8eca73c926 --- /dev/null +++ b/src/libstrongswan/credentials/ocsp_responders.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2023 Tobias Brunner + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ocsp_responders.h" + +#include +#include + +typedef struct private_ocsp_responders_t private_ocsp_responders_t; + +/** + * Private data + */ +struct private_ocsp_responders_t { + + /** + * Public interface + */ + ocsp_responders_t public; + + /** + * List of registered OCSP responders + */ + linked_list_t *responders; + + /** + * Lock to access responder list + */ + rwlock_t *lock; +}; + +METHOD(ocsp_responders_t, get_status, cert_validation_t, + private_ocsp_responders_t *this, certificate_t *cacert, + chunk_t serial_number, time_t *revocation_time, + crl_reason_t *revocation_reason) +{ + enumerator_t *enumerator; + ocsp_responder_t *current; + cert_validation_t validation = VALIDATION_SKIPPED; + + this->lock->read_lock(this->lock); + enumerator = this->responders->create_enumerator(this->responders); + while (enumerator->enumerate(enumerator, ¤t)) + { + validation = current->get_status(current, cacert, serial_number, + revocation_time, revocation_reason); + if (validation != VALIDATION_SKIPPED && + validation != VALIDATION_FAILED) + { + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + if (validation == VALIDATION_SKIPPED) + { + validation = VALIDATION_FAILED; + } + return validation; +} + +METHOD(ocsp_responders_t, add_responder, void, + private_ocsp_responders_t *this, ocsp_responder_t *responder) +{ + this->lock->write_lock(this->lock); + this->responders->insert_last(this->responders, responder); + this->lock->unlock(this->lock); +} + +METHOD(ocsp_responders_t, remove_responder, void, + private_ocsp_responders_t *this, ocsp_responder_t *responder) +{ + this->lock->write_lock(this->lock); + this->responders->remove(this->responders, responder, NULL); + this->lock->unlock(this->lock); +} + +METHOD(ocsp_responders_t, destroy, void, + private_ocsp_responders_t *this) +{ + this->responders->destroy(this->responders); + this->lock->destroy(this->lock); + free(this); +} + +/* + * Described in header + */ +ocsp_responders_t *ocsp_responders_create() +{ + private_ocsp_responders_t *this; + + INIT(this, + .public = { + .get_status = _get_status, + .add_responder = _add_responder, + .remove_responder = _remove_responder, + .destroy = _destroy, + }, + .responders = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libstrongswan/credentials/ocsp_responders.h b/src/libstrongswan/credentials/ocsp_responders.h new file mode 100644 index 0000000000..d4ce331a67 --- /dev/null +++ b/src/libstrongswan/credentials/ocsp_responders.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 Tobias Brunner + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ocsp_responders ocsp_responders + * @{ @ingroup credentials + */ + +#ifndef OCSP_RESPONDERS_H_ +#define OCSP_RESPONDERS_H_ + +typedef struct ocsp_responders_t ocsp_responders_t; + +#include + +/** + * Manages OCSP responders. + */ +struct ocsp_responders_t { + + /** + * Check the status of a certificate given by its serial number + * + * @param cacert X.509 certificate of issuer CA + * @param serial_number serial number of the certificate to be checked + * @param revocation_time receives time of revocation, if revoked + * @param reason receives reason of revocation, if revoked + * @return certificate validation status + */ + cert_validation_t (*get_status)(ocsp_responders_t *this, + certificate_t *cacert, + chunk_t serial_number, + time_t *revocation_time, + crl_reason_t *revocation_reason); + + /** + * Register an OCSP responder with this manager. + * + * @param responder OCSP responder to register + */ + void (*add_responder)(ocsp_responders_t *this, + ocsp_responder_t *responder); + + /** + * Unregister an OCSP responder from this manager. + * + * @param responder OCSP responder to unregister + */ + void (*remove_responder)(ocsp_responders_t *this, + ocsp_responder_t *responder); + + /** + * Destroy a ocsp_responders_t instance. + */ + void (*destroy)(ocsp_responders_t *this); +}; + +/** + * Create a ocsp_responders_t instance. + */ +ocsp_responders_t *ocsp_responders_create(); + +#endif /** OCSP_RESPONDERS_H_ @}*/ diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index f2ece6ca98..c65b381547 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -171,6 +171,7 @@ void library_deinit() this->public.credmgr->destroy(this->public.credmgr); this->public.creds->destroy(this->public.creds); this->public.encoding->destroy(this->public.encoding); + this->public.ocsp->destroy(this->public.ocsp); this->public.metadata->destroy(this->public.metadata); this->public.crypto->destroy(this->public.crypto); this->public.caps->destroy(this->public.caps); @@ -401,6 +402,7 @@ bool library_init(char *settings, const char *namespace) this->public.creds = credential_factory_create(); this->public.credmgr = credential_manager_create(); this->public.encoding = cred_encoding_create(); + this->public.ocsp = ocsp_responders_create(); this->public.metadata = metadata_factory_create(); this->public.fetcher = fetcher_manager_create(); this->public.resolver = resolver_manager_create(); diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index 9b8a26c1c2..20c30bdac8 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -113,6 +113,7 @@ #include "credentials/credential_factory.h" #include "credentials/credential_manager.h" #include "credentials/cred_encoding.h" +#include "credentials/ocsp_responders.h" #include "metadata/metadata_factory.h" #include "utils/chunk.h" #include "utils/capabilities.h" @@ -191,6 +192,11 @@ struct library_t { */ cred_encoding_t *encoding; + /** + * Manager for OCSP responders + */ + ocsp_responders_t *ocsp; + /** * Registry and factory for metadata creation */ From 515cecfe3e3b943072c4846e2ccd6aad6a1d8c2e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 30 Oct 2023 17:47:34 +0100 Subject: [PATCH 02/10] pki: Use OCSP responder manager for --ocsp --respond --- src/pki/commands/ocsp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pki/commands/ocsp.c b/src/pki/commands/ocsp.c index 44fdb89d86..0dc55525fe 100644 --- a/src/pki/commands/ocsp.c +++ b/src/pki/commands/ocsp.c @@ -410,11 +410,9 @@ static int ocsp() if (op == OP_RESPOND) { ocsp_responder = lib->get(lib, "ocsp-responder"); - if (!ocsp_responder) + if (ocsp_responder) { - DBG1(DBG_APP, " no ocsp-responder found"); - ocsp_status = OCSP_INTERNALERROR; - goto gen; + lib->ocsp->add_responder(lib->ocsp, ocsp_responder); } } @@ -474,9 +472,9 @@ static int ocsp() if (issuer_cacert && (issuer_cacert == first_issuer || self_signed)) { - status = ocsp_responder->get_status(ocsp_responder, - issuer_cacert, serialNumber, - &revocationTime, &revocationReason); + status = lib->ocsp->get_status(lib->ocsp, + issuer_cacert, serialNumber, + &revocationTime, &revocationReason); } DBG1(DBG_APP, " certValidation: %N", cert_validation_names, status); response->status = status; @@ -556,6 +554,10 @@ gen: res = 0; end: + if (ocsp_responder) + { + lib->ocsp->remove_responder(lib->ocsp, ocsp_responder); + } DESTROY_IF(key); lib->credmgr->remove_local_set(lib->credmgr, &creds->set); creds->destroy(creds); From efac61156680c603172c8a68807ba698f6921977 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 30 Oct 2023 17:49:34 +0100 Subject: [PATCH 03/10] openxpki: Register as OCSP responder --- src/libstrongswan/plugins/openxpki/openxpki_plugin.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libstrongswan/plugins/openxpki/openxpki_plugin.c b/src/libstrongswan/plugins/openxpki/openxpki_plugin.c index 7d7138bc54..afb8a61d7e 100644 --- a/src/libstrongswan/plugins/openxpki/openxpki_plugin.c +++ b/src/libstrongswan/plugins/openxpki/openxpki_plugin.c @@ -47,18 +47,17 @@ static bool plugin_cb(private_openxpki_plugin_t *this, { if (reg) { - /* Is there already a registered OCSP responder? */ - if (!lib->get(lib, "ocsp-responder")) + this->ocsp_responder = openxpki_ocsp_responder_create(); + if (this->ocsp_responder) { - this->ocsp_responder = openxpki_ocsp_responder_create(); - lib->set(lib, "ocsp-responder", this->ocsp_responder); + lib->ocsp->add_responder(lib->ocsp, this->ocsp_responder); } } else { if (this->ocsp_responder) { - lib->set(lib, "ocsp-responder", NULL); + lib->ocsp->remove_responder(lib->ocsp, this->ocsp_responder); this->ocsp_responder->destroy(this->ocsp_responder); } } From 3e42b2f5cb47837a8e0b22baefd6a231816b8491 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 30 Oct 2023 17:50:18 +0100 Subject: [PATCH 04/10] pki: Drop legacy registration for OCSP responders --- src/pki/commands/ocsp.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/pki/commands/ocsp.c b/src/pki/commands/ocsp.c index 0dc55525fe..0dd5b4a780 100644 --- a/src/pki/commands/ocsp.c +++ b/src/pki/commands/ocsp.c @@ -23,7 +23,6 @@ #include #include #include -#include /* * Verifies the optional OCSP request signature generated by an OCSP requestor @@ -229,7 +228,6 @@ static int ocsp() certificate_t *cacert = NULL, *first_issuer = NULL; ocsp_request_t *ocsp_request; ocsp_status_t ocsp_status = OCSP_SUCCESSFUL; - ocsp_responder_t *ocsp_responder = NULL; linked_list_t *responses = NULL; chunk_t encoding = chunk_empty, nonce = chunk_empty; chunk_t issuerNameHash, issuerKeyHash, serialNumber; @@ -406,16 +404,6 @@ static int ocsp() DBG1(DBG_APP, "nonce: %#B", &nonce); } - /* check for an ocsp responder */ - if (op == OP_RESPOND) - { - ocsp_responder = lib->get(lib, "ocsp-responder"); - if (ocsp_responder) - { - lib->ocsp->add_responder(lib->ocsp, ocsp_responder); - } - } - /* enumerate over the ocsp requests and try to identify the issuers */ enumerator = ocsp_request->create_request_enumerator(ocsp_request); while (enumerator->enumerate(enumerator, &hashAlgorithm, &issuerNameHash, @@ -554,10 +542,6 @@ gen: res = 0; end: - if (ocsp_responder) - { - lib->ocsp->remove_responder(lib->ocsp, ocsp_responder); - } DESTROY_IF(key); lib->credmgr->remove_local_set(lib->credmgr, &creds->set); creds->destroy(creds); From 1e8a72e7a0abaaa02a03d0f1d04c4bdc3bc1b00d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 30 Oct 2023 17:57:23 +0100 Subject: [PATCH 05/10] chunk: Add helper to hash chunks via pointer --- src/libstrongswan/utils/chunk.c | 8 ++++++++ src/libstrongswan/utils/chunk.h | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index f40a379c5f..c8153f4f0c 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -1088,6 +1088,14 @@ uint32_t chunk_hash(chunk_t chunk) return chunk_mac(chunk, hash_key); } +/* + * Described in header. + */ +uint32_t chunk_hash_ptr(chunk_t *chunk) +{ + return chunk_hash(*chunk); +} + /** * Described in header. */ diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index 0ee38d27de..b9fc56b1be 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -414,6 +414,15 @@ void chunk_hash_seed(); */ uint32_t chunk_hash(chunk_t chunk); +/** + * Same as chunk_hash() but takes a pointer to a chunk. Can be used in + * hashtables. + * + * @param chunk pointer to chunk to hash + * @return hash value + */ +uint32_t chunk_hash_ptr(chunk_t *chunk); + /** * Incremental version of chunk_hash. Use this to hash two or more chunks. * From f26ca67d8c16f4ab20767bb29b6a02444644fe1f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 30 Oct 2023 18:11:53 +0100 Subject: [PATCH 06/10] pki: Add index.txt-based OCSP responder --- src/pki/Makefile.am | 1 + src/pki/ocsp/index_responder.c | 261 +++++++++++++++++++++++++++++++++ src/pki/ocsp/index_responder.h | 38 +++++ 3 files changed, 300 insertions(+) create mode 100644 src/pki/ocsp/index_responder.c create mode 100644 src/pki/ocsp/index_responder.h diff --git a/src/pki/Makefile.am b/src/pki/Makefile.am index 1dbcd9a444..8ba99746ca 100644 --- a/src/pki/Makefile.am +++ b/src/pki/Makefile.am @@ -22,6 +22,7 @@ pki_SOURCES = pki.c pki.h pki_cert.c pki_cert.h command.c command.h \ commands/signcrl.c \ commands/verify.c \ est/est_tls.h est/est_tls.c \ + ocsp/index_responder.h ocsp/index_responder.c \ scep/scep.h scep/scep.c pki_LDADD = \ diff --git a/src/pki/ocsp/index_responder.c b/src/pki/ocsp/index_responder.c new file mode 100644 index 0000000000..c00512d7b8 --- /dev/null +++ b/src/pki/ocsp/index_responder.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2023 Tobias Brunner + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include "index_responder.h" + +#include +#include + +typedef struct private_ocsp_responder_t private_ocsp_responder_t; + +/** + * Private data + */ +struct private_ocsp_responder_t { + + /** + * Public interface + */ + ocsp_responder_t public; + + /** + * CA certificate + */ + certificate_t *ca; + + /** + * Certificate database + */ + hashtable_t *certs; +}; + +/** + * Status information on a certificate + */ +typedef struct { + /** Serial number */ + chunk_t serial; + /** Certificate's validity */ + cert_validation_t validation; + /** Revocation reason */ + crl_reason_t reason; + /** Revocation time */ + time_t revocation_time; +} cert_entry_t; + +/** + * Destroy a certificate status entry + */ +static void destroy_cert_entry(cert_entry_t *this) +{ + chunk_free(&this->serial); + free(this); +} + +METHOD(ocsp_responder_t, get_status, cert_validation_t, + private_ocsp_responder_t *this, certificate_t *cacert, + chunk_t serial_number, time_t *revocation_time, crl_reason_t *reason) +{ + cert_entry_t *cert; + + if (!cacert->equals(cacert, this->ca)) + { + return VALIDATION_SKIPPED; + } + cert = this->certs->get(this->certs, &serial_number); + if (!cert) + { + return VALIDATION_FAILED; + } + if (revocation_time) + { + *revocation_time = cert->revocation_time; + } + if (reason) + { + *reason = cert->reason; + } + return cert->validation; +} + +METHOD(ocsp_responder_t, destroy, void, + private_ocsp_responder_t *this) +{ + lib->ocsp->remove_responder(lib->ocsp, &this->public); + this->certs->destroy_function(this->certs, (void*)destroy_cert_entry); + this->ca->destroy(this->ca); + free(this); +} + +/* + * Described in header + */ +ocsp_responder_t *index_responder_create(certificate_t *ca, char *path) +{ + private_ocsp_responder_t *this; + hashtable_t *certs; + char line[BUF_LEN], *token, *pos, *reason_str; + FILE *file; + + file = fopen(path, "r"); + if (!file) + { + fprintf(stderr, "failed to open '%s': %s\n", path, strerror(errno)); + return NULL; + } + certs = hashtable_create((hashtable_hash_t)chunk_hash_ptr, + (hashtable_equals_t)chunk_equals_ptr, 32); + while (fgets(line, sizeof(line), file)) + { + enumerator_t *enumerator; + cert_entry_t *cert; + cert_validation_t validation; + crl_reason_t reason = CRL_REASON_UNSPECIFIED; + time_t revocation_time = 0; + chunk_t revocation, serial; + bool valid = FALSE; + int i = 0; + + switch (line[0]) + { + case 'E': + /* OpenSSL only converts valid entries to expired ones */ + case 'V': + validation = VALIDATION_GOOD; + break; + case 'R': + validation = VALIDATION_REVOKED; + break; + default: + /* ignore comments, empty lines etc. */ + continue; + } + enumerator = enumerator_create_token(&line[1], "\t", " \n\r"); + while (enumerator->enumerate(enumerator, &token)) + { + switch (i++) + { + case 0: /* expiration date/time in UTC (YYMMDDHHMMSSZ), ignored */ + continue; + case 1: /* if revoked, revocation date/time and optional reason */ + if (validation == VALIDATION_REVOKED) + { + reason_str = NULL; + pos = strchr(token, ','); + if (pos) + { + *pos = '\0'; + reason_str = ++pos; + /* OpenSSL may optionally store an OID if the reason + * is certificateHold (hold instruction code in + * RFC 3280, was removed with RFC 5280) */ + pos = strchr(pos, ','); + if (pos) + { + *pos = '\0'; + } + } + revocation = chunk_from_str(token); + revocation_time = asn1_to_time(&revocation, + ASN1_UTCTIME); + if (!revocation_time) + { + break; + } + if (strcaseeq(reason_str, "keyCompromise")) + { + reason = CRL_REASON_KEY_COMPROMISE; + } + else if (strcaseeq(reason_str, "CACompromise")) + { + reason = CRL_REASON_CA_COMPROMISE; + } + else if (strcaseeq(reason_str, "affiliationChanged")) + { + reason = CRL_REASON_AFFILIATION_CHANGED; + } + else if (strcaseeq(reason_str, "superseded")) + { + reason = CRL_REASON_SUPERSEDED; + } + else if (strcaseeq(reason_str, "cessationOfOperation")) + { + reason = CRL_REASON_CESSATION_OF_OPERATION; + } + else if (strcaseeq(reason_str, "certificateHold")) + { + reason = CRL_REASON_CERTIFICATE_HOLD; + validation = VALIDATION_ON_HOLD; + } + else if (strcaseeq(reason_str, "removeFromCRL")) + { + reason = CRL_REASON_REMOVE_FROM_CRL; + } + else + { + reason = CRL_REASON_UNSPECIFIED; + } + continue; + } + i++; + /* if not revoked, this field is empty, fall-through */ + case 2: /* hexadecimal serial number */ + serial = chunk_from_hex(chunk_from_str(token), NULL); + valid = serial.len > 0; + /* skip the last two fields, an optional path, usually set + * to "unknown", and the subject DN (RDNs separated by + * slashes), which we don't use */ + break; + default: + break; + } + break; + } + enumerator->destroy(enumerator); + + if (valid) + { + INIT(cert, + .serial = serial, + .validation = validation, + .reason = reason, + .revocation_time = revocation_time, + ); + cert = certs->put(certs, &cert->serial, cert); + if (cert) + { + destroy_cert_entry(cert); + } + } + } + fclose(file); + + INIT(this, + .public = { + .get_status = _get_status, + .destroy = _destroy, + }, + .ca = ca->get_ref(ca), + .certs = certs, + ); + lib->ocsp->add_responder(lib->ocsp, &this->public); + + DBG1(DBG_APP, "loaded status of %u certificates issued by '%Y' from %s", + certs->get_count(certs), ca->get_subject(ca), path); + return &this->public; +} diff --git a/src/pki/ocsp/index_responder.h b/src/pki/ocsp/index_responder.h new file mode 100644 index 0000000000..c126b36149 --- /dev/null +++ b/src/pki/ocsp/index_responder.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 Tobias Brunner + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ocsp ocsp + * @{ @ingroup pki + */ + +#ifndef INDEX_RESPONDER_H_ +#define INDEX_RESPONDER_H_ + +#include + +/** + * Create an index.txt-based OCSP responder for the given CA and file. + * + * On success, the responder is automatically registered until destroyed. + * + * @param ca CA certificate (referenced) + * @param path path to index.txt + * @return OCSP responder, NULL if file is invalid + */ +ocsp_responder_t *index_responder_create(certificate_t *ca, char *path); + +#endif /** INDEX_RESPONDER_H_ @} */ From 95c7d499544aee263f6c1f27b41f2cccbcb594f1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 30 Oct 2023 18:12:12 +0100 Subject: [PATCH 07/10] pki: Add option to load certificate status information from index.txt Each index.txt is associated with the most recently loaded CA certificate. --- src/pki/commands/ocsp.c | 36 ++++++++++++++++++++++---- src/pki/man/pki---ocsp.1.in | 51 ++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/pki/commands/ocsp.c b/src/pki/commands/ocsp.c index 0dd5b4a780..81e732cf49 100644 --- a/src/pki/commands/ocsp.c +++ b/src/pki/commands/ocsp.c @@ -18,7 +18,9 @@ #include #include "pki.h" +#include "ocsp/index_responder.h" +#include #include #include #include @@ -155,7 +157,7 @@ static bool find_issuer_cacert(hash_algorithm_t hashAlgorithm, /* * Find an OCSP signer certificate. Either the certificate of the CA itself that - * issued the end entitity certificate, the certificate of an OCSP signer + * issued the end-entity certificate, the certificate of an OCSP signer * delegated by the CA via the standard OCSPSigning Extended Key Usage (EKU) * flag or a self-signed OCSP signer certificate when multiple issuer OCSP * requests have to be supported. @@ -180,7 +182,7 @@ static void find_ocsp_signer(certificate_t *first_issuer, bool *self_signed, KEY_ANY, NULL, TRUE); while (certs->enumerate(certs, &candidate)) { - /* get the flags and key identfiers of the candidate certificate */ + /* get the flags and key identifiers of the candidate certificate */ x509 = (x509_t*)candidate; flags = x509->get_flags(x509); subKeyId = x509->get_subjectKeyIdentifier(x509); @@ -228,7 +230,9 @@ static int ocsp() certificate_t *cacert = NULL, *first_issuer = NULL; ocsp_request_t *ocsp_request; ocsp_status_t ocsp_status = OCSP_SUCCESSFUL; + ocsp_responder_t *index_responder = NULL; linked_list_t *responses = NULL; + array_t *index_responders = NULL; chunk_t encoding = chunk_empty, nonce = chunk_empty; chunk_t issuerNameHash, issuerKeyHash, serialNumber; hash_algorithm_t hashAlgorithm = HASH_SHA1, digest = HASH_UNKNOWN; @@ -284,6 +288,7 @@ static int ocsp() creds->add_cert(creds, TRUE, cert); continue; case 'C': + DESTROY_IF(cacert); cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, arg, BUILD_END); @@ -292,7 +297,7 @@ static int ocsp() error = "parsing CA certificate failed"; goto usage; } - creds->add_cert(creds, TRUE, cacert); + cacert = creds->add_cert_ref(creds, TRUE, cacert); continue; case 'l': lifetime = atoi(arg) * 60; @@ -316,6 +321,21 @@ static int ocsp() goto usage; } continue; + case 'x': + if (!cacert) + { + error = "--index must follow --cacert of corresponding CA"; + goto usage; + } + index_responder = index_responder_create(cacert, arg); + if (!index_responder) + { + error = "invalid ---index value"; + goto usage; + } + array_insert_create(&index_responders, ARRAY_TAIL, + index_responder); + continue; case EOF: break; default: @@ -331,7 +351,7 @@ static int ocsp() if (op == OP_RESPOND && !cacert) { - error = "respond mode requires a ca certificate"; + error = "respond mode requires a CA certificate"; goto end; } @@ -542,6 +562,8 @@ gen: res = 0; end: + array_destroy_offset(index_responders, offsetof(ocsp_responder_t, destroy)); + DESTROY_IF(cacert); DESTROY_IF(key); lib->credmgr->remove_local_set(lib->credmgr, &creds->set); creds->destroy(creds); @@ -558,6 +580,8 @@ end: return res; usage: + array_destroy_offset(index_responders, offsetof(ocsp_responder_t, destroy)); + DESTROY_IF(cacert); creds->destroy(creds); return command_usage(error); } @@ -569,7 +593,8 @@ static void __attribute__ ((constructor))reg() { command_register((command_t) { ocsp, 'o', "ocsp", "OCSP responder", - {"[--in file] [--respond] [--cert file]+ [--key file]+ [--cacert file]+ ", + {"[--in file] [--respond] [--cert file]+ [--key file]+ ", + "[--cacert file [--index file]]+", "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]", "[--rsa-padding pkcs1|pss] [--lifetime minutes]"}, { @@ -579,6 +604,7 @@ static void __attribute__ ((constructor))reg() {"key", 'k', 1, "path to OCSP signing private key (can be used multiple times)"}, {"cert", 'c', 1, "path to OCSP signing certificate (can be used multiple times"}, {"cacert", 'C', 1, "CA certificate (can be used multiple times"}, + {"index", 'x', 1, "OpenSSL-style index.txt to check status of certificates"}, {"digest", 'g', 1, "digest for signature creation, default: key-specific"}, {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"}, {"lifetime", 'l', 1, "validity in minutes of the OCSP response (if missing, nextUpdate is omitted)"}, diff --git a/src/pki/man/pki---ocsp.1.in b/src/pki/man/pki---ocsp.1.in index 23d4c7de4f..54ae002249 100644 --- a/src/pki/man/pki---ocsp.1.in +++ b/src/pki/man/pki---ocsp.1.in @@ -18,6 +18,7 @@ pki \-\-ocsp \- OCSP request parser and OCSP responder. .BI \-\-cacert\~ file .BI \-\-key\~ file .OP \-\-cert file +.OP \-\-index file .OP \-\-lifetime minutes .OP \-\-digest digest .OP \-\-rsa\-padding padding @@ -87,6 +88,14 @@ OCSP signer key. Can be used multiple times. OCSP signer certificate (if it is not a CA certificate). Can be used multiple times. .TP +.BI "\-x, \-\-index " file +OpenSSL-style index.txt providing information about the status of certificates +issued by the CA certificate loaded immediately before. Can be used multiple +times if the status for multiple CAs should be provided, just make sure to +pass each index.txt file right after the corresponding CA certificate. + +See below for a description of the structure of these files. +.TP .BI "\-l, \-\-lifetime " minutes Validity in minutes of the OCSP response (if missing, nextUpdate is omitted). .TP @@ -94,12 +103,52 @@ Validity in minutes of the OCSP response (if missing, nextUpdate is omitted). Digest to use for signature creation. One of \fImd5\fR, \fIsha1\fR, \fIsha224\fR, \fIsha256\fR, \fIsha384\fR, or \fIsha512\fR, \fIsha3_224\fR, \fIsha3_256\fR, \fIsha3_384\fR, \fIsha3_512\fR. The default is -determined based on the type and size of the ocsp signing key. +determined based on the type and size of the OCSP signing key. .TP .BI "\-R, \-\-rsa\-padding " padding Padding to use for RSA signatures. Either \fIpkcs1\fR or \fIpss\fR, defaults to \fIpkcs1\fR. . +.SH "INDEX.TXT DESCRIPTION" +. +Each line in an index.txt file consists of six columns that are separated by +tab characters: + +The first column denotes the certificate status, which can be either "V" (for +valid), "E" (for expired, treated like valid), or "R" (for revoked). + +The second column contains the certificate's expiration date and time in UTC in +the format YYMMDDHHMMSSZ. This field is ignored by the command but must not be +empty. + +The third column is the revocation date and time in UTC in the format +YYMMDDHHMMSSZ and an optional revocation reason that immediately follows it, +separated by a comma. Valid reasons are "keyCompromise", "CACompromise", +"affiliationChanged", "superseded", "cessationOfOperation", "certificateHold", +and "removeFromCRL", any other value or omitting a reason results in +"unspecified". + +The fourth column contains the certificate's serial number in +hexadecimal encoding. + +The fifth and sixth columns are both ignored by the command, so they may be +omitted completely. They can contain a path to the certificate (usually set to +"unknown") and the certificate's subject DN with slashes separating the RDNs. + +Example index.txt: +.PP +.EX +V 310930122422Z 03 unknown /C=CH/O=strongSwan/CN=moon... +V 310930122422Z 04 unknown /C=CH/O=strongSwan/CN=sun... +R 310930122422Z 231002122422Z,keyCompromise 88 +V Z 05 +.EE +.PP +Note that the fields are separated by tabs. So if a certificate is valid, two +tabs follow after the expiration date. The third line in this example only +specifies the relevant first four columns, the fourth even uses a dummy +expiration date. +. .SH "EXAMPLES" . Show the raw content of an OCSP request: From 5764e1e5069ad9fa80d30a33d5733b3c25456f56 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 31 Oct 2023 09:17:05 +0100 Subject: [PATCH 08/10] pki: Pre-process common arguments This way the position of --debug doesn't matter for it to apply to the parsing of all command-specific arguments. --- src/pki/command.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/pki/command.c b/src/pki/command.c index 5dd53e9dec..accec5fe51 100644 --- a/src/pki/command.c +++ b/src/pki/command.c @@ -116,20 +116,41 @@ int command_getopt(char **arg) { op = getopt_long(argc, argv, command_optstring, command_opts, NULL); switch (op) + { + case '+': + case 'v': + continue; + default: + *arg = optarg; + return op; + } + } +} + +/** + * Process options common for all commands + */ +static bool process_common_opts() +{ + while (TRUE) + { + switch (getopt_long(argc, argv, command_optstring, command_opts, NULL)) { case '+': if (!options->from(options, optarg, &argc, &argv, optind)) { - /* a error value */ - return 255; + return FALSE; } continue; case 'v': dbg_default_set_level(atoi(optarg)); continue; default: - *arg = optarg; - return op; + continue; + case '?': + return FALSE; + case EOF: + return TRUE; } } } @@ -279,6 +300,11 @@ int command_dispatch(int c, char *v[]) { active = i; build_opts(); + if (!process_common_opts()) + { + return command_usage("invalid options"); + } + optind = 2; return cmds[i].call(); } } From c10a13589ea7aae04bb40eadafe5b581ad9eecac Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 31 Oct 2023 09:28:33 +0100 Subject: [PATCH 09/10] testing: Use pki --ocsp as OCSP responder The only exception is the ikev2/ocsp-no-signer-cert scenario as the pki command won't sign an OCSP response with a certificate that isn't the CA certificate or marked as an OCSP signer. --- testing/hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 6 ++---- testing/hosts/winnetou/etc/ca/research/ocsp/ocsp.cgi | 6 ++---- testing/hosts/winnetou/etc/ca/sales/ocsp/ocsp.cgi | 6 ++---- .../ocsp-local-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 6 ++---- .../ocsp-no-signer-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 5 +++-- .../ocsp-root-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 6 ++---- .../ocsp-timeouts-good/hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 6 ++---- .../hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 6 ++---- .../ocsp-untrusted-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 6 ++---- 9 files changed, 19 insertions(+), 34 deletions(-) diff --git a/testing/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/hosts/winnetou/etc/ca/ocsp/ocsp.cgi index 230bbf346c..92543cac34 100755 --- a/testing/hosts/winnetou/etc/ca/ocsp/ocsp.cgi +++ b/testing/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -5,7 +5,5 @@ cd /etc/ca echo "Content-type: application/ocsp-response" echo "" -cat | /usr/bin/openssl ocsp -index index.txt -CA strongswanCert.pem \ - -rkey ocspKey.pem -rsigner ocspCert.pem \ - -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert strongswanCert.pem --index index.txt \ + --cert ocspCert.pem --key ocspKey.pem --lifetime 5 --debug 0 diff --git a/testing/hosts/winnetou/etc/ca/research/ocsp/ocsp.cgi b/testing/hosts/winnetou/etc/ca/research/ocsp/ocsp.cgi index 4154f5d823..58596b1936 100755 --- a/testing/hosts/winnetou/etc/ca/research/ocsp/ocsp.cgi +++ b/testing/hosts/winnetou/etc/ca/research/ocsp/ocsp.cgi @@ -5,7 +5,5 @@ cd /etc/ca/research echo "Content-type: application/ocsp-response" echo "" -cat | /usr/bin/openssl ocsp -index index.txt -CA researchCert.pem \ - -rkey ocspKey.pem -rsigner ocspCert.pem \ - -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert researchCert.pem --index index.txt \ + --cert ocspCert.pem --key ocspKey.pem --lifetime 5 --debug 0 diff --git a/testing/hosts/winnetou/etc/ca/sales/ocsp/ocsp.cgi b/testing/hosts/winnetou/etc/ca/sales/ocsp/ocsp.cgi index 05d304dc3c..3b067a10cf 100755 --- a/testing/hosts/winnetou/etc/ca/sales/ocsp/ocsp.cgi +++ b/testing/hosts/winnetou/etc/ca/sales/ocsp/ocsp.cgi @@ -5,7 +5,5 @@ cd /etc/ca/sales echo "Content-type: application/ocsp-response" echo "" -cat | /usr/bin/openssl ocsp -index index.txt -CA salesCert.pem \ - -rkey ocspKey.pem -rsigner ocspCert.pem \ - -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert salesCert.pem --index index.txt \ + --cert ocspCert.pem --key ocspKey.pem --lifetime 5 --debug 0 diff --git a/testing/tests/ikev2/ocsp-local-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/tests/ikev2/ocsp-local-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi index ea9be3d92f..bf76e6a750 100755 --- a/testing/tests/ikev2/ocsp-local-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi +++ b/testing/tests/ikev2/ocsp-local-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -5,7 +5,5 @@ cd /etc/ca echo "Content-type: application/ocsp-response" echo "" -cat | /usr/bin/openssl ocsp -index index.txt -CA strongswanCert.pem \ - -rkey ocspKey-self.pem -rsigner ocspCert-self.pem \ - -resp_no_certs -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert strongswanCert.pem --index index.txt \ + --cert ocspCert-self.pem --key ocspKey-self.pem --lifetime 5 --debug 0 diff --git a/testing/tests/ikev2/ocsp-no-signer-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/tests/ikev2/ocsp-no-signer-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi index 8c7b9cd136..6b033d0aa0 100755 --- a/testing/tests/ikev2/ocsp-no-signer-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi +++ b/testing/tests/ikev2/ocsp-no-signer-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -5,7 +5,8 @@ cd /etc/ca echo "Content-type: application/ocsp-response" echo "" +# we have to use OpenSSL here as pki --ocsp rejects signing with such a +# non-OCSP-signer certificate cat | /usr/bin/openssl ocsp -index index.txt -CA strongswanCert.pem \ -rkey winnetouKey.pem -rsigner winnetouCert.pem \ - -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat + -nmin 5 -reqin /dev/stdin -respout /dev/stdout | cat diff --git a/testing/tests/ikev2/ocsp-root-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/tests/ikev2/ocsp-root-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi index 74ca4181cc..1755af9c16 100755 --- a/testing/tests/ikev2/ocsp-root-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi +++ b/testing/tests/ikev2/ocsp-root-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -5,7 +5,5 @@ cd /etc/ca echo "Content-type: application/ocsp-response" echo "" -cat | /usr/bin/openssl ocsp -index index.txt -CA strongswanCert.pem \ - -rkey strongswanKey.pem -rsigner strongswanCert.pem \ - -resp_no_certs -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert strongswanCert.pem --index index.txt \ + --key strongswanKey.pem --lifetime 5 --debug 0 diff --git a/testing/tests/ikev2/ocsp-timeouts-good/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/tests/ikev2/ocsp-timeouts-good/hosts/winnetou/etc/ca/ocsp/ocsp.cgi index 7dd3ddb0f8..ef1b89611f 100755 --- a/testing/tests/ikev2/ocsp-timeouts-good/hosts/winnetou/etc/ca/ocsp/ocsp.cgi +++ b/testing/tests/ikev2/ocsp-timeouts-good/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -8,7 +8,5 @@ echo "" # simulate a delayed response sleep 2 -cat | /usr/bin/openssl ocsp -index index.txt -CA strongswanCert.pem \ - -rkey ocspKey.pem -rsigner ocspCert.pem \ - -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert strongswanCert.pem --index index.txt \ + --cert ocspCert.pem --key ocspKey.pem --lifetime 5 --debug 0 diff --git a/testing/tests/ikev2/ocsp-timeouts-unknown/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/tests/ikev2/ocsp-timeouts-unknown/hosts/winnetou/etc/ca/ocsp/ocsp.cgi index 7dd3ddb0f8..ef1b89611f 100755 --- a/testing/tests/ikev2/ocsp-timeouts-unknown/hosts/winnetou/etc/ca/ocsp/ocsp.cgi +++ b/testing/tests/ikev2/ocsp-timeouts-unknown/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -8,7 +8,5 @@ echo "" # simulate a delayed response sleep 2 -cat | /usr/bin/openssl ocsp -index index.txt -CA strongswanCert.pem \ - -rkey ocspKey.pem -rsigner ocspCert.pem \ - -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert strongswanCert.pem --index index.txt \ + --cert ocspCert.pem --key ocspKey.pem --lifetime 5 --debug 0 diff --git a/testing/tests/ikev2/ocsp-untrusted-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/tests/ikev2/ocsp-untrusted-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi index bce963fadd..bf76e6a750 100755 --- a/testing/tests/ikev2/ocsp-untrusted-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi +++ b/testing/tests/ikev2/ocsp-untrusted-cert/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -5,7 +5,5 @@ cd /etc/ca echo "Content-type: application/ocsp-response" echo "" -cat | /usr/bin/openssl ocsp -index index.txt -CA strongswanCert.pem \ - -rkey ocspKey-self.pem -rsigner ocspCert-self.pem \ - -nmin 5 \ - -reqin /dev/stdin -respout /dev/stdout | cat +cat | pki --ocsp --respond --cacert strongswanCert.pem --index index.txt \ + --cert ocspCert-self.pem --key ocspKey-self.pem --lifetime 5 --debug 0 From 801c6c32e5f5939bb7ede30502ead05c991d0a3b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 7 Nov 2023 11:21:14 +0100 Subject: [PATCH 10/10] testing: Use a single OCSP responder for ikev2-multi-ca/ocsp-signers scenario This demonstrates the multi-CA capabilities of the pki --ocsp command. --- .../hosts/moon/etc/swanctl/swanctl.conf | 10 +++++----- .../hosts/winnetou/etc/ca/ocsp/ocsp.cgi | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 testing/tests/ikev2-multi-ca/ocsp-signers/hosts/winnetou/etc/ca/ocsp/ocsp.cgi diff --git a/testing/tests/ikev2-multi-ca/ocsp-signers/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/ikev2-multi-ca/ocsp-signers/hosts/moon/etc/swanctl/swanctl.conf index c5beb2cde9..fb6e7cb9f6 100755 --- a/testing/tests/ikev2-multi-ca/ocsp-signers/hosts/moon/etc/swanctl/swanctl.conf +++ b/testing/tests/ikev2-multi-ca/ocsp-signers/hosts/moon/etc/swanctl/swanctl.conf @@ -11,11 +11,11 @@ connections { remote { auth = pubkey cacerts = researchCert.pem - revocation = ifuri + revocation = ifuri } children { alice { - local_ts = 10.1.0.10/32 + local_ts = 10.1.0.10/32 esp_proposals = aes128-sha256-ecp256 } } @@ -34,7 +34,7 @@ connections { remote { auth = pubkey cacerts = salesCert.pem - revocation = ifuri + revocation = ifuri } children { venus { @@ -56,11 +56,11 @@ authorities { research { cacert = researchCert.pem - ocsp_uris = http://ocsp.strongswan.org:8881 + ocsp_uris = http://ocsp.strongswan.org:8880 } sales { cacert = salesCert.pem - ocsp_uris = http://ocsp.strongswan.org:8882 + ocsp_uris = http://ocsp.strongswan.org:8880 } } diff --git a/testing/tests/ikev2-multi-ca/ocsp-signers/hosts/winnetou/etc/ca/ocsp/ocsp.cgi b/testing/tests/ikev2-multi-ca/ocsp-signers/hosts/winnetou/etc/ca/ocsp/ocsp.cgi new file mode 100644 index 0000000000..f0942445c5 --- /dev/null +++ b/testing/tests/ikev2-multi-ca/ocsp-signers/hosts/winnetou/etc/ca/ocsp/ocsp.cgi @@ -0,0 +1,15 @@ +#!/bin/bash + +cd /etc/ca + +echo "Content-type: application/ocsp-response" +echo "" + +cat | pki --ocsp --respond \ + --cacert strongswanCert.pem --index index.txt \ + --cert ocspCert.pem --key ocspKey.pem \ + --cacert research/researchCert.pem --index research/index.txt \ + --cert research/ocspCert.pem --key research/ocspKey.pem \ + --cacert sales/salesCert.pem --index sales/index.txt \ + --cert sales/ocspCert.pem --key sales/ocspKey.pem \ + --lifetime 5 --debug 0