mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-03 00:00:24 -04:00
647 lines
18 KiB
C
647 lines
18 KiB
C
/*
|
|
* Copyright (C) 2023 Andreas Steffen, strongSec GmbH
|
|
*
|
|
* 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 <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>
|
|
|
|
/*
|
|
* Verifies the optional OCSP request signature generated by an OCSP requestor
|
|
*/
|
|
static bool verify_signature(certificate_t *ocsp_req, mem_cred_t *creds)
|
|
{
|
|
identification_t *signer;
|
|
certificate_t *signer_cert, *cert_found;
|
|
ocsp_request_t *ocsp_request;
|
|
enumerator_t *certs;
|
|
bool trusted = TRUE;
|
|
|
|
ocsp_request = (ocsp_request_t*)ocsp_req;
|
|
|
|
signer_cert = ocsp_request->get_signer_cert(ocsp_request);
|
|
if (signer_cert)
|
|
{
|
|
signer = signer_cert->get_subject(signer_cert);
|
|
|
|
/* establish trust relative to root CA */
|
|
creds->add_cert(creds, FALSE, signer_cert->get_ref(signer_cert));
|
|
certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
|
|
KEY_ANY, signer, FALSE);
|
|
trusted = certs->enumerate(certs, &cert_found, NULL) &&
|
|
(cert_found == signer_cert);
|
|
certs->destroy(certs);
|
|
trusted = trusted && ocsp_req->issued_by(ocsp_req, signer_cert, NULL);
|
|
}
|
|
DBG1(DBG_APP, "requestor is %strusted", trusted ? "" : "not ");
|
|
|
|
return trusted;
|
|
}
|
|
|
|
/*
|
|
* Find the CA certificate of the certificate issuer based on the issuerKey and
|
|
* issuerName hashes contained in the OCSP request
|
|
*/
|
|
static bool find_issuer_cacert(hash_algorithm_t hashAlgorithm,
|
|
chunk_t issuerKeyHash, chunk_t issuerNameHash,
|
|
certificate_t **issuer_cacert)
|
|
{
|
|
bool issuerKeyHash_ok = FALSE, issuerNameHash_ok = FALSE;
|
|
certificate_t *candidate;
|
|
identification_t *issuer;
|
|
public_key_t *public;
|
|
x509_t *x509_ca;
|
|
chunk_t caKeyHash = chunk_empty, caNameHash = chunk_empty;
|
|
hasher_t *hasher;
|
|
enumerator_t *certs;
|
|
|
|
*issuer_cacert = NULL;
|
|
|
|
if (hashAlgorithm != HASH_SHA1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
certs = lib->credmgr->create_cert_enumerator(lib->credmgr, CERT_X509,
|
|
KEY_ANY, NULL, TRUE);
|
|
while (certs->enumerate(certs, &candidate))
|
|
{
|
|
x509_ca = (x509_t*)candidate;
|
|
|
|
if (!(x509_ca->get_flags(x509_ca) & X509_CA))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* retrieve the caKeyHash of the candidate issuer */
|
|
public = candidate->get_public_key(candidate);
|
|
if (!public)
|
|
{
|
|
DBG1(DBG_APP, "could not retrieve public key of cacert candidate");
|
|
break;
|
|
}
|
|
if (!public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &caKeyHash))
|
|
{
|
|
DBG1(DBG_APP, "could not retrieve SHA1 hash of public key");
|
|
public->destroy(public);
|
|
break;
|
|
}
|
|
|
|
issuerKeyHash_ok = chunk_equals_const(issuerKeyHash, caKeyHash);
|
|
public->destroy(public);
|
|
if (!issuerKeyHash_ok)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* compute the caNameHash of the candidate issuer */
|
|
issuer = candidate->get_subject(candidate);
|
|
|
|
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
|
if (!hasher)
|
|
{
|
|
DBG1(DBG_APP, "failed to create SHA1 hasher");
|
|
break;
|
|
}
|
|
|
|
if (!hasher->allocate_hash(hasher, issuer->get_encoding(issuer),
|
|
&caNameHash))
|
|
{
|
|
hasher->destroy(hasher);
|
|
DBG1(DBG_APP, "failed to compute SHA1 caNameHash");
|
|
break;
|
|
}
|
|
hasher->destroy(hasher);
|
|
|
|
issuerNameHash_ok = chunk_equals_const(issuerNameHash, caNameHash);
|
|
chunk_free(&caNameHash);
|
|
if (!issuerNameHash_ok)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* we found the issuer */
|
|
DBG1(DBG_APP, "issuer: \"%Y\"", issuer);
|
|
*issuer_cacert = candidate;
|
|
|
|
break;
|
|
}
|
|
certs->destroy(certs);
|
|
|
|
DBG1(DBG_APP, " issuerKeyHash: %#B (%s)", &issuerKeyHash,
|
|
issuerKeyHash_ok ? "ok" : "no match");
|
|
DBG1(DBG_APP, " issuerNameHash: %#B (%s)", &issuerNameHash,
|
|
issuerNameHash_ok ? "ok" : "no match");
|
|
|
|
return (*issuer_cacert != NULL);
|
|
}
|
|
|
|
/*
|
|
* Find an OCSP signer certificate. Either the certificate of the CA itself that
|
|
* 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.
|
|
*/
|
|
static void find_ocsp_signer(certificate_t *first_issuer, bool *self_signed,
|
|
certificate_t **cert, private_key_t **key)
|
|
{
|
|
certificate_t *candidate;
|
|
identification_t *keyid;
|
|
private_key_t *key_candidate;
|
|
chunk_t subKeyId, authKeyId, subKeyId_ca;
|
|
x509_t *x509, *x509_ca;
|
|
x509_flag_t flags;
|
|
enumerator_t *certs;
|
|
|
|
/* retrieve the subjectKeyIdentifier of the first issuer certificate */
|
|
x509_ca = (x509_t*)first_issuer;
|
|
subKeyId_ca = x509_ca->get_subjectKeyIdentifier(x509_ca);
|
|
|
|
/* iterate over all certificates */
|
|
certs = lib->credmgr->create_cert_enumerator(lib->credmgr, CERT_X509,
|
|
KEY_ANY, NULL, TRUE);
|
|
while (certs->enumerate(certs, &candidate))
|
|
{
|
|
/* get the flags and key identifiers of the candidate certificate */
|
|
x509 = (x509_t*)candidate;
|
|
flags = x509->get_flags(x509);
|
|
subKeyId = x509->get_subjectKeyIdentifier(x509);
|
|
authKeyId = x509->get_authKeyIdentifier(x509);
|
|
|
|
/* get a private key matching the candidate certificate */
|
|
keyid = identification_create_from_encoding(ID_KEY_ID, subKeyId);
|
|
key_candidate = lib->credmgr->get_private(lib->credmgr,
|
|
KEY_ANY, keyid, NULL);
|
|
keyid->destroy(keyid);
|
|
|
|
if (key_candidate)
|
|
{
|
|
if (((flags & X509_OCSP_SIGNER && chunk_equals(authKeyId, subKeyId_ca)) ||
|
|
(flags & X509_CA && chunk_equals(subKeyId, subKeyId_ca))) && !*key)
|
|
{
|
|
*cert = candidate;
|
|
*key = key_candidate;
|
|
continue;
|
|
}
|
|
else if (flags & X509_SELF_SIGNED && !(flags & X509_CA))
|
|
{
|
|
DESTROY_IF(*key);
|
|
*cert = candidate;
|
|
*key = key_candidate;
|
|
*self_signed = TRUE;
|
|
break;
|
|
}
|
|
key_candidate->destroy(key_candidate);
|
|
}
|
|
}
|
|
certs->destroy(certs);
|
|
}
|
|
|
|
/**
|
|
* Show|Respond to OCSP requests
|
|
*/
|
|
static int ocsp()
|
|
{
|
|
char *arg, *file = NULL, *error = NULL;
|
|
identification_t *requestor;
|
|
cred_encoding_type_t form = CERT_ASN1_DER;
|
|
private_key_t *key = NULL;
|
|
certificate_t *cert = NULL, *ocsp_req = NULL, *ocsp_resp = NULL;
|
|
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, handle = chunk_empty;
|
|
chunk_t issuerNameHash, issuerKeyHash, serialNumber;
|
|
hash_algorithm_t hashAlgorithm = HASH_SHA1, digest = HASH_UNKNOWN;
|
|
signature_params_t *scheme = NULL;
|
|
time_t lifetime = 0;
|
|
mem_cred_t *creds;
|
|
bool multiple_issuers = FALSE, self_signed = FALSE;
|
|
enumerator_t *enumerator;
|
|
int res = 1;
|
|
|
|
enum {
|
|
OP_SHOW,
|
|
OP_RESPOND,
|
|
} op = OP_SHOW;
|
|
|
|
bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
|
|
lib->ns);
|
|
|
|
creds = mem_cred_create();
|
|
|
|
while (TRUE)
|
|
{
|
|
switch (command_getopt(&arg))
|
|
{
|
|
case 'h': /* --help */
|
|
goto usage;
|
|
case 'i': /* --in */
|
|
file = arg;
|
|
continue;
|
|
case 'r': /* --respond */
|
|
op = OP_RESPOND;
|
|
continue;
|
|
case 'k': /* --key */
|
|
key = lib->creds->create(lib->creds,
|
|
CRED_PRIVATE_KEY, KEY_ANY,
|
|
BUILD_FROM_FILE, arg, BUILD_END);
|
|
if (!key)
|
|
{
|
|
error = "parsing private key failed";
|
|
goto usage;
|
|
}
|
|
creds->add_key(creds, key);
|
|
continue;
|
|
case 'K': /* --keyid */
|
|
handle = chunk_from_hex(chunk_create(arg, strlen(arg)), NULL);
|
|
key = lib->creds->create(lib->creds,
|
|
CRED_PRIVATE_KEY, KEY_ANY,
|
|
BUILD_PKCS11_KEYID, handle, BUILD_END);
|
|
chunk_free(&handle);
|
|
if (!key)
|
|
{
|
|
DBG1(DBG_APP, "attaching to private key handle %s failed", arg);
|
|
goto usage;
|
|
}
|
|
creds->add_key(creds, key);
|
|
continue;
|
|
case 'c': /* --cert */
|
|
cert = lib->creds->create(lib->creds,
|
|
CRED_CERTIFICATE, CERT_X509,
|
|
BUILD_FROM_FILE, arg, BUILD_END);
|
|
if (!cert)
|
|
{
|
|
error = "parsing certificate failed";
|
|
goto usage;
|
|
}
|
|
creds->add_cert(creds, TRUE, cert);
|
|
continue;
|
|
case 'X': /* --certid */
|
|
handle = chunk_from_hex(chunk_create(arg, strlen(arg)), NULL);
|
|
cert = lib->creds->create(lib->creds,
|
|
CRED_CERTIFICATE, CERT_X509,
|
|
BUILD_PKCS11_KEYID, handle, BUILD_END);
|
|
chunk_free(&handle);
|
|
if (!cert)
|
|
{
|
|
DBG1(DBG_APP, "attaching to certificate handle %s failed", arg);
|
|
goto usage;
|
|
}
|
|
creds->add_cert(creds, TRUE, cert);
|
|
continue;
|
|
case 'C': /* --cacert */
|
|
DESTROY_IF(cacert);
|
|
cacert = lib->creds->create(lib->creds,
|
|
CRED_CERTIFICATE, CERT_X509,
|
|
BUILD_FROM_FILE, arg, BUILD_END);
|
|
if (!cacert)
|
|
{
|
|
error = "parsing CA certificate failed";
|
|
goto usage;
|
|
}
|
|
cacert = creds->add_cert_ref(creds, TRUE, cacert);
|
|
continue;
|
|
case 'l': /* --lifetime */
|
|
lifetime = atoi(arg) * 60;
|
|
if (!lifetime)
|
|
{
|
|
error = "invalid --lifetime value";
|
|
goto usage;
|
|
}
|
|
continue;
|
|
case 'g': /* --digest */
|
|
if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
|
|
{
|
|
error = "invalid --digest type";
|
|
goto usage;
|
|
}
|
|
continue;
|
|
case 'R': /* --rsa-padding */
|
|
if (!parse_rsa_padding(arg, &pss))
|
|
{
|
|
error = "invalid RSA padding";
|
|
goto usage;
|
|
}
|
|
continue;
|
|
case 'x': /* --help */
|
|
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:
|
|
error = "invalid --ocsp option";
|
|
goto usage;
|
|
}
|
|
break;
|
|
}
|
|
|
|
lib->credmgr->add_local_set(lib->credmgr, &creds->set, FALSE);
|
|
|
|
responses = linked_list_create();
|
|
|
|
if (op == OP_RESPOND && !cacert)
|
|
{
|
|
error = "respond mode requires a CA certificate";
|
|
goto end;
|
|
}
|
|
|
|
if (op == OP_RESPOND && !key)
|
|
{
|
|
error = "respond mode requires a private signer key";
|
|
goto end;
|
|
}
|
|
|
|
/* re-initialize signing certificate and key pointers */
|
|
cert = NULL;
|
|
key = NULL;
|
|
|
|
if (file)
|
|
{
|
|
ocsp_req = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
|
CERT_X509_OCSP_REQUEST,
|
|
BUILD_FROM_FILE, file, BUILD_END);
|
|
}
|
|
else
|
|
{
|
|
chunk_t chunk;
|
|
|
|
set_file_mode(stdin, CERT_ASN1_DER);
|
|
if (!chunk_from_fd(0, &chunk))
|
|
{
|
|
fprintf(stderr, "%s: ", strerror(errno));
|
|
error = "reading certificate request failed";
|
|
goto end;
|
|
}
|
|
ocsp_req = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
|
CERT_X509_OCSP_REQUEST,
|
|
BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
|
|
free(chunk.ptr);
|
|
}
|
|
if (!ocsp_req)
|
|
{
|
|
if (op == OP_SHOW)
|
|
{
|
|
error = "malformed OCSP request";
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
DBG1(DBG_APP, "malformed OCSP request");
|
|
ocsp_status = OCSP_MALFORMEDREQUEST;
|
|
goto gen;
|
|
}
|
|
}
|
|
ocsp_request = (ocsp_request_t*)ocsp_req;
|
|
|
|
/* does the requestor identify itself? */
|
|
requestor = ocsp_req->get_subject(ocsp_req);
|
|
if (requestor)
|
|
{
|
|
DBG1(DBG_APP, "requestor: \"%Y\"", requestor);
|
|
|
|
/* verify an optional ocsp request signature */
|
|
if (!verify_signature(ocsp_req, creds))
|
|
{
|
|
ocsp_status = OCSP_UNAUTHORIZED;
|
|
goto gen;
|
|
}
|
|
}
|
|
|
|
/* extract nonce from OCSP request */
|
|
nonce = ocsp_request->get_nonce(ocsp_request);
|
|
if (nonce.len > 0)
|
|
{
|
|
DBG1(DBG_APP, "nonce: %#B", &nonce);
|
|
}
|
|
|
|
/* 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,
|
|
&issuerKeyHash, &serialNumber))
|
|
{
|
|
certificate_t *issuer_cacert = NULL;
|
|
cert_validation_t status = VALIDATION_FAILED;
|
|
ocsp_single_response_t *response = NULL;
|
|
crl_reason_t revocationReason;
|
|
time_t revocationTime;
|
|
|
|
/* search for the matching issuer cacert */
|
|
if (find_issuer_cacert(hashAlgorithm, issuerKeyHash, issuerNameHash,
|
|
&issuer_cacert))
|
|
{
|
|
if (!first_issuer)
|
|
{
|
|
first_issuer = issuer_cacert;
|
|
|
|
/* search for a signing certificate plus matching private key */
|
|
if (op == OP_RESPOND)
|
|
{
|
|
find_ocsp_signer(first_issuer, &self_signed, &cert, &key);
|
|
}
|
|
}
|
|
else if (first_issuer != issuer_cacert)
|
|
{
|
|
multiple_issuers = TRUE;
|
|
}
|
|
}
|
|
DBG1(DBG_APP, " serialNumber: %#B", &serialNumber);
|
|
|
|
if (op == OP_SHOW)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/**
|
|
* fill in the OCSP single response
|
|
*/
|
|
response = ocsp_single_response_create();
|
|
response->hashAlgorithm = hashAlgorithm;
|
|
response->issuerNameHash = chunk_clone(issuerNameHash);
|
|
response->issuerKeyHash = chunk_clone(issuerKeyHash);
|
|
response->serialNumber = chunk_clone(serialNumber);
|
|
response->thisUpdate = time(NULL);
|
|
DBG1(DBG_APP, " thisUpdate: %#T", &response->thisUpdate, TRUE);
|
|
|
|
if (lifetime)
|
|
{
|
|
response->nextUpdate = response->thisUpdate + lifetime;
|
|
DBG1(DBG_APP, " nextUpdate: %#T", &response->nextUpdate, TRUE);
|
|
}
|
|
|
|
if (issuer_cacert && (issuer_cacert == first_issuer || self_signed))
|
|
{
|
|
status = lib->ocsp->get_status(lib->ocsp,
|
|
issuer_cacert, serialNumber,
|
|
&revocationTime, &revocationReason);
|
|
}
|
|
DBG1(DBG_APP, " certValidation: %N", cert_validation_names, status);
|
|
response->status = status;
|
|
|
|
if (status == VALIDATION_REVOKED || status == VALIDATION_ON_HOLD)
|
|
{
|
|
DBG1(DBG_APP, " revocationTime: %T", &revocationTime, TRUE);
|
|
DBG1(DBG_APP, " revocationReason: %N", crl_reason_names,
|
|
revocationReason);
|
|
response->revocationTime = revocationTime;
|
|
response->revocationReason = revocationReason;
|
|
}
|
|
responses->insert_last(responses, response);
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
|
|
if (multiple_issuers)
|
|
{
|
|
DBG1(DBG_APP, "there are multiple known issuers");
|
|
}
|
|
|
|
gen:
|
|
if (op == OP_RESPOND)
|
|
{
|
|
if (cert)
|
|
{
|
|
DBG1(DBG_APP, "%s \"%Y\"",
|
|
self_signed ? "self-signed signer:" : "trusted signer: ",
|
|
cert->get_subject(cert));
|
|
|
|
scheme = get_signature_scheme(key, digest, pss);
|
|
if (scheme)
|
|
{
|
|
if (digest == HASH_UNKNOWN)
|
|
{
|
|
digest = hasher_from_signature_scheme(scheme->scheme,
|
|
scheme->params);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG1(DBG_APP, "no signature scheme found");
|
|
ocsp_status = OCSP_INTERNALERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG1(DBG_APP, "no signer certificate found");
|
|
ocsp_status = OCSP_INTERNALERROR;
|
|
}
|
|
DBG1(DBG_APP, "ocspResponseStatus: %N", ocsp_status_names, ocsp_status);
|
|
|
|
enumerator = responses->create_enumerator(responses);
|
|
ocsp_resp = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
|
CERT_X509_OCSP_RESPONSE,
|
|
BUILD_OCSP_STATUS, ocsp_status,
|
|
BUILD_OCSP_RESPONSES, enumerator,
|
|
BUILD_SIGNING_KEY, key,
|
|
BUILD_SIGNING_CERT, cert,
|
|
BUILD_SIGNATURE_SCHEME, scheme,
|
|
BUILD_NONCE, nonce,
|
|
BUILD_END);
|
|
enumerator->destroy(enumerator);
|
|
|
|
if (!ocsp_resp)
|
|
{
|
|
error = "generating OCSP response failed";
|
|
goto end;
|
|
}
|
|
if (!ocsp_resp->get_encoding(ocsp_resp, form, &encoding))
|
|
{
|
|
error = "encoding OCSP response failed";
|
|
goto end;
|
|
}
|
|
set_file_mode(stdout, form);
|
|
if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
|
|
{
|
|
error = "writing OCSP response failed";
|
|
goto end;
|
|
}
|
|
}
|
|
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);
|
|
responses->destroy_offset(responses,
|
|
offsetof(ocsp_single_response_t, destroy));
|
|
DESTROY_IF(ocsp_req);
|
|
DESTROY_IF(ocsp_resp);
|
|
signature_params_destroy(scheme);
|
|
free(encoding.ptr);
|
|
if (error)
|
|
{
|
|
fprintf(stderr, "%s\n", error);
|
|
}
|
|
return res;
|
|
|
|
usage:
|
|
array_destroy_offset(index_responders, offsetof(ocsp_responder_t, destroy));
|
|
DESTROY_IF(cacert);
|
|
creds->destroy(creds);
|
|
return command_usage(error);
|
|
}
|
|
|
|
/**
|
|
* Register the command.
|
|
*/
|
|
static void __attribute__ ((constructor))reg()
|
|
{
|
|
command_register((command_t) {
|
|
ocsp, 'o', "ocsp", "OCSP responder",
|
|
{"[--in file] [--respond] [--cert file|--certid hex]+ [--key file|--keyid hex]+ ",
|
|
"[--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]"},
|
|
{
|
|
{"help", 'h', 0, "show usage information"},
|
|
{"respond", 'r', 0, "respond to OCSP request with OCSP response"},
|
|
{"in", 'i', 1, "input file, default: stdin"},
|
|
{"key", 'k', 1, "path to OCSP signing private key (can be used multiple times)"},
|
|
{"keyid", 'K', 1, "smartcard or TPM private key object handle (can be used multiple times)"},
|
|
{"cert", 'c', 1, "path to OCSP signing certificate (can be used multiple times"},
|
|
{"certid", 'X', 1, "smartcard or TPM certificate object handle (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)"},
|
|
}
|
|
});
|
|
}
|