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.
This commit is contained in:
committed by
Tobias Brunner
parent
24d45de633
commit
199c7083e1
@@ -79,6 +79,7 @@ plugins = \
|
||||
plugins/lookip.opt \
|
||||
plugins/ntru.opt \
|
||||
plugins/openssl.opt \
|
||||
plugins/openxpki.opt \
|
||||
plugins/osx-attr.opt \
|
||||
plugins/p-cscf.opt \
|
||||
plugins/pkcs11.opt \
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
charon.plugins.openxpki.database =
|
||||
Database URI connecting to the OpenXPKI **certificate** database. If it
|
||||
contains a password, make sure to adjust the permissions of the config
|
||||
file accordingly.
|
||||
+6
-2
@@ -178,6 +178,7 @@ ARG_DISBL_SET([pkcs12], [disable PKCS12 container support plugin.])
|
||||
ARG_DISBL_SET([pubkey], [disable RAW public key support plugin.])
|
||||
ARG_DISBL_SET([sshkey], [disable SSH key decoding plugin.])
|
||||
ARG_DISBL_SET([x509], [disable X509 certificate implementation plugin.])
|
||||
ARG_ENABL_SET([openxpki], [enable OCSP responder accessing OpenXPKI certificate database.])
|
||||
# fetcher/resolver plugins
|
||||
ARG_ENABL_SET([curl], [enable CURL fetcher plugin to fetch files via libcurl. Requires libcurl.])
|
||||
ARG_ENABL_SET([files], [enable simple file:// URI fetcher.])
|
||||
@@ -1592,8 +1593,9 @@ ADD_PLUGIN([curl], [s charon pki scripts nm cmd])
|
||||
ADD_PLUGIN([files], [s charon pki scripts nm cmd])
|
||||
ADD_PLUGIN([winhttp], [s charon pki scripts])
|
||||
ADD_PLUGIN([soup], [s charon pki scripts nm cmd])
|
||||
ADD_PLUGIN([mysql], [s charon pool manager medsrv attest])
|
||||
ADD_PLUGIN([sqlite], [s charon pool manager medsrv attest])
|
||||
ADD_PLUGIN([mysql], [s charon pki pool manager medsrv attest])
|
||||
ADD_PLUGIN([sqlite], [s charon pki pool manager medsrv attest])
|
||||
ADD_PLUGIN([openxpki], [s pki])
|
||||
ADD_PLUGIN([attr], [c charon])
|
||||
ADD_PLUGIN([attr-sql], [c charon])
|
||||
ADD_PLUGIN([load-tester], [c charon])
|
||||
@@ -1728,6 +1730,7 @@ AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue)
|
||||
AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue)
|
||||
AM_CONDITIONAL(USE_PKCS8, test x$pkcs8 = xtrue)
|
||||
AM_CONDITIONAL(USE_PKCS12, test x$pkcs12 = xtrue)
|
||||
AM_CONDITIONAL(USE_OPENXPKI, test x$openxpki = xtrue)
|
||||
AM_CONDITIONAL(USE_PGP, test x$pgp = xtrue)
|
||||
AM_CONDITIONAL(USE_DNSKEY, test x$dnskey = xtrue)
|
||||
AM_CONDITIONAL(USE_SSHKEY, test x$sshkey = xtrue)
|
||||
@@ -2010,6 +2013,7 @@ AC_CONFIG_FILES([
|
||||
src/libstrongswan/plugins/pkcs7/Makefile
|
||||
src/libstrongswan/plugins/pkcs8/Makefile
|
||||
src/libstrongswan/plugins/pkcs12/Makefile
|
||||
src/libstrongswan/plugins/openxpki/Makefile
|
||||
src/libstrongswan/plugins/pgp/Makefile
|
||||
src/libstrongswan/plugins/dnskey/Makefile
|
||||
src/libstrongswan/plugins/sshkey/Makefile
|
||||
|
||||
@@ -92,6 +92,7 @@ credentials/certificates/certificate.h credentials/certificates/x509.h \
|
||||
credentials/certificates/ac.h credentials/certificates/crl.h \
|
||||
credentials/certificates/pkcs10.h credentials/certificates/ocsp_request.h \
|
||||
credentials/certificates/ocsp_response.h \
|
||||
credentials/certificates/ocsp_responder.h \
|
||||
credentials/certificates/pgp_certificate.h \
|
||||
credentials/certificates/certificate_printer.h \
|
||||
credentials/containers/container.h credentials/containers/pkcs7.h \
|
||||
@@ -479,6 +480,13 @@ if MONOLITHIC
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_OPENXPKI
|
||||
SUBDIRS += plugins/openxpki
|
||||
if MONOLITHIC
|
||||
libstrongswan_la_LIBADD += plugins/openxpki/libstrongswan-openxpki.la
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_PGP
|
||||
SUBDIRS += plugins/pgp
|
||||
if MONOLITHIC
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ocsp_responder ocsp_responder
|
||||
* @{ @ingroup certificates
|
||||
*/
|
||||
|
||||
#ifndef OCSP_RESPONDER_H_
|
||||
#define OCSP_RESPONDER_H_
|
||||
|
||||
#include <credentials/certificates/crl.h>
|
||||
|
||||
typedef struct ocsp_responder_t ocsp_responder_t;
|
||||
|
||||
/**
|
||||
* OCSP responder object.
|
||||
*/
|
||||
struct ocsp_responder_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_responder_t *this,
|
||||
certificate_t *cacert,
|
||||
chunk_t serial_number,
|
||||
time_t *revocation_time,
|
||||
crl_reason_t *revocation_reason);
|
||||
|
||||
/**
|
||||
* Destroy an ocsp_responder_t object.
|
||||
*/
|
||||
void (*destroy)(ocsp_responder_t *this);
|
||||
|
||||
};
|
||||
|
||||
#endif /** OCSP_RESPONDER_H_ @}*/
|
||||
@@ -0,0 +1,17 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(PLUGIN_CFLAGS)
|
||||
|
||||
if MONOLITHIC
|
||||
noinst_LTLIBRARIES = libstrongswan-openxpki.la
|
||||
else
|
||||
plugin_LTLIBRARIES = libstrongswan-openxpki.la
|
||||
endif
|
||||
|
||||
libstrongswan_openxpki_la_SOURCES = \
|
||||
openxpki_plugin.h openxpki_plugin.c \
|
||||
openxpki_ocsp_responder.h openxpki_ocsp_responder.c
|
||||
|
||||
libstrongswan_openxpki_la_LDFLAGS = -module -avoid-version
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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 <library.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include "openxpki_ocsp_responder.h"
|
||||
|
||||
typedef struct private_openxpki_ocsp_responder_t private_openxpki_ocsp_responder_t;
|
||||
|
||||
/**
|
||||
* Private Data of a openxpki_ocsp_responder_t object.
|
||||
*/
|
||||
struct private_openxpki_ocsp_responder_t {
|
||||
|
||||
/**
|
||||
* Public data
|
||||
*/
|
||||
openxpki_ocsp_responder_t public;
|
||||
|
||||
/**
|
||||
* OpenXPKI certificate database
|
||||
*/
|
||||
database_t *db;
|
||||
};
|
||||
|
||||
METHOD(ocsp_responder_t, get_status, cert_validation_t,
|
||||
private_openxpki_ocsp_responder_t *this, certificate_t *cacert,
|
||||
chunk_t serial_number, time_t *revocation_time, crl_reason_t *reason)
|
||||
{
|
||||
cert_validation_t validation = VALIDATION_FAILED;
|
||||
int rev_time;
|
||||
const int max_decimals = 49;
|
||||
const int max_bytes = max_decimals / 2.4083;
|
||||
char serial[max_decimals + 1], authKeyId[60];
|
||||
char *status, *reason_code;
|
||||
chunk_t subjectKeyId;
|
||||
public_key_t *public;
|
||||
enumerator_t *e;
|
||||
bool success;
|
||||
|
||||
/* convert serialNumber from binary to decimal as required for the DB query.
|
||||
* check for a potential overflow since the database table field supports
|
||||
* up to 49 decimal digits, only.
|
||||
*/
|
||||
if (serial_number.len > max_bytes)
|
||||
{
|
||||
DBG1(DBG_LIB, "serialNumber conversion exceeds %d decimals", max_decimals);
|
||||
return VALIDATION_FAILED;
|
||||
|
||||
}
|
||||
chunk_to_dec(serial_number, serial);
|
||||
|
||||
/* additionally use the subjectyKeyId of the issuing CA for the DB query */
|
||||
public = cacert->get_public_key(cacert);
|
||||
success = public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &subjectKeyId);
|
||||
public->destroy(public);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
DBG1(DBG_LIB, "failed to extract subjectKeyId from CA certificate");
|
||||
return VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
/* the authKeyId of the certificate is the subjectKeyId of the issuing CA */
|
||||
snprintf(authKeyId, sizeof(authKeyId), "%#B", &subjectKeyId);
|
||||
|
||||
/* query the OpenXPKI certificate database */
|
||||
e = this->db->query(this->db, "SELECT status, reason_code, revocation_time "
|
||||
"FROM certificate WHERE cert_key = ? "
|
||||
"AND authority_key_identifier = ?", DB_TEXT, serial,
|
||||
DB_TEXT, authKeyId, DB_TEXT, DB_TEXT, DB_INT);
|
||||
if (e && e->enumerate(e, &status, &reason_code, &rev_time))
|
||||
{
|
||||
if (streq(status, "ISSUED") || streq(status, "ISSUANCE_PENDING"))
|
||||
{
|
||||
validation = VALIDATION_GOOD;
|
||||
}
|
||||
else if (streq(status, "UNKNOWN"))
|
||||
{
|
||||
validation = VALIDATION_FAILED;
|
||||
}
|
||||
else if (streq(status, "REVOKED") || streq(status, "HOLD") ||
|
||||
streq(status, "CRL_ISSUANCE_PENDING"))
|
||||
{
|
||||
validation = VALIDATION_REVOKED;
|
||||
|
||||
if (revocation_time)
|
||||
{
|
||||
*revocation_time = rev_time;
|
||||
}
|
||||
if (reason)
|
||||
{
|
||||
if (streq(reason_code, "unspecified"))
|
||||
{
|
||||
*reason = CRL_REASON_UNSPECIFIED;
|
||||
}
|
||||
else if (streq(reason_code, "keyCompromise"))
|
||||
{
|
||||
*reason = CRL_REASON_KEY_COMPROMISE;
|
||||
}
|
||||
else if (streq(reason_code, "CACompromise"))
|
||||
{
|
||||
*reason = CRL_REASON_CA_COMPROMISE;
|
||||
}
|
||||
else if (streq(reason_code, "affiliationChanged"))
|
||||
{
|
||||
*reason = CRL_REASON_AFFILIATION_CHANGED;
|
||||
}
|
||||
else if (streq(reason_code, "superseded"))
|
||||
{
|
||||
*reason = CRL_REASON_SUPERSEDED;
|
||||
}
|
||||
else if (streq(reason_code, "cessationOfOperation"))
|
||||
{
|
||||
*reason = CRL_REASON_CESSATION_OF_OPERATION;
|
||||
}
|
||||
else if (streq(reason_code, "certificateHold"))
|
||||
{
|
||||
*reason = CRL_REASON_CERTIFICATE_HOLD;
|
||||
validation = VALIDATION_ON_HOLD;
|
||||
}
|
||||
else if (streq(reason_code, "removeFromCRL"))
|
||||
{
|
||||
*reason = CRL_REASON_REMOVE_FROM_CRL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*reason = CRL_REASON_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DESTROY_IF(e);
|
||||
|
||||
return validation;
|
||||
}
|
||||
|
||||
METHOD(ocsp_responder_t, destroy, void,
|
||||
private_openxpki_ocsp_responder_t *this)
|
||||
{
|
||||
this->db->destroy(this->db);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* See header
|
||||
*/
|
||||
ocsp_responder_t *openxpki_ocsp_responder_create()
|
||||
{
|
||||
private_openxpki_ocsp_responder_t *this;
|
||||
database_t *db;
|
||||
char *uri;
|
||||
|
||||
uri = lib->settings->get_str(lib->settings,
|
||||
"%s.plugins.openxpki.database", NULL, lib->ns);
|
||||
if (!uri)
|
||||
{
|
||||
DBG1(DBG_CFG, "openxpki database URI missing");
|
||||
return NULL;
|
||||
}
|
||||
db = lib->db->create(lib->db, uri);
|
||||
if (!db)
|
||||
{
|
||||
DBG1(DBG_CFG, "opening openxpki database failed");
|
||||
return NULL;
|
||||
}
|
||||
INIT(this,
|
||||
.public = {
|
||||
.interface = {
|
||||
.get_status = _get_status,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.db = db,
|
||||
);
|
||||
|
||||
return &this->public.interface;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup openxpki_ocsp_responder openxpki_ocsp_responder
|
||||
* @{ @ingroup openxpki_p
|
||||
*/
|
||||
|
||||
#ifndef OPENXPKI_OCSP_RESPONDER_H_
|
||||
#define OPENXPKI_OCSP_RESPONDER_H_
|
||||
|
||||
typedef struct openxpki_ocsp_responder_t openxpki_ocsp_responder_t;
|
||||
|
||||
#include <credentials/certificates/ocsp_responder.h>
|
||||
|
||||
/**
|
||||
* OCSP responder implementation using OpenXPKI.
|
||||
*/
|
||||
struct openxpki_ocsp_responder_t {
|
||||
|
||||
/**
|
||||
* Implements ocsp_responder interface
|
||||
*/
|
||||
ocsp_responder_t interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a openxpki_ocsp_responder instance.
|
||||
*/
|
||||
ocsp_responder_t *openxpki_ocsp_responder_create();
|
||||
|
||||
#endif /** OPENXPKI_OCSP_RESPONDER_H_ @}*/
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 "openxpki_plugin.h"
|
||||
|
||||
#include "openxpki_ocsp_responder.h"
|
||||
|
||||
typedef struct private_openxpki_plugin_t private_openxpki_plugin_t;
|
||||
|
||||
/**
|
||||
* Private data of an openxpki_plugin_t object.
|
||||
*/
|
||||
struct private_openxpki_plugin_t {
|
||||
|
||||
/**
|
||||
* Public interface.
|
||||
*/
|
||||
openxpki_plugin_t public;
|
||||
|
||||
/**
|
||||
* OCSP responder
|
||||
*/
|
||||
ocsp_responder_t *ocsp_responder;
|
||||
};
|
||||
|
||||
METHOD(plugin_t, get_name, char*,
|
||||
private_openxpki_plugin_t *this)
|
||||
{
|
||||
return "openxpki";
|
||||
}
|
||||
|
||||
static bool plugin_cb(private_openxpki_plugin_t *this,
|
||||
plugin_feature_t *feature, bool reg, void *cb_data)
|
||||
{
|
||||
if (reg)
|
||||
{
|
||||
/* Is there already a registered OCSP responder? */
|
||||
if (!lib->get(lib, "ocsp-responder"))
|
||||
{
|
||||
this->ocsp_responder = openxpki_ocsp_responder_create();
|
||||
lib->set(lib, "ocsp-responder", this->ocsp_responder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->ocsp_responder)
|
||||
{
|
||||
lib->set(lib, "ocsp-responder", NULL);
|
||||
this->ocsp_responder->destroy(this->ocsp_responder);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(plugin_t, get_features, int,
|
||||
private_openxpki_plugin_t *this, plugin_feature_t *features[])
|
||||
{
|
||||
static plugin_feature_t f[] = {
|
||||
PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
|
||||
PLUGIN_PROVIDE(CUSTOM, "ocsp-responder"),
|
||||
PLUGIN_DEPENDS(DATABASE, DB_MYSQL),
|
||||
};
|
||||
*features = f;
|
||||
return countof(f);
|
||||
}
|
||||
|
||||
METHOD(plugin_t, destroy, void,
|
||||
private_openxpki_plugin_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *openxpki_plugin_create()
|
||||
{
|
||||
private_openxpki_plugin_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.plugin = {
|
||||
.get_name = _get_name,
|
||||
.get_features = _get_features,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup openxpki_p openxpki
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup openxpki_plugin openxpki_plugin
|
||||
* @{ @ingroup openxpki_p
|
||||
*/
|
||||
|
||||
#ifndef OPENXPKI_PLUGIN_H_
|
||||
#define OPENXPKI_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct openxpki_plugin_t openxpki_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing an OCSP responder based on OpenXPKI.
|
||||
*/
|
||||
struct openxpki_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
#endif /** OPENXPKI_PLUGIN_H_ @}*/
|
||||
Reference in New Issue
Block a user