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_ @}*/