From 5ac0e6687973e03d891141d4a9682db6a8cb80a0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 16:59:55 +0100 Subject: [PATCH] acert: Implement a plugin finding, validating and evaluating attribute certs This validator checks for any attribute certificate it can find for validated end entity certificates and tries to extract group membership information used for connection authorization rules. --- configure.ac | 4 + src/libstrongswan/Makefile.am | 7 + src/libstrongswan/plugins/acert/Makefile.am | 17 ++ .../plugins/acert/acert_plugin.c | 99 ++++++++++++ .../plugins/acert/acert_plugin.h | 42 +++++ .../plugins/acert/acert_validator.c | 149 ++++++++++++++++++ .../plugins/acert/acert_validator.h | 49 ++++++ 7 files changed, 367 insertions(+) create mode 100644 src/libstrongswan/plugins/acert/Makefile.am create mode 100644 src/libstrongswan/plugins/acert/acert_plugin.c create mode 100644 src/libstrongswan/plugins/acert/acert_plugin.h create mode 100644 src/libstrongswan/plugins/acert/acert_validator.c create mode 100644 src/libstrongswan/plugins/acert/acert_validator.h diff --git a/configure.ac b/configure.ac index 3b37ac967..bdcf397dd 100644 --- a/configure.ac +++ b/configure.ac @@ -165,6 +165,7 @@ ARG_ENABL_SET([mysql], [enable MySQL database support. Requires libmysq ARG_ENABL_SET([sqlite], [enable SQLite database support. Requires libsqlite3.]) # authentication/credential plugins ARG_ENABL_SET([addrblock], [enables RFC 3779 address block constraint support.]) +ARG_ENABL_SET([acert], [enable X509 attribute certificate checking plugin.]) ARG_ENABL_SET([agent], [enables the ssh-agent signing plugin.]) ARG_DISBL_SET([constraints], [disable advanced X509 constraint checking plugin.]) ARG_ENABL_SET([coupling], [enable IKEv2 plugin to couple peer certificates permanently to authentication.]) @@ -1090,6 +1091,7 @@ ADD_PLUGIN([nonce], [s charon nm cmd]) ADD_PLUGIN([x509], [s charon openac scepclient pki scripts attest nm cmd]) ADD_PLUGIN([revocation], [s charon nm cmd]) ADD_PLUGIN([constraints], [s charon nm cmd]) +ADD_PLUGIN([acert], [s charon]) ADD_PLUGIN([pubkey], [s charon cmd]) ADD_PLUGIN([pkcs1], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([pkcs7], [s charon scepclient pki scripts nm cmd]) @@ -1229,6 +1231,7 @@ AM_CONDITIONAL(USE_NONCE, test x$nonce = xtrue) AM_CONDITIONAL(USE_X509, test x$x509 = xtrue) AM_CONDITIONAL(USE_REVOCATION, test x$revocation = xtrue) AM_CONDITIONAL(USE_CONSTRAINTS, test x$constraints = xtrue) +AM_CONDITIONAL(USE_ACERT, test x$acert = xtrue) AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue) AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue) AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue) @@ -1454,6 +1457,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/x509/Makefile src/libstrongswan/plugins/revocation/Makefile src/libstrongswan/plugins/constraints/Makefile + src/libstrongswan/plugins/acert/Makefile src/libstrongswan/plugins/pubkey/Makefile src/libstrongswan/plugins/pkcs1/Makefile src/libstrongswan/plugins/pkcs7/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 50cac493d..3462d2ffc 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -307,6 +307,13 @@ if MONOLITHIC endif endif +if USE_ACERT + SUBDIRS += plugins/acert +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/acert/libstrongswan-acert.la +endif +endif + if USE_PUBKEY SUBDIRS += plugins/pubkey if MONOLITHIC diff --git a/src/libstrongswan/plugins/acert/Makefile.am b/src/libstrongswan/plugins/acert/Makefile.am new file mode 100644 index 000000000..ba16f413a --- /dev/null +++ b/src/libstrongswan/plugins/acert/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = \ + -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-acert.la +else +plugin_LTLIBRARIES = libstrongswan-acert.la +endif + +libstrongswan_acert_la_SOURCES = \ + acert_validator.h acert_validator.c \ + acert_plugin.h acert_plugin.c + +libstrongswan_acert_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/acert/acert_plugin.c b/src/libstrongswan/plugins/acert/acert_plugin.c new file mode 100644 index 000000000..01d9ae3b8 --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_plugin.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec 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 . + * + * 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 "acert_plugin.h" +#include "acert_validator.h" + +#include + +typedef struct private_acert_plugin_t private_acert_plugin_t; + +/** + * private data of acert_plugin + */ +struct private_acert_plugin_t { + + /** + * public functions + */ + acert_plugin_t public; + + /** + * Validator implementation instance. + */ + acert_validator_t *validator; +}; + +METHOD(plugin_t, get_name, char*, + private_acert_plugin_t *this) +{ + return "acert"; +} + +/** + * Register validator + */ +static bool plugin_cb(private_acert_plugin_t *this, + plugin_feature_t *feature, bool reg, void *cb_data) +{ + if (reg) + { + lib->credmgr->add_validator(lib->credmgr, &this->validator->validator); + } + else + { + lib->credmgr->remove_validator(lib->credmgr, &this->validator->validator); + } + return TRUE; +} + +METHOD(plugin_t, get_features, int, + private_acert_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL), + PLUGIN_PROVIDE(CUSTOM, "acert"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_acert_plugin_t *this) +{ + this->validator->destroy(this->validator); + free(this); +} + +/* + * see header file + */ +plugin_t *acert_plugin_create() +{ + private_acert_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + .validator = acert_validator_create(), + ); + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/acert/acert_plugin.h b/src/libstrongswan/plugins/acert/acert_plugin.h new file mode 100644 index 000000000..97d12936d --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec 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 . + * + * 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 acert acert + * @ingroup plugins + * + * @defgroup acert_plugin acert_plugin + * @{ @ingroup acert + */ + +#ifndef ACERT_PLUGIN_H_ +#define ACERT_PLUGIN_H_ + +#include + +typedef struct acert_plugin_t acert_plugin_t; + +/** + * X.509 attribute certificate group membership checking. + */ +struct acert_plugin_t { + + /** + * Implements plugin_t. interface. + */ + plugin_t plugin; +}; + +#endif /** ACERT_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/acert/acert_validator.c b/src/libstrongswan/plugins/acert/acert_validator.c new file mode 100644 index 000000000..ab15dba98 --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_validator.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec 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 . + * + * 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. + */ + +#define _GNU_SOURCE +#include + +#include "acert_validator.h" + +#include +#include + +typedef struct private_acert_validator_t private_acert_validator_t; + +/** + * Private data of an acert_validator_t object. + */ +struct private_acert_validator_t { + + /** + * Public acert_validator_t interface. + */ + acert_validator_t public; +}; + +/** + * Check if an AC can be trusted + */ +static bool verify(private_acert_validator_t *this, certificate_t *ac) +{ + certificate_t *issuer; + enumerator_t *enumerator; + bool verified = FALSE; + + if (!ac->get_validity(ac, NULL, NULL, NULL)) + { + return FALSE; + } + DBG1(DBG_CFG, "verifying attribute certificate issued by \"%Y\"", + ac->get_issuer(ac)); + enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr, KEY_ANY, + ac->get_issuer(ac), TRUE); + while (enumerator->enumerate(enumerator, &issuer, NULL)) + { + if (issuer->get_validity(issuer, NULL, NULL, NULL)) + { + if (lib->credmgr->issued_by(lib->credmgr, ac, issuer, NULL)) + { + verified = TRUE; + break; + } + } + } + enumerator->destroy(enumerator); + + return verified; +} + +/** + * Apply AC group membership to auth config + */ +static void apply(private_acert_validator_t *this, ac_t *ac, auth_cfg_t *auth) +{ + enumerator_t *enumerator; + ac_group_type_t type; + chunk_t chunk; + + enumerator = ac->create_group_enumerator(ac); + while (enumerator->enumerate(enumerator, &type, &chunk)) + { + if (type == AC_GROUP_TYPE_STRING) + { + auth->add(auth, AUTH_RULE_GROUP, + identification_create_from_data(chunk)); + } + } + enumerator->destroy(enumerator); +} + +METHOD(cert_validator_t, validate, bool, + private_acert_validator_t *this, certificate_t *subject, + certificate_t *issuer, bool online, u_int pathlen, bool anchor, + auth_cfg_t *auth) +{ + /* for X.509 end entity certs only */ + if (pathlen == 0 && subject->get_type(subject) == CERT_X509) + { + x509_t *x509 = (x509_t*)subject; + enumerator_t *enumerator; + identification_t *id, *serial; + ac_t *ac; + + /* find attribute certificates by serial and issuer. A lookup by + * the holder DN would work as well, but RFC 5755 recommends the use + * of baseCertificateID. */ + serial = identification_create_from_encoding(ID_KEY_ID, + x509->get_serial(x509)); + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_X509_AC, KEY_ANY, serial, FALSE); + while (enumerator->enumerate(enumerator, &ac)) + { + id = ac->get_holderIssuer(ac); + if (id && id->equals(id, subject->get_issuer(subject))) + { + if (verify(this, &ac->certificate)) + { + apply(this, ac, auth); + } + } + } + enumerator->destroy(enumerator); + serial->destroy(serial); + } + return TRUE; +} + +METHOD(acert_validator_t, destroy, void, + private_acert_validator_t *this) +{ + free(this); +} + +/** + * See header + */ +acert_validator_t *acert_validator_create() +{ + private_acert_validator_t *this; + + INIT(this, + .public = { + .validator.validate = _validate, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/libstrongswan/plugins/acert/acert_validator.h b/src/libstrongswan/plugins/acert/acert_validator.h new file mode 100644 index 000000000..507776f18 --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_validator.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec 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 . + * + * 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 acert_validator acert_validator + * @{ @ingroup acert + */ + +#ifndef ACERT_VALIDATOR_H_ +#define ACERT_VALIDATOR_H_ + +#include + +typedef struct acert_validator_t acert_validator_t; + +/** + * Attribute certificate group membership checking + */ +struct acert_validator_t { + + /** + * Implements cert_validator_t interface. + */ + cert_validator_t validator; + + /** + * Destroy a acert_validator_t. + */ + void (*destroy)(acert_validator_t *this); +}; + +/** + * Create a acert_validator instance. + */ +acert_validator_t *acert_validator_create(); + +#endif /** ACERT_VALIDATOR_H_ @}*/