pki: Add option to load certificate status information from index.txt

Each index.txt is associated with the most recently loaded CA
certificate.
This commit is contained in:
Tobias Brunner
2023-11-13 12:50:47 +01:00
parent f26ca67d8c
commit 95c7d49954
2 changed files with 81 additions and 6 deletions
+31 -5
View File
@@ -18,7 +18,9 @@
#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>
@@ -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)"},
+50 -1
View File
@@ -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: