Skip to content

Commit 199c708

Browse files
strongX509tobiasbrunner
authored andcommitted
openxpki: OCSP responder plugin accessing OpenXPKI
The openxpki plugin directly access the certificates table in the OpenXPKI's MariaDB in order to retrieve the status of an issued X.509 certificate based on its serial number.
1 parent 24d45de commit 199c708

File tree

10 files changed

+476
-2
lines changed

10 files changed

+476
-2
lines changed

conf/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ plugins = \
7979
plugins/lookip.opt \
8080
plugins/ntru.opt \
8181
plugins/openssl.opt \
82+
plugins/openxpki.opt \
8283
plugins/osx-attr.opt \
8384
plugins/p-cscf.opt \
8485
plugins/pkcs11.opt \

conf/plugins/openxpki.opt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
charon.plugins.openxpki.database =
2+
Database URI connecting to the OpenXPKI **certificate** database. If it
3+
contains a password, make sure to adjust the permissions of the config
4+
file accordingly.

configure.ac

+6-2
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ ARG_DISBL_SET([pkcs12], [disable PKCS12 container support plugin.])
178178
ARG_DISBL_SET([pubkey], [disable RAW public key support plugin.])
179179
ARG_DISBL_SET([sshkey], [disable SSH key decoding plugin.])
180180
ARG_DISBL_SET([x509], [disable X509 certificate implementation plugin.])
181+
ARG_ENABL_SET([openxpki], [enable OCSP responder accessing OpenXPKI certificate database.])
181182
# fetcher/resolver plugins
182183
ARG_ENABL_SET([curl], [enable CURL fetcher plugin to fetch files via libcurl. Requires libcurl.])
183184
ARG_ENABL_SET([files], [enable simple file:// URI fetcher.])
@@ -1592,8 +1593,9 @@ ADD_PLUGIN([curl], [s charon pki scripts nm cmd])
15921593
ADD_PLUGIN([files], [s charon pki scripts nm cmd])
15931594
ADD_PLUGIN([winhttp], [s charon pki scripts])
15941595
ADD_PLUGIN([soup], [s charon pki scripts nm cmd])
1595-
ADD_PLUGIN([mysql], [s charon pool manager medsrv attest])
1596-
ADD_PLUGIN([sqlite], [s charon pool manager medsrv attest])
1596+
ADD_PLUGIN([mysql], [s charon pki pool manager medsrv attest])
1597+
ADD_PLUGIN([sqlite], [s charon pki pool manager medsrv attest])
1598+
ADD_PLUGIN([openxpki], [s pki])
15971599
ADD_PLUGIN([attr], [c charon])
15981600
ADD_PLUGIN([attr-sql], [c charon])
15991601
ADD_PLUGIN([load-tester], [c charon])
@@ -1728,6 +1730,7 @@ AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue)
17281730
AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue)
17291731
AM_CONDITIONAL(USE_PKCS8, test x$pkcs8 = xtrue)
17301732
AM_CONDITIONAL(USE_PKCS12, test x$pkcs12 = xtrue)
1733+
AM_CONDITIONAL(USE_OPENXPKI, test x$openxpki = xtrue)
17311734
AM_CONDITIONAL(USE_PGP, test x$pgp = xtrue)
17321735
AM_CONDITIONAL(USE_DNSKEY, test x$dnskey = xtrue)
17331736
AM_CONDITIONAL(USE_SSHKEY, test x$sshkey = xtrue)
@@ -2010,6 +2013,7 @@ AC_CONFIG_FILES([
20102013
src/libstrongswan/plugins/pkcs7/Makefile
20112014
src/libstrongswan/plugins/pkcs8/Makefile
20122015
src/libstrongswan/plugins/pkcs12/Makefile
2016+
src/libstrongswan/plugins/openxpki/Makefile
20132017
src/libstrongswan/plugins/pgp/Makefile
20142018
src/libstrongswan/plugins/dnskey/Makefile
20152019
src/libstrongswan/plugins/sshkey/Makefile

src/libstrongswan/Makefile.am

+8
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ credentials/certificates/certificate.h credentials/certificates/x509.h \
9292
credentials/certificates/ac.h credentials/certificates/crl.h \
9393
credentials/certificates/pkcs10.h credentials/certificates/ocsp_request.h \
9494
credentials/certificates/ocsp_response.h \
95+
credentials/certificates/ocsp_responder.h \
9596
credentials/certificates/pgp_certificate.h \
9697
credentials/certificates/certificate_printer.h \
9798
credentials/containers/container.h credentials/containers/pkcs7.h \
@@ -479,6 +480,13 @@ if MONOLITHIC
479480
endif
480481
endif
481482

483+
if USE_OPENXPKI
484+
SUBDIRS += plugins/openxpki
485+
if MONOLITHIC
486+
libstrongswan_la_LIBADD += plugins/openxpki/libstrongswan-openxpki.la
487+
endif
488+
endif
489+
482490
if USE_PGP
483491
SUBDIRS += plugins/pgp
484492
if MONOLITHIC
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (C) 2023 Andreas Steffen, strongSec GmbH
3+
*
4+
* Copyright (C) secunet Security Networks AG
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License as published by the
8+
* Free Software Foundation; either version 2 of the License, or (at your
9+
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10+
*
11+
* This program is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* for more details.
15+
*/
16+
17+
/**
18+
* @defgroup ocsp_responder ocsp_responder
19+
* @{ @ingroup certificates
20+
*/
21+
22+
#ifndef OCSP_RESPONDER_H_
23+
#define OCSP_RESPONDER_H_
24+
25+
#include <credentials/certificates/crl.h>
26+
27+
typedef struct ocsp_responder_t ocsp_responder_t;
28+
29+
/**
30+
* OCSP responder object.
31+
*/
32+
struct ocsp_responder_t {
33+
34+
/**
35+
* Check the status of a certificate given by its serial number
36+
*
37+
* @param cacert X.509 certificate of issuer CA
38+
* @param serial_number serial number of the certificate to be checked
39+
* @param revocation_time receives time of revocation, if revoked
40+
* @param reason receives reason of revocation, if revoked
41+
* @return certificate validation status
42+
*/
43+
cert_validation_t (*get_status)(ocsp_responder_t *this,
44+
certificate_t *cacert,
45+
chunk_t serial_number,
46+
time_t *revocation_time,
47+
crl_reason_t *revocation_reason);
48+
49+
/**
50+
* Destroy an ocsp_responder_t object.
51+
*/
52+
void (*destroy)(ocsp_responder_t *this);
53+
54+
};
55+
56+
#endif /** OCSP_RESPONDER_H_ @}*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
AM_CPPFLAGS = \
2+
-I$(top_srcdir)/src/libstrongswan
3+
4+
AM_CFLAGS = \
5+
$(PLUGIN_CFLAGS)
6+
7+
if MONOLITHIC
8+
noinst_LTLIBRARIES = libstrongswan-openxpki.la
9+
else
10+
plugin_LTLIBRARIES = libstrongswan-openxpki.la
11+
endif
12+
13+
libstrongswan_openxpki_la_SOURCES = \
14+
openxpki_plugin.h openxpki_plugin.c \
15+
openxpki_ocsp_responder.h openxpki_ocsp_responder.c
16+
17+
libstrongswan_openxpki_la_LDFLAGS = -module -avoid-version
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* Copyright (C) 2023 Andreas Steffen, strongSec GmbH
3+
*
4+
* Copyright (C) secunet Security Networks AG
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License as published by the
8+
* Free Software Foundation; either version 2 of the License, or (at your
9+
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10+
*
11+
* This program is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* for more details.
15+
*/
16+
17+
#include <library.h>
18+
#include <utils/debug.h>
19+
20+
#include "openxpki_ocsp_responder.h"
21+
22+
typedef struct private_openxpki_ocsp_responder_t private_openxpki_ocsp_responder_t;
23+
24+
/**
25+
* Private Data of a openxpki_ocsp_responder_t object.
26+
*/
27+
struct private_openxpki_ocsp_responder_t {
28+
29+
/**
30+
* Public data
31+
*/
32+
openxpki_ocsp_responder_t public;
33+
34+
/**
35+
* OpenXPKI certificate database
36+
*/
37+
database_t *db;
38+
};
39+
40+
METHOD(ocsp_responder_t, get_status, cert_validation_t,
41+
private_openxpki_ocsp_responder_t *this, certificate_t *cacert,
42+
chunk_t serial_number, time_t *revocation_time, crl_reason_t *reason)
43+
{
44+
cert_validation_t validation = VALIDATION_FAILED;
45+
int rev_time;
46+
const int max_decimals = 49;
47+
const int max_bytes = max_decimals / 2.4083;
48+
char serial[max_decimals + 1], authKeyId[60];
49+
char *status, *reason_code;
50+
chunk_t subjectKeyId;
51+
public_key_t *public;
52+
enumerator_t *e;
53+
bool success;
54+
55+
/* convert serialNumber from binary to decimal as required for the DB query.
56+
* check for a potential overflow since the database table field supports
57+
* up to 49 decimal digits, only.
58+
*/
59+
if (serial_number.len > max_bytes)
60+
{
61+
DBG1(DBG_LIB, "serialNumber conversion exceeds %d decimals", max_decimals);
62+
return VALIDATION_FAILED;
63+
64+
}
65+
chunk_to_dec(serial_number, serial);
66+
67+
/* additionally use the subjectyKeyId of the issuing CA for the DB query */
68+
public = cacert->get_public_key(cacert);
69+
success = public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &subjectKeyId);
70+
public->destroy(public);
71+
72+
if (!success)
73+
{
74+
DBG1(DBG_LIB, "failed to extract subjectKeyId from CA certificate");
75+
return VALIDATION_FAILED;
76+
}
77+
78+
/* the authKeyId of the certificate is the subjectKeyId of the issuing CA */
79+
snprintf(authKeyId, sizeof(authKeyId), "%#B", &subjectKeyId);
80+
81+
/* query the OpenXPKI certificate database */
82+
e = this->db->query(this->db, "SELECT status, reason_code, revocation_time "
83+
"FROM certificate WHERE cert_key = ? "
84+
"AND authority_key_identifier = ?", DB_TEXT, serial,
85+
DB_TEXT, authKeyId, DB_TEXT, DB_TEXT, DB_INT);
86+
if (e && e->enumerate(e, &status, &reason_code, &rev_time))
87+
{
88+
if (streq(status, "ISSUED") || streq(status, "ISSUANCE_PENDING"))
89+
{
90+
validation = VALIDATION_GOOD;
91+
}
92+
else if (streq(status, "UNKNOWN"))
93+
{
94+
validation = VALIDATION_FAILED;
95+
}
96+
else if (streq(status, "REVOKED") || streq(status, "HOLD") ||
97+
streq(status, "CRL_ISSUANCE_PENDING"))
98+
{
99+
validation = VALIDATION_REVOKED;
100+
101+
if (revocation_time)
102+
{
103+
*revocation_time = rev_time;
104+
}
105+
if (reason)
106+
{
107+
if (streq(reason_code, "unspecified"))
108+
{
109+
*reason = CRL_REASON_UNSPECIFIED;
110+
}
111+
else if (streq(reason_code, "keyCompromise"))
112+
{
113+
*reason = CRL_REASON_KEY_COMPROMISE;
114+
}
115+
else if (streq(reason_code, "CACompromise"))
116+
{
117+
*reason = CRL_REASON_CA_COMPROMISE;
118+
}
119+
else if (streq(reason_code, "affiliationChanged"))
120+
{
121+
*reason = CRL_REASON_AFFILIATION_CHANGED;
122+
}
123+
else if (streq(reason_code, "superseded"))
124+
{
125+
*reason = CRL_REASON_SUPERSEDED;
126+
}
127+
else if (streq(reason_code, "cessationOfOperation"))
128+
{
129+
*reason = CRL_REASON_CESSATION_OF_OPERATION;
130+
}
131+
else if (streq(reason_code, "certificateHold"))
132+
{
133+
*reason = CRL_REASON_CERTIFICATE_HOLD;
134+
validation = VALIDATION_ON_HOLD;
135+
}
136+
else if (streq(reason_code, "removeFromCRL"))
137+
{
138+
*reason = CRL_REASON_REMOVE_FROM_CRL;
139+
}
140+
else
141+
{
142+
*reason = CRL_REASON_UNSPECIFIED;
143+
}
144+
}
145+
}
146+
}
147+
DESTROY_IF(e);
148+
149+
return validation;
150+
}
151+
152+
METHOD(ocsp_responder_t, destroy, void,
153+
private_openxpki_ocsp_responder_t *this)
154+
{
155+
this->db->destroy(this->db);
156+
free(this);
157+
}
158+
159+
/*
160+
* See header
161+
*/
162+
ocsp_responder_t *openxpki_ocsp_responder_create()
163+
{
164+
private_openxpki_ocsp_responder_t *this;
165+
database_t *db;
166+
char *uri;
167+
168+
uri = lib->settings->get_str(lib->settings,
169+
"%s.plugins.openxpki.database", NULL, lib->ns);
170+
if (!uri)
171+
{
172+
DBG1(DBG_CFG, "openxpki database URI missing");
173+
return NULL;
174+
}
175+
db = lib->db->create(lib->db, uri);
176+
if (!db)
177+
{
178+
DBG1(DBG_CFG, "opening openxpki database failed");
179+
return NULL;
180+
}
181+
INIT(this,
182+
.public = {
183+
.interface = {
184+
.get_status = _get_status,
185+
.destroy = _destroy,
186+
},
187+
},
188+
.db = db,
189+
);
190+
191+
return &this->public.interface;
192+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (C) 2023 Andreas Steffen, strongSec GmbH
3+
*
4+
* Copyright (C) secunet Security Networks AG
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License as published by the
8+
* Free Software Foundation; either version 2 of the License, or (at your
9+
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10+
*
11+
* This program is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* for more details.
15+
*/
16+
17+
/**
18+
* @defgroup openxpki_ocsp_responder openxpki_ocsp_responder
19+
* @{ @ingroup openxpki_p
20+
*/
21+
22+
#ifndef OPENXPKI_OCSP_RESPONDER_H_
23+
#define OPENXPKI_OCSP_RESPONDER_H_
24+
25+
typedef struct openxpki_ocsp_responder_t openxpki_ocsp_responder_t;
26+
27+
#include <credentials/certificates/ocsp_responder.h>
28+
29+
/**
30+
* OCSP responder implementation using OpenXPKI.
31+
*/
32+
struct openxpki_ocsp_responder_t {
33+
34+
/**
35+
* Implements ocsp_responder interface
36+
*/
37+
ocsp_responder_t interface;
38+
};
39+
40+
/**
41+
* Create a openxpki_ocsp_responder instance.
42+
*/
43+
ocsp_responder_t *openxpki_ocsp_responder_create();
44+
45+
#endif /** OPENXPKI_OCSP_RESPONDER_H_ @}*/

0 commit comments

Comments
 (0)