mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-04 00:00:14 -04:00
Merge branch 'ocsp-responder-index'
Adds support for multiple OCSP responders in `pki --ocsp` and one that is based on OpenSSL-style index.txt files. The parser for these files also accepts simplified files that only specify the status, serial number and optional revocation date/reason. The OCSP test scenarios are also updated to use this OCSP responder including one that shows the multi-CA capabilities of the --ocsp command and the --index option.
This commit is contained in:
commit
a1224b6c80
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -22,10 +22,10 @@
|
||||
#ifndef OCSP_RESPONDER_H_
|
||||
#define OCSP_RESPONDER_H_
|
||||
|
||||
#include <credentials/certificates/crl.h>
|
||||
|
||||
typedef struct ocsp_responder_t ocsp_responder_t;
|
||||
|
||||
#include <credentials/certificates/crl.h>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
119
src/libstrongswan/credentials/ocsp_responders.c
Normal file
119
src/libstrongswan/credentials/ocsp_responders.c
Normal file
@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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 <collections/linked_list.h>
|
||||
#include <threading/rwlock.h>
|
||||
|
||||
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;
|
||||
}
|
76
src/libstrongswan/credentials/ocsp_responders.h
Normal file
76
src/libstrongswan/credentials/ocsp_responders.h
Normal file
@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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 <credentials/certificates/ocsp_responder.h>
|
||||
|
||||
/**
|
||||
* 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_ @}*/
|
@ -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();
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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 = \
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,13 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "pki.h"
|
||||
#include "ocsp/index_responder.h"
|
||||
|
||||
#include <collections/array.h>
|
||||
#include <credentials/sets/mem_cred.h>
|
||||
#include <credentials/certificates/ocsp_request.h>
|
||||
#include <credentials/certificates/ocsp_response.h>
|
||||
#include <credentials/certificates/ocsp_single_response.h>
|
||||
#include <credentials/certificates/ocsp_responder.h>
|
||||
|
||||
/*
|
||||
* Verifies the optional OCSP request signature generated by an OCSP requestor
|
||||
@ -156,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.
|
||||
@ -181,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);
|
||||
@ -229,8 +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 *ocsp_responder = NULL;
|
||||
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;
|
||||
@ -286,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);
|
||||
@ -294,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;
|
||||
@ -318,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:
|
||||
@ -333,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;
|
||||
}
|
||||
|
||||
@ -406,18 +424,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)
|
||||
{
|
||||
DBG1(DBG_APP, " no ocsp-responder found");
|
||||
ocsp_status = OCSP_INTERNALERROR;
|
||||
goto gen;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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,
|
||||
@ -474,9 +480,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 +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);
|
||||
@ -572,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);
|
||||
}
|
||||
@ -583,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]"},
|
||||
{
|
||||
@ -593,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)"},
|
||||
|
@ -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:
|
||||
|
261
src/pki/ocsp/index_responder.c
Normal file
261
src/pki/ocsp/index_responder.c
Normal file
@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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 <errno.h>
|
||||
|
||||
#include "index_responder.h"
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
#include <collections/hashtable.h>
|
||||
|
||||
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;
|
||||
}
|
38
src/pki/ocsp/index_responder.h
Normal file
38
src/pki/ocsp/index_responder.h
Normal file
@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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 <credentials/certificates/ocsp_responder.h>
|
||||
|
||||
/**
|
||||
* 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_ @} */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user