Merge branch 'acerts'

(Re-)Introduces X.509 Attribute Certificate support in IKE, and cleans up the
x509 AC parser/generator. ACs may be stored locally or exchanged in IKEv2
CERT payloads, Attribute Authorities must be installed locally. pki --acert
issues Attribute Certificates and replaces the removed openac utility.
This commit is contained in:
Martin Willi 2014-03-31 12:11:04 +02:00
commit 1766ede330
96 changed files with 2394 additions and 1587 deletions

13
NEWS
View File

@ -1,3 +1,16 @@
strongswan-5.1.3
----------------
- The acert plugin evaluates X.509 Attribute Certificates. Group membership
information encoded as strings can be used to fulfill authorization checks
defined with the rightgroups option. Attribute Certificates can be loaded
locally or get exchanged in IKEv2 certificate payloads.
- The pki command gained support to generate X.509 Attribute Certificates
using the --acert subcommand, while the --print command supports the ac type.
The openac utility has been removed in favor of the new pki functionality.
strongswan-5.1.2
----------------

View File

@ -1,6 +1,3 @@
openac.load =
Plugins to load in ipsec openac tool.
pki.load =
Plugins to load in ipsec pki tool.

View File

@ -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.])
@ -264,7 +265,7 @@ ARG_ENABL_SET([medsrv], [enable mediation server web frontend and daemon
ARG_ENABL_SET([nm], [enable NetworkManager backend.])
ARG_DISBL_SET([scripts], [disable additional utilities (found in directory scripts).])
ARG_ENABL_SET([tkm], [enable Trusted Key Manager support.])
ARG_DISBL_SET([tools], [disable additional utilities (openac, scepclient and pki).])
ARG_DISBL_SET([tools], [disable additional utilities (scepclient and pki).])
# optional features
ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
ARG_DISBL_SET([ikev1], [disable IKEv1 protocol support in charon.])
@ -1052,7 +1053,6 @@ charon_plugins=
starter_plugins=
pool_plugins=
attest_plugins=
openac_plugins=
scepclient_plugins=
pki_plugins=
scripts_plugins=
@ -1068,7 +1068,7 @@ h_plugins=
s_plugins=
t_plugins=
ADD_PLUGIN([test-vectors], [s charon openac scepclient pki])
ADD_PLUGIN([test-vectors], [s charon scepclient pki])
ADD_PLUGIN([curl], [s charon scepclient scripts nm cmd])
ADD_PLUGIN([soup], [s charon scripts nm cmd])
ADD_PLUGIN([unbound], [s charon scripts])
@ -1076,37 +1076,38 @@ ADD_PLUGIN([ldap], [s charon scepclient scripts nm cmd])
ADD_PLUGIN([mysql], [s charon pool manager medsrv attest])
ADD_PLUGIN([sqlite], [s charon pool manager medsrv attest])
ADD_PLUGIN([pkcs11], [s charon pki nm cmd])
ADD_PLUGIN([aes], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([des], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([blowfish], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([rc2], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([sha1], [s charon openac scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([sha2], [s charon openac scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([md4], [s charon openac manager scepclient pki nm cmd])
ADD_PLUGIN([md5], [s charon openac scepclient pki scripts attest nm cmd])
ADD_PLUGIN([rdrand], [s charon openac scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([random], [s charon openac scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([aes], [s charon scepclient pki scripts nm cmd])
ADD_PLUGIN([des], [s charon scepclient pki scripts nm cmd])
ADD_PLUGIN([blowfish], [s charon scepclient pki scripts nm cmd])
ADD_PLUGIN([rc2], [s charon scepclient pki scripts nm cmd])
ADD_PLUGIN([sha1], [s charon scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([sha2], [s charon scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([md4], [s charon manager scepclient pki nm cmd])
ADD_PLUGIN([md5], [s charon scepclient pki scripts attest nm cmd])
ADD_PLUGIN([rdrand], [s charon scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([random], [s charon scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([nonce], [s charon nm cmd])
ADD_PLUGIN([x509], [s charon openac scepclient pki scripts attest nm cmd])
ADD_PLUGIN([x509], [s charon 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([pkcs1], [s charon scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([pkcs7], [s charon scepclient pki scripts nm cmd])
ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([pkcs8], [s charon scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts cmd])
ADD_PLUGIN([pgp], [s charon])
ADD_PLUGIN([dnskey], [s charon pki])
ADD_PLUGIN([sshkey], [s charon pki nm cmd])
ADD_PLUGIN([dnscert], [c charon])
ADD_PLUGIN([ipseckey], [c charon])
ADD_PLUGIN([pem], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([pem], [s charon scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([padlock], [s charon])
ADD_PLUGIN([openssl], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([gcrypt], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([af-alg], [s charon openac scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([openssl], [s charon scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([gcrypt], [s charon scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([af-alg], [s charon scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([fips-prf], [s charon nm cmd])
ADD_PLUGIN([gmp], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([gmp], [s charon scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([agent], [s charon nm cmd])
ADD_PLUGIN([keychain], [s charon cmd])
ADD_PLUGIN([xcbc], [s charon nm cmd])
@ -1188,7 +1189,6 @@ AC_SUBST(charon_plugins)
AC_SUBST(starter_plugins)
AC_SUBST(pool_plugins)
AC_SUBST(attest_plugins)
AC_SUBST(openac_plugins)
AC_SUBST(scepclient_plugins)
AC_SUBST(pki_plugins)
AC_SUBST(scripts_plugins)
@ -1229,6 +1229,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 +1455,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
@ -1582,7 +1584,6 @@ AC_CONFIG_FILES([
src/_updown/Makefile
src/_updown_espmark/Makefile
src/_copyright/Makefile
src/openac/Makefile
src/scepclient/Makefile
src/pki/Makefile
src/pki/man/Makefile
@ -1619,6 +1620,7 @@ AC_CONFIG_FILES([
src/pki/man/pki---req.1
src/pki/man/pki---self.1
src/pki/man/pki---signcrl.1
src/pki/man/pki---acert.1
src/pki/man/pki---verify.1
])

View File

@ -1,5 +1,3 @@
usr/lib/strongswan/scepclient usr/lib/strongswan/
usr/lib/strongswan/openac usr/lib/strongswan/
usr/lib/strongswan/pki usr/lib/strongswan/
usr/share/man/man8/scepclient.8 usr/share/man/man8/
usr/share/man/man8/openac.8 usr/share/man/man8/

View File

@ -73,7 +73,7 @@ if USE_UPDOWN
endif
if USE_TOOLS
SUBDIRS += openac scepclient pki
SUBDIRS += scepclient pki
endif
if USE_CONFTEST

View File

@ -100,7 +100,6 @@ if USE_CMD
endif
if USE_TOOLS
exes += $(DESTDIR)$(ipsecdir)/openac
exes += $(DESTDIR)$(ipsecdir)/scepclient
exes += $(DESTDIR)$(bindir)/pki
endif

View File

@ -70,7 +70,6 @@ case "$1" in
echo " rereadcacerts|rereadaacerts|rereadocspcerts"
echo " rereadacerts|rereadcrls|rereadall"
echo " purgeocsp|purgecrls|purgecerts|purgeike"
echo " openac"
echo " scepclient"
echo " secrets"
echo " starter"

View File

@ -224,6 +224,9 @@ METHOD(cert_payload_t, get_cert, certificate_t*,
case ENC_X509_SIGNATURE:
type = CERT_X509;
break;
case ENC_X509_ATTRIBUTE:
type = CERT_X509_AC;
break;
case ENC_CRL:
type = CERT_X509_CRL;
break;
@ -333,6 +336,9 @@ cert_payload_t *cert_payload_create_from_cert(payload_type_t type,
case CERT_X509:
this->encoding = ENC_X509_SIGNATURE;
break;
case CERT_X509_AC:
this->encoding = ENC_X509_ATTRIBUTE;
break;
default:
DBG1(DBG_ENC, "embedding %N certificate in payload failed",
certificate_type_names, cert->get_type(cert));
@ -380,4 +386,3 @@ cert_payload_t *cert_payload_create_custom(payload_type_t type,
return &this->public;
}

View File

@ -31,8 +31,9 @@
#include <credentials/certificates/ac.h>
#include <credentials/certificates/crl.h>
#include <credentials/certificates/pgp_certificate.h>
#include <credentials/ietf_attributes/ietf_attributes.h>
#include <config/peer_cfg.h>
#include <asn1/asn1.h>
#include <asn1/oid.h>
/* warning intervals for list functions */
#define CERT_WARNING_INTERVAL 30 /* days */
@ -1027,16 +1028,19 @@ static void stroke_list_certs(linked_list_t *list, char *label,
static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
{
bool first = TRUE;
time_t thisUpdate, nextUpdate, now = time(NULL);
enumerator_t *enumerator = list->create_enumerator(list);
time_t notBefore, notAfter, now = time(NULL);
enumerator_t *enumerator;
certificate_t *cert;
while (enumerator->enumerate(enumerator, (void**)&cert))
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &cert))
{
ac_t *ac = (ac_t*)cert;
ac_group_type_t type;
identification_t *id;
ietf_attributes_t *groups;
enumerator_t *groups;
chunk_t chunk;
bool firstgroup = TRUE;
if (first)
{
@ -1061,30 +1065,78 @@ static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
{
fprintf(out, " hserial: %#B\n", &chunk);
}
groups = ac->get_groups(ac);
if (groups)
groups = ac->create_group_enumerator(ac);
while (groups->enumerate(groups, &type, &chunk))
{
fprintf(out, " groups: %s\n", groups->get_string(groups));
groups->destroy(groups);
int oid;
char *str;
if (firstgroup)
{
fprintf(out, " groups: ");
firstgroup = FALSE;
}
else
{
fprintf(out, " ");
}
switch (type)
{
case AC_GROUP_TYPE_STRING:
fprintf(out, "%.*s", (int)chunk.len, chunk.ptr);
break;
case AC_GROUP_TYPE_OID:
oid = asn1_known_oid(chunk);
if (oid == OID_UNKNOWN)
{
str = asn1_oid_to_string(chunk);
if (str)
{
fprintf(out, "%s", str);
}
else
{
fprintf(out, "OID:%#B", &chunk);
}
}
else
{
fprintf(out, "%s", oid_names[oid].name);
}
break;
case AC_GROUP_TYPE_OCTETS:
fprintf(out, "%#B", &chunk);
break;
}
fprintf(out, "\n");
}
groups->destroy(groups);
fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
chunk = chunk_skip_zero(ac->get_serial(ac));
fprintf(out, " serial: %#B\n", &chunk);
/* list validity */
cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
fprintf(out, " updates: this %T\n", &thisUpdate, utc);
fprintf(out, " next %T, ", &nextUpdate, utc);
if (now > nextUpdate)
cert->get_validity(cert, &now, &notBefore, &notAfter);
fprintf(out, " validity: not before %T, ", &notBefore, utc);
if (now < notBefore)
{
fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
fprintf(out, "not valid yet (valid in %V)\n", &now, &notBefore);
}
else
{
fprintf(out, "ok\n");
}
fprintf(out, " not after %T, ", &notAfter, utc);
if (now > notAfter)
{
fprintf(out, "expired (%V ago)\n", &now, &notAfter);
}
else
{
fprintf(out, "ok");
if (now > nextUpdate - AC_WARNING_INTERVAL * 60 * 60 * 24)
if (now > notAfter - AC_WARNING_INTERVAL * 60 * 60 * 24)
{
fprintf(out, " (expires in %V)", &now, &nextUpdate);
fprintf(out, " (expires in %V)", &now, &notAfter);
}
fprintf(out, " \n");
}

View File

@ -22,6 +22,7 @@
#include <encoding/payloads/certreq_payload.h>
#include <encoding/payloads/auth_payload.h>
#include <credentials/certificates/x509.h>
#include <credentials/certificates/ac.h>
typedef struct private_ike_cert_post_t private_ike_cert_post_t;
@ -104,6 +105,102 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
return payload;
}
/**
* Add subject certificate to message
*/
static bool add_subject_cert(private_ike_cert_post_t *this, auth_cfg_t *auth,
message_t *message)
{
cert_payload_t *payload;
certificate_t *cert;
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
if (!cert)
{
return FALSE;
}
payload = build_cert_payload(this, cert);
if (!payload)
{
return FALSE;
}
DBG1(DBG_IKE, "sending end entity cert \"%Y\"", cert->get_subject(cert));
message->add_payload(message, (payload_t*)payload);
return TRUE;
}
/**
* Add intermediate CA certificates to message
*/
static void add_im_certs(private_ike_cert_post_t *this, auth_cfg_t *auth,
message_t *message)
{
cert_payload_t *payload;
enumerator_t *enumerator;
certificate_t *cert;
auth_rule_t type;
enumerator = auth->create_enumerator(auth);
while (enumerator->enumerate(enumerator, &type, &cert))
{
if (type == AUTH_RULE_IM_CERT)
{
payload = cert_payload_create_from_cert(CERTIFICATE, cert);
if (payload)
{
DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
cert->get_subject(cert));
message->add_payload(message, (payload_t*)payload);
}
}
}
enumerator->destroy(enumerator);
}
/**
* Add any valid attribute certificates of subject to message
*/
static void add_attribute_certs(private_ike_cert_post_t *this,
auth_cfg_t *auth, message_t *message)
{
certificate_t *subject, *cert;
subject = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
if (subject && subject->get_type(subject) == CERT_X509)
{
x509_t *x509 = (x509_t*)subject;
identification_t *id, *serial;
enumerator_t *enumerator;
cert_payload_t *payload;
ac_t *ac;
/* we look for attribute certs having our serial and holder issuer,
* which is recommended by RFC 5755 */
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))
{
cert = &ac->certificate;
id = ac->get_holderIssuer(ac);
if (id && id->equals(id, subject->get_issuer(subject)) &&
cert->get_validity(cert, NULL, NULL, NULL))
{
payload = cert_payload_create_from_cert(CERTIFICATE, cert);
if (payload)
{
DBG1(DBG_IKE, "sending attribute certificate "
"issued by \"%Y\"", cert->get_issuer(cert));
message->add_payload(message, (payload_t*)payload);
}
}
}
enumerator->destroy(enumerator);
serial->destroy(serial);
}
}
/**
* add certificates to message
*/
@ -111,6 +208,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
{
peer_cfg_t *peer_cfg;
auth_payload_t *payload;
auth_cfg_t *auth;
payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
@ -130,46 +228,13 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
}
/* FALL */
case CERT_ALWAYS_SEND:
{
cert_payload_t *payload;
enumerator_t *enumerator;
certificate_t *cert;
auth_rule_t type;
auth_cfg_t *auth;
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
/* get subject cert first, then issuing certificates */
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
if (!cert)
if (add_subject_cert(this, auth, message))
{
break;
add_im_certs(this, auth, message);
add_attribute_certs(this, auth, message);
}
payload = build_cert_payload(this, cert);
if (!payload)
{
break;
}
DBG1(DBG_IKE, "sending end entity cert \"%Y\"",
cert->get_subject(cert));
message->add_payload(message, (payload_t*)payload);
enumerator = auth->create_enumerator(auth);
while (enumerator->enumerate(enumerator, &type, &cert))
{
if (type == AUTH_RULE_IM_CERT)
{
payload = cert_payload_create_from_cert(CERTIFICATE, cert);
if (payload)
{
DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
cert->get_subject(cert));
message->add_payload(message, (payload_t*)payload);
}
}
}
enumerator->destroy(enumerator);
}
break;
}
}

View File

@ -259,6 +259,30 @@ static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
}
}
/**
* Process an attribute certificate payload
*/
static void process_ac(cert_payload_t *payload, auth_cfg_t *auth)
{
certificate_t *cert;
cert = payload->get_cert(payload);
if (cert)
{
if (cert->get_issuer(cert))
{
DBG1(DBG_IKE, "received attribute certificate issued by \"%Y\"",
cert->get_issuer(cert));
}
else if (cert->get_subject(cert))
{
DBG1(DBG_IKE, "received attribute certificate for \"%Y\"",
cert->get_subject(cert));
}
auth->add(auth, AUTH_HELPER_AC_CERT, cert);
}
}
/**
* Process certificate payloads
*/
@ -298,13 +322,15 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
case ENC_CRL:
process_crl(cert_payload, auth);
break;
case ENC_X509_ATTRIBUTE:
process_ac(cert_payload, auth);
break;
case ENC_PKCS7_WRAPPED_X509:
case ENC_PGP:
case ENC_DNS_SIGNED_KEY:
case ENC_KERBEROS_TOKEN:
case ENC_ARL:
case ENC_SPKI:
case ENC_X509_ATTRIBUTE:
case ENC_RAW_RSA_KEY:
case ENC_X509_HASH_AND_URL_BUNDLE:
case ENC_OCSP_CONTENT:

View File

@ -20,7 +20,7 @@ credentials/keys/public_key.c credentials/keys/shared_key.c \
credentials/certificates/certificate.c credentials/certificates/crl.c \
credentials/certificates/ocsp_response.c \
credentials/containers/container.c credentials/containers/pkcs12.c \
credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \
credentials/credential_manager.c \
credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \
credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \

View File

@ -18,7 +18,7 @@ credentials/keys/public_key.c credentials/keys/shared_key.c \
credentials/certificates/certificate.c credentials/certificates/crl.c \
credentials/certificates/ocsp_response.c \
credentials/containers/container.c credentials/containers/pkcs12.c \
credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \
credentials/credential_manager.c \
credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \
credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \
@ -61,7 +61,6 @@ credentials/certificates/ocsp_response.h \
credentials/certificates/pgp_certificate.h \
credentials/containers/container.h credentials/containers/pkcs7.h \
credentials/containers/pkcs12.h \
credentials/ietf_attributes/ietf_attributes.h \
credentials/credential_manager.h credentials/sets/auth_cfg_wrapper.h \
credentials/sets/ocsp_response_wrapper.h credentials/sets/cert_cache.h \
credentials/sets/mem_cred.h credentials/sets/callback_cred.h \
@ -308,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

View File

@ -31,7 +31,7 @@ ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_XAUTH,
"XAuth",
);
ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_REVOCATION_CERT,
ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_AC_CERT,
"RULE_IDENTITY",
"RULE_IDENTITY_LOOSE",
"RULE_AUTH_CLASS",
@ -56,6 +56,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_REVOCATION_CERT,
"HELPER_IM_HASH_URL",
"HELPER_SUBJECT_HASH_URL",
"HELPER_REVOCATION_CERT",
"HELPER_AC_CERT",
);
/**
@ -91,6 +92,7 @@ static inline bool is_multi_value_rule(auth_rule_t type)
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
return TRUE;
}
return FALSE;
@ -224,6 +226,7 @@ static void init_entry(entry_t *this, auth_rule_t type, va_list args)
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
/* pointer type */
this->value = va_arg(args, void*);
break;
@ -262,6 +265,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2)
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
{
certificate_t *c1, *c2;
@ -319,6 +323,7 @@ static void destroy_entry_value(entry_t *entry)
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
{
certificate_t *cert = (certificate_t*)entry->value;
cert->destroy(cert);
@ -390,6 +395,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator,
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
/* pointer type */
entry->value = va_arg(args, void*);
break;
@ -467,6 +473,7 @@ METHOD(auth_cfg_t, get, void*,
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
case AUTH_RULE_MAX:
break;
}
@ -736,6 +743,7 @@ METHOD(auth_cfg_t, complies, bool,
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
case AUTH_RULE_MAX:
/* skip helpers */
continue;
@ -868,6 +876,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
{
certificate_t *cert = (certificate_t*)value;
@ -1029,6 +1038,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*,
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_REVOCATION_CERT:
case AUTH_HELPER_AC_CERT:
{
certificate_t *cert = (certificate_t*)value;
clone->add(clone, type, cert->get_ref(cert));

View File

@ -117,6 +117,8 @@ enum auth_rule_t {
AUTH_HELPER_SUBJECT_HASH_URL,
/** revocation certificate (CRL, OCSP), certificate_t* */
AUTH_HELPER_REVOCATION_CERT,
/** attribute certificate for authorization decisions, certificate_t */
AUTH_HELPER_AC_CERT,
/** helper to determine the number of elements in this enum */
AUTH_RULE_MAX,

View File

@ -38,7 +38,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_SERIAL",
"BUILD_DIGEST_ALG",
"BUILD_ENCRYPTION_ALG",
"BUILD_IETF_GROUP_ATTR",
"BUILD_AC_GROUP_STRINGS",
"BUILD_CA_CERT",
"BUILD_CERT",
"BUILD_CRL_DISTRIBUTION_POINTS",
@ -72,4 +72,3 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_THRESHOLD",
"BUILD_END",
);

View File

@ -87,8 +87,8 @@ enum builder_part_t {
BUILD_DIGEST_ALG,
/** encryption algorithm to use, encryption_algorithm_t */
BUILD_ENCRYPTION_ALG,
/** a comma-separated list of ietf group attributes, char* */
BUILD_IETF_GROUP_ATTR,
/** list of AC group memberships, linked_list_t* with char* */
BUILD_AC_GROUP_STRINGS,
/** a ca certificate, certificate_t* */
BUILD_CA_CERT,
/** a certificate, certificate_t* */

View File

@ -24,9 +24,18 @@
#include <library.h>
#include <credentials/certificates/certificate.h>
#include <credentials/ietf_attributes/ietf_attributes.h>
typedef struct ac_t ac_t;
typedef enum ac_group_type_t ac_group_type_t;
/**
* Common group types, from IETF Attributes Syntax
*/
enum ac_group_type_t {
AC_GROUP_TYPE_OCTETS,
AC_GROUP_TYPE_STRING,
AC_GROUP_TYPE_OID,
};
/**
* X.509 attribute certificate interface.
@ -70,19 +79,11 @@ struct ac_t {
chunk_t (*get_authKeyIdentifier)(ac_t *this);
/**
* Get the group memberships as a list of IETF attributes
* Create an enumerator of contained Group memberships.
*
* @return object containing a list of IETF attributes
* @return enumerator over (ac_group_type_t, chunk_t)
*/
ietf_attributes_t* (*get_groups)(ac_t *this);
/**
* @brief Checks if two attribute certificates belong to the same holder
*
* @param that other attribute certificate
* @return TRUE if same holder
*/
bool (*equals_holder) (ac_t *this, ac_t *other);
enumerator_t* (*create_group_enumerator)(ac_t *this);
};
#endif /** AC_H_ @}*/

View File

@ -1,534 +0,0 @@
/*
* Copyright (C) 2007-2009 Andreas Steffen
*
* HSR Hochschule fuer Technik Rapperswil
*
* 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 <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <collections/linked_list.h>
#include <utils/lexparser.h>
#include "ietf_attributes.h"
/**
* Private definition of IETF attribute types
*/
typedef enum {
IETF_ATTRIBUTE_OCTETS = 0,
IETF_ATTRIBUTE_OID = 1,
IETF_ATTRIBUTE_STRING = 2
} ietf_attribute_type_t;
typedef struct ietf_attr_t ietf_attr_t;
/**
* Private definition of an IETF attribute
*/
struct ietf_attr_t {
/**
* IETF attribute type
*/
ietf_attribute_type_t type;
/**
* IETF attribute value
*/
chunk_t value;
/**
* Compares two IETF attributes
*
* return -1 if this is earlier in the alphabet than other
* return 0 if this equals other
* return +1 if this is later in the alphabet than other
*
* @param other other object
*/
int (*compare) (ietf_attr_t *this, ietf_attr_t *other);
/**
* Destroys an ietf_attr_t object.
*/
void (*destroy) (ietf_attr_t *this);
};
/**
* Implements ietf_attr_t.compare.
*/
static int ietf_attr_compare(ietf_attr_t *this, ietf_attr_t *other)
{
int cmp_len, len, cmp_value;
/* OID attributes are appended after STRING and OCTETS attributes */
if (this->type != IETF_ATTRIBUTE_OID && other->type == IETF_ATTRIBUTE_OID)
{
return -1;
}
if (this->type == IETF_ATTRIBUTE_OID && other->type != IETF_ATTRIBUTE_OID)
{
return 1;
}
cmp_len = this->value.len - other->value.len;
len = (cmp_len < 0) ? this->value.len : other->value.len;
cmp_value = memcmp(this->value.ptr, other->value.ptr, len);
return (cmp_value == 0) ? cmp_len : cmp_value;
}
/**
* Implements ietf_attr_t.destroy.
*/
static void ietf_attr_destroy(ietf_attr_t *this)
{
free(this->value.ptr);
free(this);
}
/**
* Creates an ietf_attr_t object.
*/
static ietf_attr_t* ietf_attr_create(ietf_attribute_type_t type, chunk_t value)
{
ietf_attr_t *this;
INIT(this,
.compare = ietf_attr_compare,
.destroy = ietf_attr_destroy,
.type = type,
.value = chunk_clone(value),
);
return this;
}
typedef struct private_ietf_attributes_t private_ietf_attributes_t;
/**
* Private data of an ietf_attributes_t object.
*/
struct private_ietf_attributes_t {
/**
* Public interface.
*/
ietf_attributes_t public;
/**
* Printable representation of the IETF attributes
*/
char *string;
/**
* Linked list of IETF attributes.
*/
linked_list_t *list;
/**
* reference count
*/
refcount_t ref;
};
METHOD(ietf_attributes_t, get_string, char*,
private_ietf_attributes_t *this)
{
if (this->string == NULL)
{
char buf[BUF_LEN];
char *pos = buf;
int len = BUF_LEN;
bool first = TRUE;
ietf_attr_t *attr;
enumerator_t *enumerator;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &attr))
{
int written;
if (first)
{
first = FALSE;
}
else
{
written = snprintf(pos, len, ", ");
if (written < 0 || written >= len)
{
break;
}
pos += written;
len -= written;
}
switch (attr->type)
{
case IETF_ATTRIBUTE_OCTETS:
case IETF_ATTRIBUTE_STRING:
written = snprintf(pos, len, "%.*s", (int)attr->value.len,
attr->value.ptr);
break;
case IETF_ATTRIBUTE_OID:
{
int oid = asn1_known_oid(attr->value);
if (oid == OID_UNKNOWN)
{
written = snprintf(pos, len, "0x%#B", &attr->value);
}
else
{
written = snprintf(pos, len, "%s", oid_names[oid].name);
}
break;
}
default:
written = 0;
break;
}
if (written < 0 || written >= len)
{
break;
}
pos += written;
len -= written;
}
enumerator->destroy(enumerator);
if (len < BUF_LEN)
{
this->string = strdup(buf);
}
}
return this->string;
}
METHOD(ietf_attributes_t, get_encoding, chunk_t,
private_ietf_attributes_t *this)
{
chunk_t values;
size_t size = 0;
u_char *pos;
ietf_attr_t *attr;
enumerator_t *enumerator;
/* precalculate the total size of all values */
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &attr))
{
size_t len = attr->value.len;
size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
}
enumerator->destroy(enumerator);
pos = asn1_build_object(&values, ASN1_SEQUENCE, size);
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &attr))
{
chunk_t ietfAttribute;
asn1_t type = ASN1_NULL;
switch (attr->type)
{
case IETF_ATTRIBUTE_OCTETS:
type = ASN1_OCTET_STRING;
break;
case IETF_ATTRIBUTE_STRING:
type = ASN1_UTF8STRING;
break;
case IETF_ATTRIBUTE_OID:
type = ASN1_OID;
break;
}
ietfAttribute = asn1_simple_object(type, attr->value);
/* copy ietfAttribute into values chunk */
memcpy(pos, ietfAttribute.ptr, ietfAttribute.len);
pos += ietfAttribute.len;
free(ietfAttribute.ptr);
}
enumerator->destroy(enumerator);
return asn1_wrap(ASN1_SEQUENCE, "m", values);
}
/**
* Implementation of ietf_attributes_t.equals.
*/
static bool equals(private_ietf_attributes_t *this,
private_ietf_attributes_t *other)
{
bool result = TRUE;
/* lists must have the same number of attributes */
if (other == NULL ||
this->list->get_count(this->list) != other->list->get_count(other->list))
{
return FALSE;
}
/* compare two alphabetically-sorted lists */
{
ietf_attr_t *attr_a, *attr_b;
enumerator_t *enum_a, *enum_b;
enum_a = this->list->create_enumerator(this->list);
enum_b = other->list->create_enumerator(other->list);
while (enum_a->enumerate(enum_a, &attr_a) &&
enum_b->enumerate(enum_b, &attr_b))
{
if (attr_a->compare(attr_a, attr_b) != 0)
{
/* we have a mismatch */
result = FALSE;
break;
}
}
enum_a->destroy(enum_a);
enum_b->destroy(enum_b);
}
return result;
}
/**
* Implementation of ietf_attributes_t.matches.
*/
static bool matches(private_ietf_attributes_t *this,
private_ietf_attributes_t *other)
{
bool result = FALSE;
ietf_attr_t *attr_a, *attr_b;
enumerator_t *enum_a, *enum_b;
/* always match if this->list does not contain any attributes */
if (this->list->get_count(this->list) == 0)
{
return TRUE;
}
/* never match if other->list does not contain any attributes */
if (other == NULL || other->list->get_count(other->list) == 0)
{
return FALSE;
}
/* get first attribute from both lists */
enum_a = this->list->create_enumerator(this->list);
enum_a->enumerate(enum_a, &attr_a);
enum_b = other->list->create_enumerator(other->list);
enum_b->enumerate(enum_b, &attr_b);
/* look for at least one common attribute */
while (TRUE)
{
int cmp = attr_a->compare(attr_a, attr_b);
if (cmp == 0)
{
/* we have a match */
result = TRUE;
break;
}
if (cmp == -1)
{
/* attr_a is earlier in the alphabet, get next attr_a */
if (!enum_a->enumerate(enum_a, &attr_a))
{
/* we have reached the end of enum_a */
break;
}
}
else
{
/* attr_a is later in the alphabet, get next attr_b */
if (!enum_b->enumerate(enum_b, &attr_b))
{
/* we have reached the end of enum_b */
break;
}
}
}
enum_a->destroy(enum_a);
enum_b->destroy(enum_b);
return result;
}
METHOD(ietf_attributes_t, get_ref, ietf_attributes_t*,
private_ietf_attributes_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(ietf_attributes_t, destroy, void,
private_ietf_attributes_t *this)
{
if (ref_put(&this->ref))
{
this->list->destroy_offset(this->list, offsetof(ietf_attr_t, destroy));
free(this->string);
free(this);
}
}
static private_ietf_attributes_t* create_empty(void)
{
private_ietf_attributes_t *this;
INIT(this,
.public = {
.get_string = _get_string,
.get_encoding = _get_encoding,
.equals = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))equals,
.matches = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))matches,
.get_ref = _get_ref,
.destroy = _destroy,
},
.list = linked_list_create(),
.ref = 1,
);
return this;
}
/**
* Adds an ietf_attr_t object to a sorted linked list
*/
static void ietf_attributes_add(private_ietf_attributes_t *this,
ietf_attr_t *attr)
{
ietf_attr_t *current_attr;
enumerator_t *enumerator;
int cmp = -1;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, (void **)&current_attr) &&
(cmp = attr->compare(attr, current_attr)) > 0)
{
continue;
}
if (cmp == 0)
{
attr->destroy(attr);
}
else
{ /* the enumerator either points to the end or to the attribute > attr */
this->list->insert_before(this->list, enumerator, attr);
}
enumerator->destroy(enumerator);
}
/*
* Described in header.
*/
ietf_attributes_t *ietf_attributes_create_from_string(char *string)
{
private_ietf_attributes_t *this = create_empty();
chunk_t line = { string, strlen(string) };
while (eat_whitespace(&line))
{
chunk_t group;
/* extract the next comma-separated group attribute */
if (!extract_token(&group, ',', &line))
{
group = line;
line.len = 0;
}
/* remove any trailing spaces */
while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
{
group.len--;
}
/* add the group attribute to the list */
if (group.len > 0)
{
ietf_attr_t *attr = ietf_attr_create(IETF_ATTRIBUTE_STRING, group);
ietf_attributes_add(this, attr);
}
}
return &(this->public);
}
/**
* ASN.1 definition of ietfAttrSyntax
*/
static const asn1Object_t ietfAttrSyntaxObjects[] =
{
{ 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
ASN1_BODY }, /* 1 */
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
{ 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
{ 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
ASN1_BODY }, /* 4 */
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
{ 2, "oid", ASN1_OID, ASN1_OPT |
ASN1_BODY }, /* 6 */
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
{ 2, "string", ASN1_UTF8STRING, ASN1_OPT |
ASN1_BODY }, /* 8 */
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define IETF_ATTR_OCTETS 4
#define IETF_ATTR_OID 6
#define IETF_ATTR_STRING 8
/*
* Described in header.
*/
ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded)
{
private_ietf_attributes_t *this = create_empty();
asn1_parser_t *parser;
chunk_t object;
int objectID;
parser = asn1_parser_create(ietfAttrSyntaxObjects, encoded);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case IETF_ATTR_OCTETS:
case IETF_ATTR_OID:
case IETF_ATTR_STRING:
{
ietf_attribute_type_t type;
ietf_attr_t *attr;
type = (objectID - IETF_ATTR_OCTETS) / 2;
attr = ietf_attr_create(type, object);
ietf_attributes_add(this, attr);
}
break;
default:
break;
}
}
parser->destroy(parser);
return &(this->public);
}

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2007-2009 Andreas Steffen
*
* HSR Hochschule fuer Technik Rapperswil
*
* 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 ietf_attributes ietf_attributes
* @{ @ingroup credentials
*/
#ifndef IETF_ATTRIBUTES_H_
#define IETF_ATTRIBUTES_H_
typedef struct ietf_attributes_t ietf_attributes_t;
#include <library.h>
/**
*
*/
struct ietf_attributes_t {
/**
* Get the an alphabetically sorted list of printable IETF attributes.
*
* Result points to internal data, do not free.
*
* @return a string containing printable attributes
*/
char* (*get_string) (ietf_attributes_t *this);
/**
* Get the ASN.1 encoding of the IETF attributes.
*
* @return allocated chunk containing the encoded bytes
*/
chunk_t (*get_encoding) (ietf_attributes_t *this);
/**
* Check for equality between two lists.
*
* @param other attribute list to be checked for equality
* @return TRUE if equal
*/
bool (*equals) (ietf_attributes_t *this, ietf_attributes_t *other);
/**
* Check for common attributes between two lists.
*
* @param other attribute list to be matched
* @return TRUE if there is at least a common attribute
*/
bool (*matches) (ietf_attributes_t *this, ietf_attributes_t *other);
/**
* Get a new reference to the IETF attributes.
*
* @return this, with an increased refcount
*/
ietf_attributes_t* (*get_ref)(ietf_attributes_t *this);
/**
* Destroys an ietf_attributes_t object.
*/
void (*destroy) (ietf_attributes_t *this);
};
/**
* @param string input string, which will be converted
* @return ietf_attributes_t
*/
ietf_attributes_t *ietf_attributes_create_from_string(char *string);
/**
* @param encoded ASN.1 encoded bytes, such as from ietf_attributes.get_encoding
* @return ietf_attributes_t
*/
ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded);
#endif /** IETF_ATTRIBUTES_H_ @}*/

View File

@ -133,7 +133,8 @@ static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
}
else if (rule != AUTH_HELPER_SUBJECT_CERT &&
rule != AUTH_HELPER_IM_CERT &&
rule != AUTH_HELPER_REVOCATION_CERT)
rule != AUTH_HELPER_REVOCATION_CERT &&
rule != AUTH_HELPER_AC_CERT)
{ /* handle only HELPER certificates */
continue;
}

View File

@ -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

View File

@ -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 <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 "acert_plugin.h"
#include "acert_validator.h"
#include <library.h>
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;
}

View File

@ -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 <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 acert acert
* @ingroup plugins
*
* @defgroup acert_plugin acert_plugin
* @{ @ingroup acert
*/
#ifndef ACERT_PLUGIN_H_
#define ACERT_PLUGIN_H_
#include <plugins/plugin.h>
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_ @}*/

View File

@ -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 <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.
*/
#define _GNU_SOURCE
#include <library.h>
#include "acert_validator.h"
#include <credentials/certificates/x509.h>
#include <credentials/certificates/ac.h>
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;
}

View File

@ -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 <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 acert_validator acert_validator
* @{ @ingroup acert
*/
#ifndef ACERT_VALIDATOR_H_
#define ACERT_VALIDATOR_H_
#include <credentials/cert_validator.h>
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_ @}*/

View File

@ -106,6 +106,12 @@ bool pem_encoder_encode(cred_encoding_type_t type, chunk_t *encoding,
label = "CERTIFICATE REQUEST";
break;
}
if (cred_encoding_args(args, CRED_PART_X509_AC_ASN1_DER,
&asn1, CRED_PART_END))
{
label = "ATTRIBUTE CERTIFICATE";
break;
}
default:
return FALSE;
}
@ -154,4 +160,3 @@ bool pem_encoder_encode(cred_encoding_type_t type, chunk_t *encoding,
encoding->len = pos - encoding->ptr;
return TRUE;
}

View File

@ -29,7 +29,6 @@
#include <utils/identification.h>
#include <collections/linked_list.h>
#include <credentials/certificates/x509.h>
#include <credentials/ietf_attributes/ietf_attributes.h>
#include <credentials/keys/private_key.h>
extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob,
@ -75,7 +74,7 @@ struct private_x509_ac_t {
/**
* Serial number of the holder certificate
*/
chunk_t holderSerial;
identification_t *holderSerial;
/**
* ID representing the holder
@ -98,14 +97,9 @@ struct private_x509_ac_t {
time_t notAfter;
/**
* List of charging attributes
* List of group attributes, as group_t
*/
ietf_attributes_t *charging;
/**
* List of groub attributes
*/
ietf_attributes_t *groups;
linked_list_t *groups;
/**
* Authority Key Identifier
@ -153,6 +147,25 @@ struct private_x509_ac_t {
refcount_t ref;
};
/**
* Group definition, an IETF attribute
*/
typedef struct {
/** Attribute type */
ac_group_type_t type;
/* attribute value */
chunk_t value;
} group_t;
/**
* Clean up a group entry
*/
static void group_destroy(group_t *group)
{
free(group->value.ptr);
free(group);
}
static chunk_t ASN1_noRevAvail_ext = chunk_from_chars(
0x30, 0x09,
0x06, 0x03,
@ -169,42 +182,41 @@ extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
/**
* parses a directoryName
*/
static bool parse_directoryName(chunk_t blob, int level, bool implicit, identification_t **name)
static bool parse_directoryName(chunk_t blob, int level, bool implicit,
identification_t **name)
{
bool has_directoryName;
linked_list_t *list = linked_list_create();
identification_t *directoryName;
enumerator_t *enumerator;
bool first = TRUE;
linked_list_t *list;
list = linked_list_create();
x509_parse_generalNames(blob, level, implicit, list);
has_directoryName = list->get_count(list) > 0;
if (has_directoryName)
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &directoryName))
{
enumerator_t *enumerator = list->create_enumerator(list);
identification_t *directoryName;
bool first = TRUE;
while (enumerator->enumerate(enumerator, (void**)&directoryName))
if (first)
{
if (first)
{
*name = directoryName;
first = FALSE;
}
else
{
DBG1(DBG_ASN, "more than one directory name - first selected");
directoryName->destroy(directoryName);
}
*name = directoryName;
first = FALSE;
}
else
{
DBG1(DBG_ASN, "more than one directory name - first selected");
directoryName->destroy(directoryName);
break;
}
enumerator->destroy(enumerator);
}
else
enumerator->destroy(enumerator);
list->destroy(list);
if (first)
{
DBG1(DBG_ASN, "no directoryName found");
return FALSE;
}
list->destroy(list);
return has_directoryName;
return TRUE;
}
/**
@ -243,6 +255,74 @@ static void parse_roleSyntax(chunk_t blob, int level0)
parser->destroy(parser);
}
/**
* ASN.1 definition of ietfAttrSyntax
*/
static const asn1Object_t ietfAttrSyntaxObjects[] =
{
{ 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
ASN1_BODY }, /* 1 */
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
{ 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
{ 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
ASN1_BODY }, /* 4 */
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
{ 2, "oid", ASN1_OID, ASN1_OPT |
ASN1_BODY }, /* 6 */
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
{ 2, "string", ASN1_UTF8STRING, ASN1_OPT |
ASN1_BODY }, /* 8 */
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define IETF_ATTR_OCTETS 4
#define IETF_ATTR_OID 6
#define IETF_ATTR_STRING 8
/**
* Parse group memberships, IETF attributes
*/
static bool parse_groups(private_x509_ac_t *this, chunk_t encoded, int level0)
{
ac_group_type_t type;
group_t *group;
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success;
parser = asn1_parser_create(ietfAttrSyntaxObjects, encoded);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case IETF_ATTR_OCTETS:
type = AC_GROUP_TYPE_OCTETS;
break;
case IETF_ATTR_OID:
type = AC_GROUP_TYPE_OID;
break;
case IETF_ATTR_STRING:
type = AC_GROUP_TYPE_STRING;
break;
default:
continue;
}
INIT(group,
.type = type,
.value = chunk_clone(object),
);
this->groups->insert_last(this->groups, group);
}
success = parser->success(parser);
parser->destroy(parser);
return success;
}
/**
* ASN.1 definition of an X509 attribute certificate
*/
@ -250,57 +330,57 @@ static const asn1Object_t acObjects[] =
{
{ 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "version", ASN1_INTEGER, ASN1_DEF |
{ 2, "version", ASN1_INTEGER, ASN1_DEF |
ASN1_BODY }, /* 2 */
{ 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
{ 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
{ 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
ASN1_BODY }, /* 7 */
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
{ 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
{ 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
ASN1_OBJ }, /* 10 */
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
{ 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */
{ 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
{ 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */
{ 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
ASN1_BODY }, /* 14 */
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
{ 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
{ 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
{ 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
{ 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
{ 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
ASN1_OBJ }, /* 19 */
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
{ 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
{ 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
{ 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
{ 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
{ 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
{ 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
{ 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
ASN1_BODY }, /* 25 */
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
{ 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
{ 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
{ 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
{ 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
{ 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
{ 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
ASN1_BODY }, /* 31 */
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
{ 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
{ 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
{ 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
{ 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
{ 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
{ 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
{ 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
{ 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
{ 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
{ 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
{ 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
{ 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
{ 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
{ 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
{ 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
@ -368,22 +448,26 @@ static bool parse_certificate(private_x509_ac_t *this)
}
break;
case AC_OBJ_HOLDER_ISSUER:
if (!parse_directoryName(object, level, FALSE, &this->holderIssuer))
if (!parse_directoryName(object, level, FALSE,
&this->holderIssuer))
{
goto end;
}
break;
case AC_OBJ_HOLDER_SERIAL:
this->holderSerial = object;
this->holderSerial = identification_create_from_encoding(
ID_KEY_ID, object);
break;
case AC_OBJ_ENTITY_NAME:
if (!parse_directoryName(object, level, TRUE, &this->entityName))
if (!parse_directoryName(object, level, TRUE,
&this->entityName))
{
goto end;
}
break;
case AC_OBJ_ISSUER_NAME:
if (!parse_directoryName(object, level, FALSE, &this->issuerName))
if (!parse_directoryName(object, level, FALSE,
&this->issuerName))
{
goto end;
}
@ -414,13 +498,14 @@ static bool parse_certificate(private_x509_ac_t *this)
DBG2(DBG_ASN, " need to parse accessIdentity");
break;
case OID_CHARGING_IDENTITY:
DBG2(DBG_ASN, "-- > --");
this->charging = ietf_attributes_create_from_encoding(object);
DBG2(DBG_ASN, "-- < --");
DBG2(DBG_ASN, " need to parse chargingIdentity");
break;
case OID_GROUP:
DBG2(DBG_ASN, "-- > --");
this->groups = ietf_attributes_create_from_encoding(object);
if (!parse_groups(this, object, level))
{
goto end;
}
DBG2(DBG_ASN, "-- < --");
break;
case OID_ROLE:
@ -446,8 +531,9 @@ static bool parse_certificate(private_x509_ac_t *this)
DBG2(DBG_ASN, " need to parse crlDistributionPoints");
break;
case OID_AUTHORITY_KEY_ID:
this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
level, &this->authKeySerialNumber);
this->authKeyIdentifier =
x509_parse_authorityKeyIdentifier(object,
level, &this->authKeySerialNumber);
break;
case OID_TARGET_INFORMATION:
DBG2(DBG_ASN, " need to parse targetInformation");
@ -490,7 +576,7 @@ end:
static chunk_t build_directoryName(asn1_t tag, chunk_t name)
{
return asn1_wrap(tag, "m",
asn1_simple_object(ASN1_CONTEXT_C_4, name));
asn1_simple_object(ASN1_CONTEXT_C_4, name));
}
/**
@ -499,14 +585,15 @@ static chunk_t build_directoryName(asn1_t tag, chunk_t name)
static chunk_t build_holder(private_x509_ac_t *this)
{
x509_t* x509 = (x509_t*)this->holderCert;
identification_t *issuer = this->holderCert->get_issuer(this->holderCert);
identification_t *subject = this->holderCert->get_subject(this->holderCert);
identification_t *issuer, *subject;
issuer = this->holderCert->get_issuer(this->holderCert);
subject = this->holderCert->get_subject(this->holderCert);
return asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_wrap(ASN1_CONTEXT_C_0, "mm",
build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)),
asn1_simple_object(ASN1_INTEGER, x509->get_serial(x509))
),
asn1_simple_object(ASN1_INTEGER, x509->get_serial(x509))),
build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject)));
}
@ -515,10 +602,12 @@ static chunk_t build_holder(private_x509_ac_t *this)
*/
static chunk_t build_v2_form(private_x509_ac_t *this)
{
identification_t *subject = this->signerCert->get_subject(this->signerCert);
identification_t *subject;
subject = this->signerCert->get_subject(this->signerCert);
return asn1_wrap(ASN1_CONTEXT_C_0, "m",
build_directoryName(ASN1_SEQUENCE, subject->get_encoding(subject)));
build_directoryName(ASN1_SEQUENCE,
subject->get_encoding(subject)));
}
/**
@ -531,7 +620,6 @@ static chunk_t build_attr_cert_validity(private_x509_ac_t *this)
asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME));
}
/**
* build attribute type
*/
@ -547,8 +635,55 @@ static chunk_t build_attribute_type(int type, chunk_t content)
*/
static chunk_t build_attributes(private_x509_ac_t *this)
{
enumerator_t *enumerator;
group_t *group;
chunk_t values;
size_t size = 0, len;
u_char *pos;
/* precalculate the total size of all values */
enumerator = this->groups->create_enumerator(this->groups);
while (enumerator->enumerate(enumerator, &group))
{
len = group->value.len;
size += 1 + (len > 0) + (len >= 128) +
(len >= 256) + (len >= 65536) + len;
}
enumerator->destroy(enumerator);
pos = asn1_build_object(&values, ASN1_SEQUENCE, size);
enumerator = this->groups->create_enumerator(this->groups);
while (enumerator->enumerate(enumerator, &group))
{
chunk_t attr;
asn1_t type;
switch (group->type)
{
case AC_GROUP_TYPE_OCTETS:
type = ASN1_OCTET_STRING;
break;
case AC_GROUP_TYPE_STRING:
type = ASN1_UTF8STRING;
break;
case AC_GROUP_TYPE_OID:
type = ASN1_OID;
break;
default:
continue;
}
attr = asn1_simple_object(type, group->value);
memcpy(pos, attr.ptr, attr.len);
pos += attr.len;
free(attr.ptr);
}
enumerator->destroy(enumerator);
return asn1_wrap(ASN1_SEQUENCE, "m",
build_attribute_type(OID_GROUP, this->groups->get_encoding(this->groups)));
build_attribute_type(OID_GROUP,
asn1_wrap(ASN1_SEQUENCE, "m", values)));
}
/**
@ -621,14 +756,11 @@ static chunk_t build_attr_cert_info(private_x509_ac_t *this)
*/
static chunk_t build_ac(private_x509_ac_t *this)
{
chunk_t signatureValue;
chunk_t attributeCertificateInfo;
chunk_t signatureValue, attributeCertificateInfo;
attributeCertificateInfo = build_attr_cert_info(this);
this->signerKey->sign(this->signerKey, SIGN_RSA_EMSA_PKCS1_SHA1,
attributeCertificateInfo, &signatureValue);
return asn1_wrap(ASN1_SEQUENCE, "mmm",
attributeCertificateInfo,
asn1_algorithmIdentifier(OID_SHA1_WITH_RSA),
@ -644,7 +776,11 @@ METHOD(ac_t, get_serial, chunk_t,
METHOD(ac_t, get_holderSerial, chunk_t,
private_x509_ac_t *this)
{
return this->holderSerial;
if (this->holderSerial)
{
return this->holderSerial->get_encoding(this->holderSerial);
}
return chunk_empty;
}
METHOD(ac_t, get_holderIssuer, identification_t*,
@ -659,10 +795,28 @@ METHOD(ac_t, get_authKeyIdentifier, chunk_t,
return this->authKeyIdentifier;
}
METHOD(ac_t, get_groups, ietf_attributes_t*,
/**
* Filter function for attribute enumeration
*/
static bool attr_filter(void *null, group_t **in, ac_group_type_t *type,
void *in2, chunk_t *out)
{
if ((*in)->type == AC_GROUP_TYPE_STRING &&
!chunk_printable((*in)->value, NULL, 0))
{ /* skip non-printable strings */
return FALSE;
}
*type = (*in)->type;
*out = (*in)->value;
return TRUE;
}
METHOD(ac_t, create_group_enumerator, enumerator_t*,
private_x509_ac_t *this)
{
return this->groups ? this->groups->get_ref(this->groups) : NULL;
return enumerator_create_filter(
this->groups->create_enumerator(this->groups),
(void*)attr_filter, NULL, NULL);
}
METHOD(certificate_t, get_type, certificate_type_t,
@ -674,7 +828,11 @@ METHOD(certificate_t, get_type, certificate_type_t,
METHOD(certificate_t, get_subject, identification_t*,
private_x509_ac_t *this)
{
return this->entityName;
if (this->entityName)
{
return this->entityName;
}
return this->holderSerial;
}
METHOD(certificate_t, get_issuer, identification_t*,
@ -686,13 +844,24 @@ METHOD(certificate_t, get_issuer, identification_t*,
METHOD(certificate_t, has_subject, id_match_t,
private_x509_ac_t *this, identification_t *subject)
{
return ID_MATCH_NONE;
id_match_t entity = ID_MATCH_NONE, serial = ID_MATCH_NONE;
if (this->entityName)
{
entity = this->entityName->matches(this->entityName, subject);
}
if (this->holderSerial)
{
serial = this->holderSerial->matches(this->holderSerial, subject);
}
return max(entity, serial);
}
METHOD(certificate_t, has_issuer, id_match_t,
private_x509_ac_t *this, identification_t *issuer)
{
if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr &&
if (issuer->get_type(issuer) == ID_KEY_ID &&
this->authKeyIdentifier.ptr &&
chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer)))
{
return ID_MATCH_PERFECT;
@ -808,9 +977,10 @@ METHOD(certificate_t, equals, bool,
{
return TRUE;
}
if (other->equals == (void*)equals)
if (other->equals == _equals)
{ /* skip allocation if we have the same implementation */
return chunk_equals(this->encoding, ((private_x509_ac_t*)other)->encoding);
return chunk_equals(this->encoding,
((private_x509_ac_t*)other)->encoding);
}
if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
{
@ -827,13 +997,13 @@ METHOD(certificate_t, destroy, void,
if (ref_put(&this->ref))
{
DESTROY_IF(this->holderIssuer);
DESTROY_IF(this->holderSerial);
DESTROY_IF(this->entityName);
DESTROY_IF(this->issuerName);
DESTROY_IF(this->holderCert);
DESTROY_IF(this->signerCert);
DESTROY_IF(this->signerKey);
DESTROY_IF(this->charging);
DESTROY_IF(this->groups);
this->groups->destroy_function(this->groups, (void*)group_destroy);
free(this->serialNumber.ptr);
free(this->authKeyIdentifier.ptr);
free(this->encoding.ptr);
@ -869,9 +1039,10 @@ static private_x509_ac_t *create_empty(void)
.get_holderSerial = _get_holderSerial,
.get_holderIssuer = _get_holderIssuer,
.get_authKeyIdentifier = _get_authKeyIdentifier,
.get_groups = _get_groups,
.create_group_enumerator = _create_group_enumerator,
},
},
.groups = linked_list_create(),
.ref = 1,
);
@ -913,6 +1084,27 @@ x509_ac_t *x509_ac_load(certificate_type_t type, va_list args)
return NULL;
}
/**
* Add groups from a list into AC group memberships
*/
static void add_groups_from_list(private_x509_ac_t *this, linked_list_t *list)
{
enumerator_t *enumerator;
group_t *group;
char *name;
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &name))
{
INIT(group,
.type = AC_GROUP_TYPE_STRING,
.value = chunk_clone(chunk_from_str(name)),
);
this->groups->insert_last(this->groups, group);
}
enumerator->destroy(enumerator);
}
/**
* See header.
*/
@ -934,8 +1126,8 @@ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args)
case BUILD_SERIAL:
ac->serialNumber = chunk_clone(va_arg(args, chunk_t));
continue;
case BUILD_IETF_GROUP_ATTR:
ac->groups = ietf_attributes_create_from_string(va_arg(args, char*));
case BUILD_AC_GROUP_STRINGS:
add_groups_from_list(ac, va_arg(args, linked_list_t*));
continue;
case BUILD_CERT:
ac->holderCert = va_arg(args, certificate_t*);
@ -968,4 +1160,3 @@ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args)
destroy(ac);
return NULL;
}

View File

@ -1 +0,0 @@
openac

View File

@ -1,11 +0,0 @@
ipsec_PROGRAMS = openac
openac_SOURCES = openac.c
dist_man_MANS = openac.8
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-DIPSEC_CONFDIR=\"${sysconfdir}\" \
-DPLUGINS=\""${openac_plugins}\""
openac_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
openac.o : $(top_builddir)/config.status

View File

@ -1,165 +0,0 @@
.TH IPSEC_OPENAC 8 "22 September 2007"
.SH NAME
ipsec openac \- Generation of X.509 attribute certificates
.SH SYNOPSIS
.B ipsec
.B openac
[
.B \-\-help
] [
.B \-\-version
] [
.B \-\-optionsfrom
\fIfilename\fP
]
.br
\ \ \ [
.B \-\-quiet
] [
.B \-\-debug
\fIlevel\fP
]
.br
\ \ \ [
.B \-\-days
\fIdays\fP
] [
.B \-\-hours
\fIhours\fP
]
.br
\ \ \ [
.B \-\-startdate
\fIYYYYMMDDHHMMSSZ\fP
] [
.B \-\-stopdate
\fIYYYYMMDDHHMMSSZ\fP
]
.br
.B \ \ \ \-\-cert
\fIcertfile\fP
.B \-\-key
\fIkeyfile\fP
[
.B \-\-password
\fIpassword\fP
]
.br
.B \ \ \ \-\-usercert
\fIcertfile\fP
.B \-\-groups
\fIattr1,attr2,...\fP
.B \-\-out
\fIfilename\fP
.SH DESCRIPTION
.BR openac
is intended to be used by an Authorization Authority (AA) to generate and sign
X.509 attribute certificates. Currently only the inclusion of one ore several group
attributes is supported. An attribute certificate is linked to a holder by
including the issuer and serial number of the holder's X.509 certificate.
.SH OPTIONS
.TP
\fB\-\-help\fP
display the usage message.
.TP
\fB\-\-version\fP
display the version of \fBopenac\fP.
.TP
\fB\-\-optionsfrom\fP\ \fIfilename\fP
adds the contents of the file to the argument list.
If \fIfilename\fP is a relative path then the file is searched in the directory
\fI/etc/openac\fP.
.TP
\fB\-\-quiet\fP
By default \fBopenac\fP logs all control output both to syslog and stderr.
With the \fB\-\-quiet\fP option no output is written to stderr.
.TP
\fB\-\-days\fP\ \fIdays\fP
Validity of the X.509 attribute certificate in days. If neiter the \fB\-\-days\fP\ nor
the \fB\-\-hours\fP\ option is specified then a default validity interval of 1 day is assumed.
The \fB\-\-days\fP\ option can be combined with the \fB\-\-hours\fP\ option.
.TP
\fB\-\-hours\fP\ \fIhours\fP
Validity of the X.509 attribute certificate in hours. If neiter the \fB\-\-hours\fP\ nor
the \fB\-\-days\fP\ option is specified then a default validity interval of 24 hours is assumed.
The \fB\-\-hours\fP\ option can be combined with the \fB\-\-days\fP\ option.
.TP
\fB\-\-startdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
defines the \fBnotBefore\fP date when the X.509 attribute certificate becomes valid.
The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
If the \fB\-\-startdate\fP option is not specified then the current date is taken as a default.
.TP
\fB\-\-stopdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
defines the \fBnotAfter\fP date when the X.509 attribute certificate will expire.
The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
If the \fB\-\-stopdate\fP option is not specified then the default \fBnotAfter\fP value is computed
by adding the validity interval specified by the \fB\-\-days\fP\ and/or \fB\-\-days\fP\ options
to the \fBnotBefore\fP date.
.TP
\fB\-\-cert\fP\ \fIcertfile\fP
specifies the file containing the X.509 certificate of the Authorization Authority.
The certificate is stored either in PEM or DER format.
.TP
\fB\-\-key\fP\ \fIkeyfile\fP
specifies the encrypted file containing the private RSA key of the Authoritzation
Authority. The private key is stored in PKCS#1 format.
.TP
\fB\-\-password\fP\ \fIpassword\fP
specifies the password with which the private RSA keyfile defined by the
\fB\-\-key\fP option has been protected. If the option is missing then the
password is prompted for on the command line.
.TP
\fB\-\-usercert\fP\ \fIcertfile\fP
specifies file containing the X.509 certificate of the user to which the generated attribute
certificate will apply. The certificate file is stored either in PEM or DER format.
.TP
\fB\-\-groups\fP\ \fIattr1,attr2\fP
specifies a comma-separated list of group attributes that will go into the
X.509 attribute certificate.
.TP
\fB\-\-out\fP\ \fIfilename\fP
specifies the file where the generated X.509 attribute certificate will be stored to.
.SS Debugging
.LP
\fBopenac\fP produces a prodigious amount of debugging information. To do so,
it must be compiled with \-DDEBUG. There are several classes of debugging output,
and \fBopenac\fP may be directed to produce a selection of them. All lines of
debugging output are prefixed with ``|\ '' to distinguish them from error messages.
.LP
When \fBopenac\fP is invoked, it may be given arguments to specify
which classes to output. The current options are:
.TP
\fB\-\-debug\fP\ \fIlevel\fP
sets the debug level to 0 (none), 1 (normal), 2 (more), 3 (raw), and 4 (private),
the default level being 1.
.SH EXIT STATUS
.LP
The execution of \fBopenac\fP terminates with one of the following two exit codes:
.TP
0
means that the attribute certificate was successfully generated and stored.
.TP
1
means that something went wrong.
.SH FILES
\fI/etc/openac/serial\fP\ \ \ serial number of latest attribute certificate
.SH SEE ALSO
.LP
The X.509 attribute certificates generated with \fBopenac\fP can be used to
enforce group policies defined by \fIipsec.conf\fP(5). Use \fIipsec_auto\fP(8)
to load and list X.509 attribute certificates.
.LP
For more information on X.509 attribute certificates, refer to the following
IETF RFC:
.IP
RFC 3281 An Internet Attribute Certificate Profile for Authorization
.SH HISTORY
The \fBopenac\fP program was originally written by Ariane Seiler and Ueli Galizzi.
The software was recoded by Andreas Steffen using strongSwan's X.509 library and
the ASN.1 code synthesis functions written by Christoph Gysin and Christoph Zwahlen.
All authors were with the Zurich University of Applied Sciences in Winterthur,
Switzerland.
.LP
.SH BUGS
Bugs should be reported to the <users@lists.strongswan.org> mailing list.

View File

@ -1,551 +0,0 @@
/**
* @file openac.c
*
* @brief Generation of X.509 attribute certificates.
*
*/
/*
* Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
* Copyright (C) 2004,2007 Andreas Steffen
* Hochschule fuer Technik Rapperswil, Switzerland
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <getopt.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <library.h>
#include <utils/debug.h>
#include <asn1/asn1.h>
#include <credentials/certificates/x509.h>
#include <credentials/certificates/ac.h>
#include <credentials/keys/private_key.h>
#include <credentials/sets/mem_cred.h>
#include <utils/optionsfrom.h>
#define OPENAC_PATH IPSEC_CONFDIR "/openac"
#define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial"
#define DEFAULT_VALIDITY 24*3600 /* seconds */
/**
* @brief prints the usage of the program to the stderr
*/
static void usage(const char *message)
{
if (message != NULL && *message != '\0')
{
fprintf(stderr, "%s\n", message);
}
fprintf(stderr, "Usage: openac"
" [--help]"
" [--version]"
" [--optionsfrom <filename>]"
" [--quiet]"
" \\\n\t"
" [--debug <level 0..4>]"
" \\\n\t"
" [--days <days>]"
" [--hours <hours>]"
" \\\n\t"
" [--startdate <YYYYMMDDHHMMSSZ>]"
" [--enddate <YYYYMMDDHHMMSSZ>]"
" \\\n\t"
" --cert <certfile>"
" --key <keyfile>"
" [--password <password>]"
" \\\n\t"
" --usercert <certfile>"
" --groups <attr1,attr2,..>"
" --out <filename>"
"\n"
);
}
/**
* read the last serial number from file
*/
static chunk_t read_serial(void)
{
chunk_t hex, serial = chunk_empty;
char one[] = {0x01};
FILE *fd;
fd = fopen(OPENAC_SERIAL, "r");
if (fd)
{
hex = chunk_alloca(64);
hex.len = fread(hex.ptr, 1, hex.len, fd);
if (hex.len)
{
/* remove any terminating newline character */
if (hex.ptr[hex.len-1] == '\n')
{
hex.len--;
}
serial = chunk_alloca((hex.len / 2) + (hex.len % 2));
serial = chunk_from_hex(hex, serial.ptr);
}
fclose(fd);
}
else
{
DBG1(DBG_LIB, " file '%s' does not exist yet - serial number "
"set to 01", OPENAC_SERIAL);
}
if (!serial.len)
{
return chunk_clone(chunk_create(one, 1));
}
if (chunk_increment(serial))
{ /* overflow, prepend 0x01 */
return chunk_cat("cc", chunk_create(one, 1), serial);
}
return chunk_clone(serial);
}
/**
* write back the last serial number to file
*/
static void write_serial(chunk_t serial)
{
FILE *fd = fopen(OPENAC_SERIAL, "w");
if (fd)
{
chunk_t hex_serial;
DBG1(DBG_LIB, " serial number is %#B", &serial);
hex_serial = chunk_to_hex(serial, NULL, FALSE);
fprintf(fd, "%.*s\n", (int)hex_serial.len, hex_serial.ptr);
fclose(fd);
free(hex_serial.ptr);
}
else
{
DBG1(DBG_LIB, " could not open file '%s' for writing", OPENAC_SERIAL);
}
}
/**
* global variables accessible by both main() and build.c
*/
static int debug_level = 1;
static bool stderr_quiet = FALSE;
/**
* openac dbg function
*/
static void openac_dbg(debug_t group, level_t level, char *fmt, ...)
{
int priority = LOG_INFO;
char buffer[8192];
char *current = buffer, *next;
va_list args;
if (level <= debug_level)
{
if (!stderr_quiet)
{
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
/* write in memory buffer first */
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
/* do a syslog with every line */
while (current)
{
next = strchr(current, '\n');
if (next)
{
*(next++) = '\0';
}
syslog(priority, "%s\n", current);
current = next;
}
}
}
/**
* @brief openac main program
*
* @param argc number of arguments
* @param argv pointer to the argument values
*/
int main(int argc, char **argv)
{
certificate_t *attr_cert = NULL;
certificate_t *userCert = NULL;
certificate_t *signerCert = NULL;
private_key_t *signerKey = NULL;
time_t notBefore = UNDEFINED_TIME;
time_t notAfter = UNDEFINED_TIME;
time_t validity = 0;
char *keyfile = NULL;
char *certfile = NULL;
char *usercertfile = NULL;
char *outfile = NULL;
char *groups = "";
char buf[BUF_LEN];
chunk_t passphrase = { buf, 0 };
chunk_t serial = chunk_empty;
chunk_t attr_chunk = chunk_empty;
int status = 1;
/* enable openac debugging hook */
dbg = openac_dbg;
passphrase.ptr[0] = '\0';
openlog("openac", 0, LOG_AUTHPRIV);
/* initialize library */
atexit(library_deinit);
if (!library_init(NULL, "openac"))
{
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
}
if (lib->integrity &&
!lib->integrity->check_file(lib->integrity, "openac", argv[0]))
{
fprintf(stderr, "integrity check of openac failed\n");
exit(SS_RC_DAEMON_INTEGRITY);
}
if (!lib->plugins->load(lib->plugins,
lib->settings->get_str(lib->settings, "openac.load", PLUGINS)))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
/* initialize optionsfrom */
options_t *options = options_create();
/* handle arguments */
for (;;)
{
static const struct option long_opts[] = {
/* name, has_arg, flag, val */
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "optionsfrom", required_argument, NULL, '+' },
{ "quiet", no_argument, NULL, 'q' },
{ "cert", required_argument, NULL, 'c' },
{ "key", required_argument, NULL, 'k' },
{ "password", required_argument, NULL, 'p' },
{ "usercert", required_argument, NULL, 'u' },
{ "groups", required_argument, NULL, 'g' },
{ "days", required_argument, NULL, 'D' },
{ "hours", required_argument, NULL, 'H' },
{ "startdate", required_argument, NULL, 'S' },
{ "enddate", required_argument, NULL, 'E' },
{ "out", required_argument, NULL, 'o' },
{ "debug", required_argument, NULL, 'd' },
{ 0,0,0,0 }
};
int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts, NULL);
/* Note: "breaking" from case terminates loop */
switch (c)
{
case EOF: /* end of flags */
break;
case 0: /* long option already handled */
continue;
case ':': /* diagnostic already printed by getopt_long */
case '?': /* diagnostic already printed by getopt_long */
case 'h': /* --help */
usage(NULL);
status = 1;
goto end;
case 'v': /* --version */
printf("openac (strongSwan %s)\n", VERSION);
status = 0;
goto end;
case '+': /* --optionsfrom <filename> */
{
char path[BUF_LEN];
if (*optarg == '/') /* absolute pathname */
{
strncpy(path, optarg, BUF_LEN);
path[BUF_LEN-1] = '\0';
}
else /* relative pathname */
{
snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg);
}
if (!options->from(options, path, &argc, &argv, optind))
{
status = 1;
goto end;
}
}
continue;
case 'q': /* --quiet */
stderr_quiet = TRUE;
continue;
case 'c': /* --cert */
certfile = optarg;
continue;
case 'k': /* --key */
keyfile = optarg;
continue;
case 'p': /* --key */
if (strlen(optarg) >= BUF_LEN)
{
usage("passphrase too long");
goto end;
}
strncpy(passphrase.ptr, optarg, BUF_LEN);
passphrase.len = min(strlen(optarg), BUF_LEN);
continue;
case 'u': /* --usercert */
usercertfile = optarg;
continue;
case 'g': /* --groups */
groups = optarg;
continue;
case 'D': /* --days */
if (optarg == NULL || !isdigit(optarg[0]))
{
usage("missing number of days");
goto end;
}
else
{
char *endptr;
long days = strtol(optarg, &endptr, 0);
if (*endptr != '\0' || endptr == optarg || days <= 0)
{
usage("<days> must be a positive number");
goto end;
}
validity += 24*3600*days;
}
continue;
case 'H': /* --hours */
if (optarg == NULL || !isdigit(optarg[0]))
{
usage("missing number of hours");
goto end;
}
else
{
char *endptr;
long hours = strtol(optarg, &endptr, 0);
if (*endptr != '\0' || endptr == optarg || hours <= 0)
{
usage("<hours> must be a positive number");
goto end;
}
validity += 3600*hours;
}
continue;
case 'S': /* --startdate */
if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
{
usage("date format must be YYYYMMDDHHMMSSZ");
goto end;
}
else
{
chunk_t date = { optarg, 15 };
notBefore = asn1_to_time(&date, ASN1_GENERALIZEDTIME);
}
continue;
case 'E': /* --enddate */
if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
{
usage("date format must be YYYYMMDDHHMMSSZ");
goto end;
}
else
{
chunk_t date = { optarg, 15 };
notAfter = asn1_to_time(&date, ASN1_GENERALIZEDTIME);
}
continue;
case 'o': /* --out */
outfile = optarg;
continue;
case 'd': /* --debug */
debug_level = atoi(optarg);
continue;
default:
usage("");
status = 0;
goto end;
}
/* break from loop */
break;
}
if (optind != argc)
{
usage("unexpected argument");
goto end;
}
DBG1(DBG_LIB, "starting openac (strongSwan Version %s)", VERSION);
/* load the signer's RSA private key */
if (keyfile != NULL)
{
mem_cred_t *mem;
shared_key_t *shared;
mem = mem_cred_create();
lib->credmgr->add_set(lib->credmgr, &mem->set);
shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
chunk_clone(passphrase));
mem->add_shared(mem, shared, NULL);
signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_FROM_FILE, keyfile,
BUILD_END);
lib->credmgr->remove_set(lib->credmgr, &mem->set);
mem->destroy(mem);
if (signerKey == NULL)
{
goto end;
}
DBG1(DBG_LIB, " loaded private key file '%s'", keyfile);
}
/* load the signer's X.509 certificate */
if (certfile != NULL)
{
signerCert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, certfile,
BUILD_END);
if (signerCert == NULL)
{
goto end;
}
}
/* load the users's X.509 certificate */
if (usercertfile != NULL)
{
userCert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, usercertfile,
BUILD_END);
if (userCert == NULL)
{
goto end;
}
}
/* compute validity interval */
validity = (validity)? validity : DEFAULT_VALIDITY;
notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore;
notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter;
/* build and parse attribute certificate */
if (userCert != NULL && signerCert != NULL && signerKey != NULL &&
outfile != NULL)
{
/* read the serial number and increment it by one */
serial = read_serial();
attr_cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509_AC,
BUILD_CERT, userCert,
BUILD_NOT_BEFORE_TIME, notBefore,
BUILD_NOT_AFTER_TIME, notAfter,
BUILD_SERIAL, serial,
BUILD_IETF_GROUP_ATTR, groups,
BUILD_SIGNING_CERT, signerCert,
BUILD_SIGNING_KEY, signerKey,
BUILD_END);
if (!attr_cert)
{
goto end;
}
/* write the attribute certificate to file */
if (attr_cert->get_encoding(attr_cert, CERT_ASN1_DER, &attr_chunk))
{
if (chunk_write(attr_chunk, outfile, 0022, TRUE))
{
DBG1(DBG_APP, " written attribute cert file '%s' (%d bytes)",
outfile, attr_chunk.len);
write_serial(serial);
status = 0;
}
else
{
DBG1(DBG_APP, " writing attribute cert file '%s' failed: %s",
outfile, strerror(errno));
}
}
}
else
{
usage("some of the mandatory parameters --usercert --cert --key --out "
"are missing");
}
end:
/* delete all dynamically allocated objects */
DESTROY_IF(signerKey);
DESTROY_IF(signerCert);
DESTROY_IF(userCert);
DESTROY_IF(attr_cert);
free(attr_chunk.ptr);
free(serial.ptr);
closelog();
dbg = dbg_default;
options->destroy(options);
exit(status);
}

View File

@ -11,6 +11,7 @@ pki_SOURCES = pki.c pki.h command.c command.h \
commands/self.c \
commands/print.c \
commands/signcrl.c \
commands/acert.c \
commands/pkcs7.c \
commands/verify.c

View File

@ -24,12 +24,12 @@
/**
* Maximum number of commands (+1).
*/
#define MAX_COMMANDS 11
#define MAX_COMMANDS 12
/**
* Maximum number of options in a command (+3)
*/
#define MAX_OPTIONS 32
#define MAX_OPTIONS 36
/**
* Maximum number of usage summary lines (+1)

292
src/pki/commands/acert.c Normal file
View File

@ -0,0 +1,292 @@
/*
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* 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 <time.h>
#include <errno.h>
#include "pki.h"
#include <utils/debug.h>
#include <asn1/asn1.h>
#include <collections/linked_list.h>
#include <credentials/certificates/certificate.h>
#include <credentials/certificates/x509.h>
#include <credentials/certificates/ac.h>
/**
* Issue an attribute certificate
*/
static int acert()
{
cred_encoding_type_t form = CERT_ASN1_DER;
hash_algorithm_t digest = HASH_SHA1;
certificate_t *ac = NULL, *cert = NULL, *issuer =NULL;
private_key_t *private = NULL;
public_key_t *public = NULL;
char *file = NULL, *hex = NULL, *issuercert = NULL, *issuerkey = NULL;
char *error = NULL, *keyid = NULL;
linked_list_t *groups;
chunk_t serial = chunk_empty, encoding = chunk_empty;
time_t not_before, not_after, lifetime = 24 * 60 * 60;
char *datenb = NULL, *datena = NULL, *dateform = NULL;
rng_t *rng;
char *arg;
groups = linked_list_create();
while (TRUE)
{
switch (command_getopt(&arg))
{
case 'h':
goto usage;
case 'g':
digest = enum_from_name(hash_algorithm_short_names, arg);
if (digest == -1)
{
error = "invalid --digest type";
goto usage;
}
continue;
case 'i':
file = arg;
continue;
case 'm':
groups->insert_last(groups, arg);
continue;
case 'c':
issuercert = arg;
continue;
case 'k':
issuerkey = arg;
continue;
case 'x':
keyid = arg;
continue;
case 'l':
lifetime = atoi(arg) * 60 * 60;
if (!lifetime)
{
error = "invalid --lifetime value";
goto usage;
}
continue;
case 'D':
dateform = arg;
continue;
case 'F':
datenb = arg;
continue;
case 'T':
datena = arg;
continue;
case 's':
hex = arg;
continue;
case 'f':
if (!get_form(arg, &form, CRED_CERTIFICATE))
{
error = "invalid output format";
goto usage;
}
continue;
case EOF:
break;
default:
error = "invalid --acert option";
goto usage;
}
break;
}
if (!calculate_lifetime(dateform, datenb, datena, lifetime,
&not_before, &not_after))
{
error = "invalid --not-before/after datetime";
goto usage;
}
if (!issuercert)
{
error = "--issuercert is required";
goto usage;
}
if (!issuerkey && !keyid)
{
error = "--issuerkey or --issuerkeyid is required";
goto usage;
}
issuer = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, issuercert, BUILD_END);
if (!issuer)
{
error = "parsing issuer certificate failed";
goto end;
}
public = issuer->get_public_key(issuer);
if (!public)
{
error = "extracting issuer certificate public key failed";
goto end;
}
if (issuerkey)
{
private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
public->get_type(public),
BUILD_FROM_FILE, issuerkey, BUILD_END);
}
else
{
chunk_t chunk;
chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
BUILD_PKCS11_KEYID, chunk, BUILD_END);
free(chunk.ptr);
}
if (!private)
{
error = "loading issuer private key failed";
goto end;
}
if (!private->belongs_to(private, public))
{
error = "issuer private key does not match issuer certificate";
goto end;
}
if (hex)
{
serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL);
}
else
{
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
if (!rng)
{
error = "no random number generator found";
goto end;
}
if (!rng_allocate_bytes_not_zero(rng, 8, &serial, FALSE))
{
error = "failed to generate serial number";
rng->destroy(rng);
goto end;
}
serial.ptr[0] &= 0x7F;
rng->destroy(rng);
}
if (file)
{
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, file, BUILD_END);
}
else
{
if (!chunk_from_fd(0, &encoding))
{
fprintf(stderr, "%s: ", strerror(errno));
error = "reading public key failed";
goto end;
}
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB, encoding, BUILD_END);
chunk_free(&encoding);
}
if (!cert)
{
error = "parsing user certificate failed";
goto end;
}
ac = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509_AC,
BUILD_CERT, cert,
BUILD_NOT_BEFORE_TIME, not_before,
BUILD_NOT_AFTER_TIME, not_after,
BUILD_SERIAL, serial,
BUILD_AC_GROUP_STRINGS, groups,
BUILD_SIGNING_CERT, issuer,
BUILD_SIGNING_KEY, private,
BUILD_END);
if (!ac)
{
error = "generating attribute certificate failed";
goto end;
}
if (!ac->get_encoding(ac, form, &encoding))
{
error = "encoding attribute certificate failed";
goto end;
}
if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
{
error = "writing attribute certificate key failed";
goto end;
}
end:
DESTROY_IF(ac);
DESTROY_IF(cert);
DESTROY_IF(issuer);
DESTROY_IF(public);
DESTROY_IF(private);
groups->destroy(groups);
free(encoding.ptr);
free(serial.ptr);
if (error)
{
fprintf(stderr, "%s\n", error);
return 1;
}
return 0;
usage:
groups->destroy(groups);
return command_usage(error);
}
/**
* Register the command.
*/
static void __attribute__ ((constructor))reg()
{
command_register((command_t) {
acert, 'z', "acert",
"issue an attribute certificate",
{"[--in file] [--group name]* --issuerkey file|--issuerkeyid hex",
" --issuercert file [--serial hex] [--lifetime hours]",
" [--not-before datetime] [--not-after datetime] [--dateform form]",
"[--digest md5|sha1|sha224|sha256|sha384|sha512] [--outform der|pem]"},
{
{"help", 'h', 0, "show usage information"},
{"in", 'i', 1, "holder certificate, default: stdin"},
{"group", 'm', 1, "group membership string to include"},
{"issuercert", 'c', 1, "issuer certificate file"},
{"issuerkey", 'k', 1, "issuer private key file"},
{"issuerkeyid", 'x', 1, "keyid on smartcard of issuer private key"},
{"serial", 's', 1, "serial number in hex, default: random"},
{"lifetime", 'l', 1, "hours the acert is valid, default: 24"},
{"not-before", 'F', 1, "date/time the validity of the AC starts"},
{"not-after", 'T', 1, "date/time the validity of the AC ends"},
{"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
{"digest", 'g', 1, "digest for signature creation, default: sha1"},
{"outform", 'f', 1, "encoding of generated cert, default: der"},
}
});
}

View File

@ -72,8 +72,8 @@ static int issue()
int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
chunk_t serial = chunk_empty;
chunk_t encoding = chunk_empty;
time_t lifetime = 1095;
time_t not_before, not_after;
time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
char *datenb = NULL, *datena = NULL, *dateform = NULL;
x509_flag_t flags = 0;
x509_t *x509;
x509_cdp_t *cdp = NULL;
@ -132,13 +132,22 @@ static int issue()
san->insert_last(san, identification_create_from_string(arg));
continue;
case 'l':
lifetime = atoi(arg);
lifetime = atoi(arg) * 24 * 60 * 60;
if (!lifetime)
{
error = "invalid --lifetime value";
goto usage;
}
continue;
case 'D':
dateform = arg;
continue;
case 'F':
datenb = arg;
continue;
case 'T':
datena = arg;
continue;
case 's':
hex = arg;
continue;
@ -285,6 +294,12 @@ static int issue()
error = "--cakey or --keyid is required";
goto usage;
}
if (!calculate_lifetime(dateform, datenb, datena, lifetime,
&not_before, &not_after))
{
error = "invalid --not-before/after datetime";
goto usage;
}
if (dn && *dn)
{
id = identification_create_from_string(dn);
@ -363,6 +378,7 @@ static int issue()
rng->destroy(rng);
goto end;
}
serial.ptr[0] &= 0x7F;
rng->destroy(rng);
}
@ -454,9 +470,6 @@ static int issue()
chunk_from_chars(ASN1_SEQUENCE, 0));
}
not_before = time(NULL);
not_after = not_before + lifetime * 24 * 60 * 60;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_SIGNING_KEY, private, BUILD_SIGNING_CERT, ca,
BUILD_PUBLIC_KEY, public, BUILD_SUBJECT, id,
@ -552,6 +565,9 @@ static void __attribute__ ((constructor))reg()
{"dn", 'd', 1, "distinguished name to include as subject"},
{"san", 'a', 1, "subjectAltName to include in certificate"},
{"lifetime", 'l', 1, "days the certificate is valid, default: 1095"},
{"not-before", 'F', 1, "date/time the validity of the cert starts"},
{"not-after", 'T', 1, "date/time the validity of the cert ends"},
{"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
{"serial", 's', 1, "serial number in hex, default: random"},
{"ca", 'b', 0, "include CA basicConstraint, default: no"},
{"pathlen", 'p', 1, "set path length constraint"},

View File

@ -16,9 +16,11 @@
#include "pki.h"
#include <asn1/asn1.h>
#include <asn1/oid.h>
#include <credentials/certificates/certificate.h>
#include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h>
#include <credentials/certificates/ac.h>
#include <selectors/traffic_selector.h>
#include <time.h>
@ -387,6 +389,84 @@ static void print_crl(crl_t *crl)
enumerator->destroy(enumerator);
}
/**
* Print AC specific information
*/
static void print_ac(ac_t *ac)
{
ac_group_type_t type;
identification_t *id;
enumerator_t *groups;
chunk_t chunk;
bool first = TRUE;
chunk = chunk_skip_zero(ac->get_serial(ac));
printf("serial: %#B\n", &chunk);
id = ac->get_holderIssuer(ac);
if (id)
{
printf("hissuer: \"%Y\"\n", id);
}
chunk = chunk_skip_zero(ac->get_holderSerial(ac));
if (chunk.ptr)
{
printf("hserial: %#B\n", &chunk);
}
groups = ac->create_group_enumerator(ac);
while (groups->enumerate(groups, &type, &chunk))
{
int oid;
char *str;
if (first)
{
printf("groups: ");
first = FALSE;
}
else
{
printf(" ");
}
switch (type)
{
case AC_GROUP_TYPE_STRING:
printf("%.*s", (int)chunk.len, chunk.ptr);
break;
case AC_GROUP_TYPE_OID:
oid = asn1_known_oid(chunk);
if (oid == OID_UNKNOWN)
{
str = asn1_oid_to_string(chunk);
if (str)
{
printf("%s", str);
}
else
{
printf("OID:%#B", &chunk);
}
}
else
{
printf("%s", oid_names[oid].name);
}
break;
case AC_GROUP_TYPE_OCTETS:
printf("%#B", &chunk);
break;
}
printf("\n");
}
groups->destroy(groups);
chunk = ac->get_authKeyIdentifier(ac);
if (chunk.ptr)
{
printf("authkey: %#B\n", &chunk);
}
}
/**
* Print certificate information
*/
@ -432,6 +512,9 @@ static void print_cert(certificate_t *cert)
case CERT_X509_CRL:
print_crl((crl_t*)cert);
break;
case CERT_X509_AC:
print_ac((ac_t*)cert);
break;
default:
printf("parsing certificate subtype %N not implemented\n",
certificate_type_names, cert->get_type(cert));
@ -472,6 +555,11 @@ static int print()
type = CRED_CERTIFICATE;
subtype = CERT_X509_CRL;
}
else if (streq(arg, "ac"))
{
type = CRED_CERTIFICATE;
subtype = CERT_X509_AC;
}
else if (streq(arg, "pub"))
{
type = CRED_PUBLIC_KEY;
@ -558,7 +646,7 @@ static void __attribute__ ((constructor))reg()
command_register((command_t)
{ print, 'a', "print",
"print a credential in a human readable form",
{"[--in file] [--type rsa-priv|ecdsa-priv|pub|x509|crl]"},
{"[--in file] [--type rsa-priv|ecdsa-priv|pub|x509|crl|ac]"},
{
{"help", 'h', 0, "show usage information"},
{"in", 'i', 1, "input file, default: stdin"},

View File

@ -60,8 +60,8 @@ static int self()
int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
chunk_t serial = chunk_empty;
chunk_t encoding = chunk_empty;
time_t lifetime = 1095;
time_t not_before, not_after;
time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
char *datenb = NULL, *datena = NULL, *dateform = NULL;
x509_flag_t flags = 0;
x509_cert_policy_t *policy = NULL;
char *arg;
@ -114,14 +114,24 @@ static int self()
case 'a':
san->insert_last(san, identification_create_from_string(arg));
continue;
continue;
case 'l':
lifetime = atoi(arg);
lifetime = atoi(arg) * 24 * 60 * 60;
if (!lifetime)
{
error = "invalid --lifetime value";
goto usage;
}
continue;
case 'D':
dateform = arg;
continue;
case 'F':
datenb = arg;
continue;
case 'T':
datena = arg;
continue;
case 's':
hex = arg;
continue;
@ -250,6 +260,12 @@ static int self()
error = "--dn is required";
goto usage;
}
if (!calculate_lifetime(dateform, datenb, datena, lifetime,
&not_before, &not_after))
{
error = "invalid --not-before/after datetime";
goto usage;
}
id = identification_create_from_string(dn);
if (id->get_type(id) != ID_DER_ASN1_DN)
{
@ -314,10 +330,9 @@ static int self()
rng->destroy(rng);
goto end;
}
serial.ptr[0] &= 0x7F;
rng->destroy(rng);
}
not_before = time(NULL);
not_after = not_before + lifetime * 24 * 60 * 60;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_SIGNING_KEY, private, BUILD_PUBLIC_KEY, public,
BUILD_SUBJECT, id, BUILD_NOT_BEFORE_TIME, not_before,
@ -405,6 +420,9 @@ static void __attribute__ ((constructor))reg()
{"dn", 'd', 1, "subject and issuer distinguished name"},
{"san", 'a', 1, "subjectAltName to include in certificate"},
{"lifetime", 'l', 1, "days the certificate is valid, default: 1095"},
{"not-before", 'F', 1, "date/time the validity of the cert starts"},
{"not-after", 'T', 1, "date/time the validity of the cert ends"},
{"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
{"serial", 's', 1, "serial number in hex, default: random"},
{"ca", 'b', 0, "include CA basicConstraint, default: no"},
{"pathlen", 'p', 1, "set path length constraint"},

View File

@ -124,7 +124,8 @@ static int sign_crl()
int serial_len = 0;
crl_reason_t reason = CRL_REASON_UNSPECIFIED;
time_t thisUpdate, nextUpdate, date = time(NULL);
time_t lifetime = 15;
time_t lifetime = 15 * 24 * 60 * 60;
char *datetu = NULL, *datenu = NULL, *dateform = NULL;
linked_list_t *list, *cdps;
enumerator_t *enumerator, *lastenum = NULL;
x509_cdp_t *cdp;
@ -161,13 +162,22 @@ static int sign_crl()
lastupdate = arg;
continue;
case 'l':
lifetime = atoi(arg);
lifetime = atoi(arg) * 24 * 60 * 60;
if (!lifetime)
{
error = "invalid lifetime";
error = "invalid --lifetime value";
goto usage;
}
continue;
case 'D':
dateform = arg;
continue;
case 'F':
datetu = arg;
continue;
case 'T':
datenu = arg;
continue;
case 'z':
serial_len = read_serial(arg, serial, sizeof(serial));
if (serial_len < 0)
@ -275,6 +285,12 @@ static int sign_crl()
error = "--cakey or --keyid is required";
goto usage;
}
if (!calculate_lifetime(dateform, datetu, datenu, lifetime,
&thisUpdate, &nextUpdate))
{
error = "invalid --this/next-update datetime";
goto usage;
}
ca = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, cacert, BUILD_END);
@ -321,9 +337,6 @@ static int sign_crl()
goto error;
}
thisUpdate = time(NULL);
nextUpdate = thisUpdate + lifetime * 24 * 60 * 60;
if (basecrl)
{
lastcrl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
@ -442,6 +455,9 @@ static void __attribute__ ((constructor))reg()
{"cakey", 'k', 1, "CA private key file"},
{"cakeyid", 'x', 1, "keyid on smartcard of CA private key"},
{"lifetime", 'l', 1, "days the CRL gets a nextUpdate, default: 15"},
{"this-update", 'F', 1, "date/time the validity of the CRL starts"},
{"next-update", 'T', 1, "date/time the validity of the CRL ends"},
{"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
{"lastcrl", 'a', 1, "CRL of lastUpdate to copy revocations from"},
{"basecrl", 'b', 1, "base CRL to create a delta CRL for"},
{"crluri", 'u', 1, "freshest delta CRL URI to include"},

View File

@ -4,6 +4,7 @@ man1_MANS = \
pki---self.1 \
pki---issue.1 \
pki---signcrl.1 \
pki---acert.1 \
pki---req.1 \
pki---pkcs7.1 \
pki---keyid.1 \

View File

@ -0,0 +1,130 @@
.TH "PKI \-\-ACERT" 1 "2014-02-05" "@PACKAGE_VERSION@" "strongSwan"
.
.SH "NAME"
.
pki \-\-acert \- Issue an attribute certificate
.
.SH "SYNOPSIS"
.
.SY pki\ \-\-acert
.OP \-\-in file
.OP \-\-group membership
.BI \-\-issuerkey\~ file |\-\-issuerkeyid\~ hex
.BI \-\-issuercert\~ file
.OP \-\-lifetime hours
.OP \-\-not-before datetime
.OP \-\-not-after datetime
.OP \-\-serial hex
.OP \-\-digest digest
.OP \-\-outform encoding
.OP \-\-debug level
.YS
.
.SY pki\ \-\-acert
.BI \-\-options\~ file
.YS
.
.SY "pki \-\-acert"
.B \-h
|
.B \-\-help
.YS
.
.SH "DESCRIPTION"
.
This sub-command of
.BR pki (1)
is used to issue an attribute certificate using an issuer certificate with its
private key and the holder certificate.
.
.SH "OPTIONS"
.
.TP
.B "\-h, \-\-help"
Print usage information with a summary of the available options.
.TP
.BI "\-v, \-\-debug " level
Set debug level, default: 1.
.TP
.BI "\-+, \-\-options " file
Read command line options from \fIfile\fR.
.TP
.BI "\-i, \-\-in " file
Holder certificate to issue an attribute certificate for. If not given the
certificate is read from \fISTDIN\fR.
.TP
.BI "\-m, \-\-group " membership
Group membership the attribute certificate shall certify. The specified group
is included as a string. To include multiple groups, the option can be repeated.
.TP
.BI "\-k, \-\-issuerkey " file
Issuer private key file. Either this or
.B \-\-issuerkeyid
is required.
.TP
.BI "\-x, \-\-issuerkeyid " hex
Key ID of a issuer private key on a smartcard. Either this or
.B \-\-issuerkey
is required.
.TP
.BI "\-c, \-\-issuercert " file
Issuer certificate file. Required.
.TP
.BI "\-l, \-\-lifetime " hours
Hours the attribute certificate is valid, default: 24. Ignored if both
an absolute start and end time are given.
.TP
.BI "\-F, \-\-not-before " datetime
Absolute time when the validity of the AC begins. The datetime format is
defined by the
.B \-\-dateform
option.
.TP
.BI "\-T, \-\-not-after " datetime
Absolute time when the validity of the AC ends. The datetime format is
defined by the
.B \-\-dateform
option.
.TP
.BI "\-D, \-\-dateform " form
strptime(3) format for the
.B \-\-not\-before
and
.B \-\-not\-after
options, default:
.B %d.%m.%y %T
.TP
.BI "\-s, \-\-serial " hex
Serial number in hex. It is randomly allocated by default.
.TP
.BI "\-g, \-\-digest " digest
Digest to use for signature creation. One of \fImd5\fR, \fIsha1\fR,
\fIsha224\fR, \fIsha256\fR, \fIsha384\fR, or \fIsha512\fR. Defaults to
\fIsha1\fR.
.TP
.BI "\-f, \-\-outform " encoding
Encoding of the created certificate file. Either \fIder\fR (ASN.1 DER) or
\fIpem\fR (Base64 PEM), defaults to \fIder\fR.
.
.SH "EXAMPLES"
.
To save repetitive typing, command line options can be stored in files.
Lets assume
.I acert.opt
contains the following contents:
.PP
.EX
--issuercert aacert.der --issuerkey aakey.der --digest sha256 --lifetime 4
.EE
.PP
Then the following command can be used to issue an attribute certificate based
on a holder certificate and the options above:
.PP
.EX
pki --acert --options acert.opt --in holder.der --group sales --group finance -f pem
.EE
.PP
.
.SH "SEE ALSO"
.
.BR pki (1)

View File

@ -14,6 +14,8 @@ pki \-\-issue \- Issue a certificate using a CA certificate and key
.OP \-\-dn subject-dn
.OP \-\-san subjectAltName
.OP \-\-lifetime days
.OP \-\-not-before datetime
.OP \-\-not-after datetime
.OP \-\-serial hex
.OP \-\-flag flag
.OP \-\-digest digest
@ -88,7 +90,28 @@ Subject distinguished name (DN) of the issued certificate.
subjectAltName extension to include in certificate. Can be used multiple times.
.TP
.BI "\-l, \-\-lifetime " days
Days the certificate is valid, default: 1095.
Days the certificate is valid, default: 1095. Ignored if both
an absolute start and end time are given.
.TP
.BI "\-F, \-\-not-before " datetime
Absolute time when the validity of the certificate begins. The datetime format
is defined by the
.B \-\-dateform
option.
.TP
.BI "\-T, \-\-not-after " datetime
Absolute time when the validity of the certificate ends. The datetime format is
defined by the
.B \-\-dateform
option.
.TP
.BI "\-D, \-\-dateform " form
strptime(3) format for the
.B \-\-not\-before
and
.B \-\-not\-after
options, default:
.B %d.%m.%y %T
.TP
.BI "\-s, \-\-serial " hex
Serial number in hex. It is randomly allocated by default.
@ -176,4 +199,4 @@ given PKCS#10 certificate request and the options above:
.
.SH "SEE ALSO"
.
.BR pki (1)
.BR pki (1)

View File

@ -46,8 +46,9 @@ Input file. If not given the input is read from \fISTDIN\fR.
.BI "\-t, \-\-type " type
Type of input. One of \fIrsa-priv\fR (RSA private key), \fIecdsa-priv\fR (ECDSA
private key), \fIpub\fR (public key), \fIx509\fR (X.509 certificate), \fIcrl\fR
(Certificate Revocation List, CRL), defaults to \fIx509\fR.
(Certificate Revocation List, CRL), \fIac\fR (Attribute Certificate),
defaults to \fIx509\fR.
.
.SH "SEE ALSO"
.
.BR pki (1)
.BR pki (1)

View File

@ -14,6 +14,8 @@ pki \-\-self \- Create a self-signed certificate
.BI \-\-dn\~ distinguished-name
.OP \-\-san subjectAltName
.OP \-\-lifetime days
.OP \-\-not-before datetime
.OP \-\-not-after datetime
.OP \-\-serial hex
.OP \-\-flag flag
.OP \-\-digest digest
@ -75,7 +77,28 @@ Subject and issuer distinguished name (DN). Required.
subjectAltName extension to include in certificate. Can be used multiple times.
.TP
.BI "\-l, \-\-lifetime " days
Days the certificate is valid, default: 1095.
Days the certificate is valid, default: 1095. Ignored if both
an absolute start and end time are given.
.TP
.BI "\-F, \-\-not-before " datetime
Absolute time when the validity of the certificate begins. The datetime format
is defined by the
.B \-\-dateform
option.
.TP
.BI "\-T, \-\-not-after " datetime
Absolute time when the validity of the certificate ends. The datetime format is
defined by the
.B \-\-dateform
option.
.TP
.BI "\-D, \-\-dateform " form
strptime(3) format for the
.B \-\-not\-before
and
.B \-\-not\-after
options, default:
.B %d.%m.%y %T
.TP
.BI "\-s, \-\-serial " hex
Serial number in hex. It is randomly allocated by default.
@ -145,4 +168,4 @@ Generate a self-signed certificate using the given RSA key:
.
.SH "SEE ALSO"
.
.BR pki (1)
.BR pki (1)

View File

@ -10,6 +10,8 @@ pki \-\-signcrl \- Issue a Certificate Revocation List (CRL) using a CA certific
.BI \-\-cakey\~ file |\-\-cakeyid\~ hex
.BI \-\-cacert\~ file
.OP \-\-lifetime days
.OP \-\-this-update datetime
.OP \-\-next-update datetime
.OP \-\-lastcrl crl
.OP \-\-basecrl crl
.OP \-\-crluri uri
@ -62,7 +64,28 @@ is required.
CA certificate file. Required.
.TP
.BI "\-l, \-\-lifetime " days
Days until the CRL gets a nextUpdate, default: 15.
Days until the CRL gets a nextUpdate, default: 15. Ignored if both
an absolute start and end time are given.
.TP
.BI "\-F, \-\-this-update " datetime
Absolute time when the validity of the CRL begins. The datetime format is
defined by the
.B \-\-dateform
option.
.TP
.BI "\-T, \-\-next-update " datetime
Absolute time when the validity of the CRL end. The datetime format is
defined by the
.B \-\-dateform
option.
.TP
.BI "\-D, \-\-dateform " form
strptime(3) format for the
.B \-\-this\-update
and
.B \-\-next\-update
options, default:
.B %d.%m.%y %T
.TP
.BI "\-a, \-\-lastcrl " crl
CRL of lastUpdate to copy revocations from.
@ -121,4 +144,4 @@ number, but no reason:
.PP
.SH "SEE ALSO"
.
.BR pki (1)
.BR pki (1)

View File

@ -49,6 +49,9 @@ Issue a certificate using a CA certificate and key.
.B "\-c, \-\-signcrl"
Issue a CRL using a CA certificate and key.
.TP
.B "\-z, \-\-acert"
Issue an attribute certificate.
.TP
.B "\-r, \-\-req"
Create a PKCS#10 certificate request.
.TP
@ -148,6 +151,7 @@ certificates with the \-\-crl option.
.BR pki\ \-\-self (1),
.BR pki\ \-\-issue (1),
.BR pki\ \-\-signcrl (1),
.BR pki\ \-\-acert (1),
.BR pki\ \-\-req (1),
.BR pki\ \-\-pkcs7 (1),
.BR pki\ \-\-keyid (1),

View File

@ -13,9 +13,11 @@
* for more details.
*/
#define _GNU_SOURCE
#include "command.h"
#include "pki.h"
#include <time.h>
#include <unistd.h>
#include <utils/debug.h>
@ -101,6 +103,56 @@ bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type)
return FALSE;
}
/**
* See header
*/
bool calculate_lifetime(char *format, char *nbstr, char *nastr, time_t span,
time_t *nb, time_t *na)
{
struct tm tm;
time_t now;
char *end;
if (!format)
{
format = "%d.%m.%y %T";
}
now = time(NULL);
localtime_r(&now, &tm);
if (nbstr)
{
end = strptime(nbstr, format, &tm);
if (end == NULL || *end != '\0')
{
return FALSE;
}
}
*nb = mktime(&tm);
localtime_r(&now, &tm);
if (nastr)
{
end = strptime(nastr, format, &tm);
if (end == NULL || *end != '\0')
{
return FALSE;
}
}
*na = mktime(&tm);
if (!nbstr && nastr)
{
*nb = *na - span;
}
else if (!nastr)
{
*na = *nb + span;
}
return TRUE;
}
/**
* Callback credential set pki uses
*/
@ -188,4 +240,3 @@ int main(int argc, char *argv[])
atexit(remove_callback);
return command_dispatch(argc, argv);
}

View File

@ -33,4 +33,21 @@
*/
bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type);
/**
* Calculate start/end lifetime for certificates.
*
* If both nbstr and nastr are given, span is ignored. Otherwise missing
* arguments are calculated, or assumed to be now.
*
* @param format strptime() format, NULL for default: %d.%m.%y %T
* @param nbstr string describing notBefore datetime, or NULL
* @param nastr string describing notAfter datetime, or NULL
* @param span lifetime span, from notBefore to notAfter
* @param nb calculated notBefore time
* @param na calculated notAfter time
* @return TRUE of nb/na calculated successfully
*/
bool calculate_lifetime(char *format, char *nbstr, char *nastr, time_t span,
time_t *nb, time_t *na);
#endif /** PKI_H_ @}*/

View File

@ -76,6 +76,7 @@ CONFIG_OPTS = \
--enable-unbound \
--enable-ipseckey \
--enable-dnscert \
--enable-acert \
--enable-cmd \
--enable-libipsec \
--enable-kernel-libipsec \

View File

@ -0,0 +1,11 @@
<p>The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each
to gateway <b>moon</b>. The authentication is based on <b>X.509 certificates</b>.
To authorize clients, <b>moon</b> uses locally cached attribute certificates.
While for <b>carol</b> a valid attribute certificate for the group <i>sales</i>
is available, <b>dave</b>'s attribute certificates are either expired or
do not grant permissions for the <i>sales</i> group.</p>
<p>Upon the successful establishment of the IPsec tunnels, <b>leftfirewall=yes</b>
automatically inserts iptables-based firewall rules that let pass the tunneled traffic.
In order to test both tunnel and firewall, both <b>carol</b> and <b>dave</b> try
to ping the client <b>alice</b> behind the gateway <b>moon</b>, but dave fails
to do so.</p>

View File

@ -0,0 +1,12 @@
carol::ipsec status 2> /dev/null::home.*ESTABLISHED.*carol@strongswan.org.*moon.strongswan.org::YES
dave:: ipsec status 2> /dev/null::home.*ESTABLISHED.*dave@strongswan.org.*moon.strongswan.org::NO
moon:: ipsec status 2> /dev/null::rw\[1]: ESTABLISHED.*moon.strongswan.org.*carol@strongswan.org::YES
moon:: ipsec status 2> /dev/null::rw\[2]: ESTABLISHED.*moon.strongswan.org.*dave@strongswan.org::NO
moon::cat /var/log/daemon.log::constraint check failed: group membership to 'sales' required::YES
dave::cat /var/log/daemon.log::received AUTHENTICATION_FAILED notify error::YES
carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_req=1::YES
dave:: ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_req=1::NO
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::NO
moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::NO

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn home
left=PH_IP_CAROL
leftcert=carolCert.pem
leftid=carol@strongswan.org
leftfirewall=yes
right=PH_IP_MOON
rightid=@moon.strongswan.org
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn home
left=PH_IP_DAVE
leftcert=daveCert.pem
leftid=dave@strongswan.org
leftfirewall=yes
right=PH_IP_MOON
rightid=@moon.strongswan.org
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn rw
left=PH_IP_MOON
leftcert=moonCert.pem
leftid=@moon.strongswan.org
leftsubnet=10.1.0.0/16
leftfirewall=yes
right=%any
rightgroups=sales
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIIFU5+Fa8cF2EwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UE
BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
Z1N3YW4gUm9vdCBDQTAeFw0xNDAyMDcwODUwMzVaFw0yMjA0MjYwODUwMzVaMEAx
CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRYwFAYDVQQD
Ew1zdHJvbmdTd2FuIEFBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
y6nSTRzCuTbfuv2FwnXC/R7+5L5WViVxBfCEkaxzW5GJJGTFFbSbpQJxWk603BJH
hlVAVj8jUNMKcOuj/l8UPNV8lcDslQfe/AZd6gqdCwP7uMsAQ3yWfkZZK1jxTdTP
dvcpLNozt7hmIroJVTGzmzI5YIvWbYT/zyEge6pEPaXr8IqYzdWFCUINTXUGEr/L
lt3IUKMTNnhabPHAbTIZ3i0c98Ci0ZzZjGx+JmVVvcY9lgNTjS2xaaklUCq2auR/
QzP7PxuSYkAF4qYhG7Ujeo7v4z79mXISFTlyqKe7k18wUKdf+7suyGczSRMP6+5N
jqNqab7l/SHwHQMVEE5ihwIDAQABoyMwITAfBgNVHSMEGDAWgBRdp91wBlEyfue2
bbO15eBg6i5N7zANBgkqhkiG9w0BAQUFAAOCAQEAakPgMKVjkQmpI1VROcetvZzM
ZHMWwdu9IcwNpi/8qs2qNh6wCYv9c4V6O4zRCB1u8TuAIQiwLNZgjk+OKKLzvUik
gBRogn/apXsvAtfu9ODv5GuS6F38OYWDu/c3fiCZB2MKTtmEro2EkxxMw4DkfJ02
R/xrhAnjeQlRQOChgQ3fHNmH9gVNaKXNq+JaoU2TfHFwuYMMe6q1L+vhOaBd58YA
6wPHOOLcIEaebHIqa4duAE5txJsZCEEySrr5stqo4j7929BAw+U6f+6Wb+UAEW6g
91PKAl5QVbAzgPFWoPkOTNdDOprT+B4eGx0EC2QTEtxxDv5589choF7BMRCzsQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC+DCCAeACAQEwgbCgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHaFe
pFwwWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZ6BG
MESkQjBAMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEW
MBQGA1UEAxMNc3Ryb25nU3dhbiBBQTANBgkqhkiG9w0BAQUFAAIIWCKrRUelL+kw
IhgPMjAxNDAyMDcwODU4MTJaGA8yMDIyMDQyNjA4NTgxMlowIjAgBggrBgEFBQcK
BDEUMBIwEAwFc2FsZXMMB2ZpbmFuY2UwfzByBgNVHSMEazBpCwHqxzoCXPi2xMHh
2q7CV/ZSsLChSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJv
bmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GCCBVOfhWvHBdhMAkG
A1UdOAQCBQAwDQYJKoZIhvcNAQEFBQADggEBADNSv52dbBOp30L0kJse9HqWMBaR
SA5IDrF1FMLVZfI0Vb9XgEmk1SXAnMmPm7bfk+2w0Rd1jL7D905nel3LXuvohSR9
wd4Vo8XX3WUlzNfjUEFFJb0nU2ybr7SmxF+K4wGnhvBAym2y/hNA0glp2hNjYTds
g+RUpM4bSqP5DpUfRBl19VHeEu/OymoACOzuHuNc1IndYM1mkSJYumX6YW60DpF/
TaK1So3FyEWucHeoFCziNbclrjWwB8OS3JfCOl95rxu+0JhyWc+3x1E50W8DaAnY
ZRyYxDjYT9/E9xyzV45yo0xFODIgDgfKMsDjfUmfny3dTesdFUf3Ar3vTfA=
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC9DCCAdwCAQEwgbGgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHKFf
pF0wWzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEzAR
BgNVBAsTCkFjY291bnRpbmcxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmeg
RjBEpEIwQDELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4x
FjAUBgNVBAMTDXN0cm9uZ1N3YW4gQUEwDQYJKoZIhvcNAQEFBQACCCPxWgWKmOUM
MCIYDzIwMTQwMjA3MDg1OTM3WhgPMjAyMjA0MjYwODU5MzdaMB0wGwYIKwYBBQUH
CgQxDzANMAsMCW1hcmtldGluZzB/MHIGA1UdIwRrMGkLAerHOgJc+LbEweHarsJX
9lKwsKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIIFU5+Fa8cF2EwCQYDVR04
BAIFADANBgkqhkiG9w0BAQUFAAOCAQEAThlKhGVv34sfnCSQn6nYUdxMhboTuC98
+DgvTQ/tH0hddCJNg00SpO8AbStwEsqHFaSqFzAGHcMk+XUrBRSGszAwg8nKAKfT
MCvJbK6lWQcPF0WPSSk9/r1TLan4I9xhneNIIGQf1fnNo7NrQnmhJjolUgXQNwFA
qZgKBsk0jWcOSvI0bpK90km5flCHn/OA1rDCdaPuMwreDhvNDoApORYFPZVsLhid
CXSqT+FWfm2NfegS+Q4VHP3YLbY4vLepCerU9aMTUIPit0kf1N8piG/l6AUno1XP
VrcTvruQUWQb08H9aYt7l7kyhzOKkuXjVbdn5egZnK0m4WKmV50guA==
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC8DCCAdgCAQEwgbGgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHKFf
pF0wWzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEzAR
BgNVBAsTCkFjY291bnRpbmcxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmeg
RjBEpEIwQDELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4x
FjAUBgNVBAMTDXN0cm9uZ1N3YW4gQUEwDQYJKoZIhvcNAQEFBQACCEuGbFvrRrtr
MCIYDzIwMTQwMjA3MDgwMTE3WhgPMjAxNDAyMDcwOTAxMTdaMBkwFwYIKwYBBQUH
CgQxCzAJMAcMBXNhbGVzMH8wcgYDVR0jBGswaQsB6sc6Alz4tsTB4dquwlf2UrCw
oUmkRzBFMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEb
MBkGA1UEAxMSc3Ryb25nU3dhbiBSb290IENBgggVTn4VrxwXYTAJBgNVHTgEAgUA
MA0GCSqGSIb3DQEBBQUAA4IBAQBYnOq716FJ079kXAt8vmi2GpEyyCqSBqqjr0lR
X9mGQqWKmpj88ZP61tCooCy8HaJsgKBvedKJHJ4e/YxR+fqBDkT4apFu4wX8P/xh
yKy6/RMAdTtkwVTE6flXdQryCQ/PGhSMuwwH/URFg65mixAatyyaoat4+mZ506u3
F9ZZXkHPP4nZXAJqYjLLcNXPqC4lGoXXT+9dgsm6RLAdnBXT1GGff9tmqt9CcspW
XPjoqy9AxNr6FnItvMGw0CC6MPyVOJImlSxdhFW7waZkpNfmGzRdylXMwHXk8PbW
gjmlDUbyWquu8xBlpron3X/Jx3YNGVNrhgfZLlmhzCRouMqc
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAy6nSTRzCuTbfuv2FwnXC/R7+5L5WViVxBfCEkaxzW5GJJGTF
FbSbpQJxWk603BJHhlVAVj8jUNMKcOuj/l8UPNV8lcDslQfe/AZd6gqdCwP7uMsA
Q3yWfkZZK1jxTdTPdvcpLNozt7hmIroJVTGzmzI5YIvWbYT/zyEge6pEPaXr8IqY
zdWFCUINTXUGEr/Llt3IUKMTNnhabPHAbTIZ3i0c98Ci0ZzZjGx+JmVVvcY9lgNT
jS2xaaklUCq2auR/QzP7PxuSYkAF4qYhG7Ujeo7v4z79mXISFTlyqKe7k18wUKdf
+7suyGczSRMP6+5NjqNqab7l/SHwHQMVEE5ihwIDAQABAoIBAQCIvn5QfkYUG87+
eyirV2xTjdMw/Md1UfBgP4yTTsmpqr79K5fUqg5zLX+0VfJDbRaPEICBKCVrKDfz
d5QFwAsTiXf8CKwQqFdEunWmJfgppEQIYGzN40IciNloLHDghEnEI9GGpv9glLQn
DugjRprEUmWJ+HpB0LH9fc2Ums704Fcd8ud3bStCRxU1TA5VGBHmnyK5/n1Lb1oB
01LoW8ins8lATuV+MAaWZgmCbPajfXY9wQGq3IDMVlOUOTxRo742T1GTrwBZR8ot
mgs/Gs1XkJRC1x9Z9Z1Cej1iC5llv0zX8AUdejczGHQGHj1a1Dg8FpRneW6rrLyK
vvKR8jtRAoGBAOpyk63yCPM2LqU4US5aHXPoLyyGeo4v7okTKIuoUfosQ4XJvylM
lEYoFVFKYBKcXRQhmeWyILtto2BBDnG1HWAi1MbUWLxDNEYieurzJiv4i0XbR6cH
mLhMMlQyKmwLRF5v3EiupjKBZRk2iYcx4eeL3gsUWUzRPeWJHKDgYF4PAoGBAN5i
xyOsU/32gQ6vLQxt8us6n3OBr1PiFg8JIdADPnKOCxJ5uS8dkqOQHCMKyvS9MWrf
3Wj4MOBEgW7fBBAxkvjJdPhBW70/pGM46mb991dTHJ4gIAzGxgvJIqw/FjqEC7Oo
vWDRS4dxW56Rs2tdLn2GRvvlS3+3z90twqS/t6wJAoGBAJpzhzT2Gc1YaZxxIJI/
zd15HfLgWUbo7uWhGHoBFpiQpp8yDNzBVYFukLSwIeDA4FUN2dxH4GZ50ULtOP3S
Cps19yVR6W+Fep+lwYKdUw1uvRn1Xxv71jG8CQAM2IO7XHw2h1HetSDau+bDVhEZ
3LB1JX/5FOeVhYh9Lr4Rc4sjAoGBAJCTCv+oEtqyHOjc/Z5tBFXkwLCpCMCx5MFV
oIPI+BolOhGCzN9SjHiFQaWOaK9/J9dhPmH1qGDEaJkZp1yXvgK7ha23X9rCuy4+
XDUkul4tDBfIrs1flHUpB7+PK/ZSzgC4nJWKu12MVpHaCxirdYPpfdBZGyIm753N
GBNfCBtxAoGAKkrHlsfq7GVVU7Jj1AlNCwmlm21vSJ45G3cNR1GpgdplB5JR1ldV
2kxA4xm8uFVIJ60OQ9VZ5Svaovqh8iX2sndSOZMefjH3qiDu/4mJqRA3xV5ugon3
RAzinJzUU4tnk9pajOMD3FHOHvUO4hAJjVYEzqLIIRE7QhPuEpLevZ4=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation acert hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,11 @@
moon::ipsec stop
carol::ipsec stop
dave::ipsec stop
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
dave::iptables-restore < /etc/iptables.flush
moon::rm /etc/ipsec.d/acerts/carol-sales-finance.pem
moon::rm /etc/ipsec.d/acerts/dave-sales-expired.pem
moon::rm /etc/ipsec.d/acerts/dave-marketing.pem
moon::rm /etc/ipsec.d/private/aa.pem
moon::rm /etc/ipsec.d/aacerts/aa.pem

View File

@ -0,0 +1,9 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
dave::iptables-restore < /etc/iptables.rules
moon::ipsec start
carol::ipsec start
dave::ipsec start
carol::sleep 1
carol::ipsec up home
dave::ipsec up home

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou dave"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w-d.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol dave"

View File

@ -0,0 +1,12 @@
<p>The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>.
The authentication is based on <b>X.509 certificates</b>. To authorize clients,
<b>moon</b> expects attribute certificates sent inline in IKEv2 CERT payloads.
<b>Carol</b> has attribute certificates for both the <i>sales</i> and
the <i>finance</i> groups. The attribute certificate for <i>finance</i> is not
valid anymore, hence <b>carol</b> gets access to the <i>sales</i> connection
only.</p>
<p>Upon the successful establishment of the IPsec tunnel, <b>leftfirewall=yes</b>
automatically inserts iptables-based firewall rules that let pass the tunneled traffic.
In order to test both tunnel and firewall, <b>carol</b> tries to ping both
<b>alice</b> and <b>venus</b>, but only the ping for the <i>sales</i> related
host <b>venus</b> succeeds.</p>

View File

@ -0,0 +1,8 @@
carol::ipsec status 2> /dev/null::home.*ESTABLISHED.*carol@strongswan.org.*moon.strongswan.org::YES
moon:: ipsec status 2> /dev/null::finance.*: ESTABLISHED.*moon.strongswan.org.*dave@strongswan.org::NO
moon:: ipsec status 2> /dev/null::sales.*: ESTABLISHED.*moon.strongswan.org.*carol@strongswan.org::YES
moon::cat /var/log/daemon.log::constraint check failed: group membership to 'finance' required::YES
carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_req=1::NO
carol::ping -c 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_req=1::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn home
left=PH_IP_CAROL
leftcert=carolCert.pem
leftid=carol@strongswan.org
leftfirewall=yes
right=PH_IP_MOON
rightid=@moon.strongswan.org
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC8TCCAdkCAQEwgbCgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHaFe
pFwwWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZ6BG
MESkQjBAMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEW
MBQGA1UEAxMNc3Ryb25nU3dhbiBBQTANBgkqhkiG9w0BAQUFAAIISLuuiWM2O9Yw
IhgPMjAxNDAyMDcwODQyMDVaGA8yMDE0MDIwNzA5NDIwNVowGzAZBggrBgEFBQcK
BDENMAswCQwHZmluYW5jZTB/MHIGA1UdIwRrMGkLAerHOgJc+LbEweHarsJX9lKw
sKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4x
GzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIIFU5+Fa8cF2EwCQYDVR04BAIF
ADANBgkqhkiG9w0BAQUFAAOCAQEAaDwqM5BY9pXhlSlT3cpCJYsNCfk6T1nG5s5J
Dtgwojw0BVSoxKqcbpWdP09HOpBcwbPVk++I19wd5VsdHxtQ4/o2Hoevg4QWxUUx
t3qsdMDjg7U2iH+JppYsEDmXmx9k1hvV1OiEzHJKTDlZqXkhiItLatKSptTG3c0A
DdJVS05sdepzhkRGimE/QwO7nJ3v5ixFNIetgfbojbjhJPpNfXPIgMMHerK/hAlo
ekSwcmh9ufFuEXg8C0NunQqf6Z6FbxiUXUF9j7dvlEp3n5YFsv3WSMUjE3Sb7r8T
3e2A/LXb05ky0/SNebgS4fU9oi8acEgwN2Vqwu82hClwYAcHJg==
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC7zCCAdcCAQEwgbCgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHaFe
pFwwWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZ6BG
MESkQjBAMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEW
MBQGA1UEAxMNc3Ryb25nU3dhbiBBQTANBgkqhkiG9w0BAQUFAAIIYO/yp98Yxu4w
IhgPMjAxNDAyMDcxMDAxNTdaGA8yMDIyMDQyNjEwMDE1N1owGTAXBggrBgEFBQcK
BDELMAkwBwwFc2FsZXMwfzByBgNVHSMEazBpCwHqxzoCXPi2xMHh2q7CV/ZSsLCh
SaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRsw
GQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GCCBVOfhWvHBdhMAkGA1UdOAQCBQAw
DQYJKoZIhvcNAQEFBQADggEBAJA/duSysWae5X9JTC0BLY6gK8ggj5V9H3d60rM4
7A8HVQldWe5QwYIRZmLS0XhMVHWiIvXJHwue2Xgs8DyAqILSCKIKpCJRhqPIxHCh
bek1nzw2YzVaU+E37He5V9PSkkRFO9tRvELhW3t4Wya7p4l6MVFW9ETOOtUqZYmt
bxAq/XEFZl/aFb2FW2RoKjUZpwxbrccCaV1hKIxtNen2ro31dNd9YHXe+fE4Fc7r
FTwbhOg3QLvZDXmiZt3LCXdMKAhayLbuSVsycuEtac44OVSvKhJ8GYykTRRn67nU
qCFNDe266KTNDqUMilrHm3FYGkpFtREOBajH4EqdMAJSdXg=
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,32 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn finance
left=PH_IP_MOON
leftcert=moonCert.pem
leftid=@moon.strongswan.org
leftsubnet=10.1.0.10/32
leftfirewall=yes
right=%any
rightid=*@strongswan.org
rightgroups=finance
keyexchange=ikev2
auto=add
conn sales
left=PH_IP_MOON
leftcert=moonCert.pem
leftid=@moon.strongswan.org
leftsubnet=10.1.0.20/32
leftfirewall=yes
right=%any
rightgroups=sales
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIIFU5+Fa8cF2EwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UE
BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
Z1N3YW4gUm9vdCBDQTAeFw0xNDAyMDcwODUwMzVaFw0yMjA0MjYwODUwMzVaMEAx
CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRYwFAYDVQQD
Ew1zdHJvbmdTd2FuIEFBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
y6nSTRzCuTbfuv2FwnXC/R7+5L5WViVxBfCEkaxzW5GJJGTFFbSbpQJxWk603BJH
hlVAVj8jUNMKcOuj/l8UPNV8lcDslQfe/AZd6gqdCwP7uMsAQ3yWfkZZK1jxTdTP
dvcpLNozt7hmIroJVTGzmzI5YIvWbYT/zyEge6pEPaXr8IqYzdWFCUINTXUGEr/L
lt3IUKMTNnhabPHAbTIZ3i0c98Ci0ZzZjGx+JmVVvcY9lgNTjS2xaaklUCq2auR/
QzP7PxuSYkAF4qYhG7Ujeo7v4z79mXISFTlyqKe7k18wUKdf+7suyGczSRMP6+5N
jqNqab7l/SHwHQMVEE5ihwIDAQABoyMwITAfBgNVHSMEGDAWgBRdp91wBlEyfue2
bbO15eBg6i5N7zANBgkqhkiG9w0BAQUFAAOCAQEAakPgMKVjkQmpI1VROcetvZzM
ZHMWwdu9IcwNpi/8qs2qNh6wCYv9c4V6O4zRCB1u8TuAIQiwLNZgjk+OKKLzvUik
gBRogn/apXsvAtfu9ODv5GuS6F38OYWDu/c3fiCZB2MKTtmEro2EkxxMw4DkfJ02
R/xrhAnjeQlRQOChgQ3fHNmH9gVNaKXNq+JaoU2TfHFwuYMMe6q1L+vhOaBd58YA
6wPHOOLcIEaebHIqa4duAE5txJsZCEEySrr5stqo4j7929BAw+U6f+6Wb+UAEW6g
91PKAl5QVbAzgPFWoPkOTNdDOprT+B4eGx0EC2QTEtxxDv5589choF7BMRCzsQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAy6nSTRzCuTbfuv2FwnXC/R7+5L5WViVxBfCEkaxzW5GJJGTF
FbSbpQJxWk603BJHhlVAVj8jUNMKcOuj/l8UPNV8lcDslQfe/AZd6gqdCwP7uMsA
Q3yWfkZZK1jxTdTPdvcpLNozt7hmIroJVTGzmzI5YIvWbYT/zyEge6pEPaXr8IqY
zdWFCUINTXUGEr/Llt3IUKMTNnhabPHAbTIZ3i0c98Ci0ZzZjGx+JmVVvcY9lgNT
jS2xaaklUCq2auR/QzP7PxuSYkAF4qYhG7Ujeo7v4z79mXISFTlyqKe7k18wUKdf
+7suyGczSRMP6+5NjqNqab7l/SHwHQMVEE5ihwIDAQABAoIBAQCIvn5QfkYUG87+
eyirV2xTjdMw/Md1UfBgP4yTTsmpqr79K5fUqg5zLX+0VfJDbRaPEICBKCVrKDfz
d5QFwAsTiXf8CKwQqFdEunWmJfgppEQIYGzN40IciNloLHDghEnEI9GGpv9glLQn
DugjRprEUmWJ+HpB0LH9fc2Ums704Fcd8ud3bStCRxU1TA5VGBHmnyK5/n1Lb1oB
01LoW8ins8lATuV+MAaWZgmCbPajfXY9wQGq3IDMVlOUOTxRo742T1GTrwBZR8ot
mgs/Gs1XkJRC1x9Z9Z1Cej1iC5llv0zX8AUdejczGHQGHj1a1Dg8FpRneW6rrLyK
vvKR8jtRAoGBAOpyk63yCPM2LqU4US5aHXPoLyyGeo4v7okTKIuoUfosQ4XJvylM
lEYoFVFKYBKcXRQhmeWyILtto2BBDnG1HWAi1MbUWLxDNEYieurzJiv4i0XbR6cH
mLhMMlQyKmwLRF5v3EiupjKBZRk2iYcx4eeL3gsUWUzRPeWJHKDgYF4PAoGBAN5i
xyOsU/32gQ6vLQxt8us6n3OBr1PiFg8JIdADPnKOCxJ5uS8dkqOQHCMKyvS9MWrf
3Wj4MOBEgW7fBBAxkvjJdPhBW70/pGM46mb991dTHJ4gIAzGxgvJIqw/FjqEC7Oo
vWDRS4dxW56Rs2tdLn2GRvvlS3+3z90twqS/t6wJAoGBAJpzhzT2Gc1YaZxxIJI/
zd15HfLgWUbo7uWhGHoBFpiQpp8yDNzBVYFukLSwIeDA4FUN2dxH4GZ50ULtOP3S
Cps19yVR6W+Fep+lwYKdUw1uvRn1Xxv71jG8CQAM2IO7XHw2h1HetSDau+bDVhEZ
3LB1JX/5FOeVhYh9Lr4Rc4sjAoGBAJCTCv+oEtqyHOjc/Z5tBFXkwLCpCMCx5MFV
oIPI+BolOhGCzN9SjHiFQaWOaK9/J9dhPmH1qGDEaJkZp1yXvgK7ha23X9rCuy4+
XDUkul4tDBfIrs1flHUpB7+PK/ZSzgC4nJWKu12MVpHaCxirdYPpfdBZGyIm753N
GBNfCBtxAoGAKkrHlsfq7GVVU7Jj1AlNCwmlm21vSJ45G3cNR1GpgdplB5JR1ldV
2kxA4xm8uFVIJ60OQ9VZ5Svaovqh8iX2sndSOZMefjH3qiDu/4mJqRA3xV5ugon3
RAzinJzUU4tnk9pajOMD3FHOHvUO4hAJjVYEzqLIIRE7QhPuEpLevZ4=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation acert hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,8 @@
moon::ipsec stop
carol::ipsec stop
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
carol::rm /etc/ipsec.d/acerts/carol-sales.pem
carol::rm /etc/ipsec.d/acerts/carol-finance-expired.pem
moon::rm /etc/ipsec.d/private/aa.pem
moon::rm /etc/ipsec.d/aacerts/aa.pem

View File

@ -0,0 +1,6 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
moon::ipsec start
carol::ipsec start
carol::sleep 1
carol::ipsec up home

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice venus moon carol winnetou"
# Corresponding block diagram
#
DIAGRAM="a-v-m-c-w-d.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS=""
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol"

View File

@ -0,0 +1,12 @@
<p>The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each
to gateway <b>moon</b>. The authentication is based on <b>X.509 certificates</b>.
To authorize clients, <b>moon</b> expects attribute certificates sent inline in
IKEv2 CERT payloads. <b>Carol</b> provides a valid attribute certificate for
the group <i>sales</i>, but <b>dave</b> offers two invalid attribute
certificates: One is not for the <i>sales</i> group, and the other is issued by
an AA that has been expired.</p>
<p>Upon the successful establishment of the IPsec tunnels, <b>leftfirewall=yes</b>
automatically inserts iptables-based firewall rules that let pass the tunneled traffic.
In order to test both tunnel and firewall, both <b>carol</b> and <b>dave</b> try
to ping the client <b>alice</b> behind the gateway <b>moon</b>, but dave fails
to do so.</p>

View File

@ -0,0 +1,15 @@
carol::ipsec status 2> /dev/null::home.*ESTABLISHED.*carol@strongswan.org.*moon.strongswan.org::YES
dave:: ipsec status 2> /dev/null::home.*ESTABLISHED.*dave@strongswan.org.*moon.strongswan.org::NO
moon:: ipsec status 2> /dev/null::rw\[1]: ESTABLISHED.*moon.strongswan.org.*carol@strongswan.org::YES
moon:: ipsec status 2> /dev/null::rw\[2]: ESTABLISHED.*moon.strongswan.org.*dave@strongswan.org::NO
moon::cat /var/log/daemon.log::constraint check failed: group membership to 'sales' required::YES
carol::cat /var/log/daemon.log::sending attribute certificate issued by \"C=CH, O=Linux strongSwan, CN=strongSwan AA\"::YES
dave::cat /var/log/daemon.log::sending attribute certificate issued by \"C=CH, O=Linux strongSwan, CN=strongSwan AA\"::YES
dave::cat /var/log/daemon.log::sending attribute certificate issued by \"C=CH, O=Linux strongSwan, CN=expired AA\"::YES
dave::cat /var/log/daemon.log::received AUTHENTICATION_FAILED notify error::YES
carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_req=1::YES
dave:: ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_req=1::NO
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::NO
moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::NO

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn home
left=PH_IP_CAROL
leftcert=carolCert.pem
leftid=carol@strongswan.org
leftfirewall=yes
right=PH_IP_MOON
rightid=@moon.strongswan.org
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC7zCCAdcCAQEwgbCgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHaFe
pFwwWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZ6BG
MESkQjBAMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEW
MBQGA1UEAxMNc3Ryb25nU3dhbiBBQTANBgkqhkiG9w0BAQUFAAIIYO/yp98Yxu4w
IhgPMjAxNDAyMDcxMDAxNTdaGA8yMDIyMDQyNjEwMDE1N1owGTAXBggrBgEFBQcK
BDELMAkwBwwFc2FsZXMwfzByBgNVHSMEazBpCwHqxzoCXPi2xMHh2q7CV/ZSsLCh
SaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRsw
GQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GCCBVOfhWvHBdhMAkGA1UdOAQCBQAw
DQYJKoZIhvcNAQEFBQADggEBAJA/duSysWae5X9JTC0BLY6gK8ggj5V9H3d60rM4
7A8HVQldWe5QwYIRZmLS0XhMVHWiIvXJHwue2Xgs8DyAqILSCKIKpCJRhqPIxHCh
bek1nzw2YzVaU+E37He5V9PSkkRFO9tRvELhW3t4Wya7p4l6MVFW9ETOOtUqZYmt
bxAq/XEFZl/aFb2FW2RoKjUZpwxbrccCaV1hKIxtNen2ro31dNd9YHXe+fE4Fc7r
FTwbhOg3QLvZDXmiZt3LCXdMKAhayLbuSVsycuEtac44OVSvKhJ8GYykTRRn67nU
qCFNDe266KTNDqUMilrHm3FYGkpFtREOBajH4EqdMAJSdXg=
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn home
left=PH_IP_DAVE
leftcert=daveCert.pem
leftid=dave@strongswan.org
leftfirewall=yes
right=PH_IP_MOON
rightid=@moon.strongswan.org
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC7TCCAdUCAQEwgbGgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHKFf
pF0wWzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEzAR
BgNVBAsTCkFjY291bnRpbmcxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmeg
QzBBpD8wPTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4x
EzARBgNVBAMTCmV4cGlyZWQgQUEwDQYJKoZIhvcNAQEFBQACCG25qKzXgZ9HMCIY
DzIwMTQwMjA3MTAxMzQyWhgPMjAyMjA0MjYxMDEzNDJaMBkwFwYIKwYBBQUHCgQx
CzAJMAcMBXNhbGVzMH8wcgYDVR0jBGswabOoTOBJ6lXcG4NAowI32Y/oXa9/oUmk
RzBFMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkG
A1UEAxMSc3Ryb25nU3dhbiBSb290IENBgggqIkNljRd9CTAJBgNVHTgEAgUAMA0G
CSqGSIb3DQEBBQUAA4IBAQCfX/84tHCidlVbOU4is/1hZc+FpK4GG1jcywM9mtjB
QUeX28LYkewDdRpe49zJuTbvuIIABTp+4alf/oo7sKLk+o2/qq6CPfx8BSRL1a61
Y1wVeGmXqcRQgtX+r3asMtLBoAFO8VaHt6pY52bg2YMNVRrUnCUVLqQjT+/Ujr4f
Lhs74VOxn7S94YbqvP5rytNFjdzBREipmb8j4mhIyfwUluoWFCkzxuwRaSEGhSMO
NobJuj/mK0PUU+TMYEcOMpQ/nVyb9rBtOvDoNU3BeD+ovuamErT9/9vWhEOwMD4C
OeR+ofespDX+AdCyZ1Dr1GMyUmIRK7GERdasIhx5pYMk
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIC9DCCAdwCAQEwgbGgTjBJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExp
bnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQQIBHKFf
pF0wWzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEzAR
BgNVBAsTCkFjY291bnRpbmcxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmeg
RjBEpEIwQDELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4x
FjAUBgNVBAMTDXN0cm9uZ1N3YW4gQUEwDQYJKoZIhvcNAQEFBQACCCPxWgWKmOUM
MCIYDzIwMTQwMjA3MDg1OTM3WhgPMjAyMjA0MjYwODU5MzdaMB0wGwYIKwYBBQUH
CgQxDzANMAsMCW1hcmtldGluZzB/MHIGA1UdIwRrMGkLAerHOgJc+LbEweHarsJX
9lKwsKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIIFU5+Fa8cF2EwCQYDVR04
BAIFADANBgkqhkiG9w0BAQUFAAOCAQEAThlKhGVv34sfnCSQn6nYUdxMhboTuC98
+DgvTQ/tH0hddCJNg00SpO8AbStwEsqHFaSqFzAGHcMk+XUrBRSGszAwg8nKAKfT
MCvJbK6lWQcPF0WPSSk9/r1TLan4I9xhneNIIGQf1fnNo7NrQnmhJjolUgXQNwFA
qZgKBsk0jWcOSvI0bpK90km5flCHn/OA1rDCdaPuMwreDhvNDoApORYFPZVsLhid
CXSqT+FWfm2NfegS+Q4VHP3YLbY4vLepCerU9aMTUIPit0kf1N8piG/l6AUno1XP
VrcTvruQUWQb08H9aYt7l7kyhzOKkuXjVbdn5egZnK0m4WKmV50guA==
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn rw
left=PH_IP_MOON
leftcert=moonCert.pem
leftid=@moon.strongswan.org
leftsubnet=10.1.0.0/16
leftfirewall=yes
right=%any
rightgroups="finance, sales"
keyexchange=ikev2
auto=add

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDJzCCAg+gAwIBAgIIKiJDZY0XfQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UE
BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
Z1N3YW4gUm9vdCBDQTAeFw0xNDAyMDYwOTQ4NTJaFw0xNDAyMDcwOTQ4NTJaMD0x
CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRMwEQYDVQQD
EwpleHBpcmVkIEFBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0s5R
X2Y9KUSoNewtwOhQunET9VRGrVYS+xDewmIuAHZt4jhbETSHS+r/qipV4mI+/orS
zma0+GVcDwbHRT3oDCrpG/DMpPznki+OzHT9e/HHk0yxb0Ti6vDDbZOM8y3r7ak0
Dcq6BgGwPxwIW2u1YHRTj4yxlr5wj9iKU1SQGCwZIQZmjqrjoQlcrThIXju2bqN3
SOjuaN6A2GAvcbb/IeQEm8HBqulmyBuGV7Gk9umG/nr61rulNxEp+3Dsce5mv7JR
dX5W8P6pv38A/f31Bh/EetEkv8qdnkH0aVAvd8Kb2yxc8Ofdu0kJNoPHGjrnSywl
kPh3z2pw6nOFpyFHoQIDAQABoyMwITAfBgNVHSMEGDAWgBRdp91wBlEyfue2bbO1
5eBg6i5N7zANBgkqhkiG9w0BAQUFAAOCAQEAh9Sxryf5ip00ykCMStDYzQk27l4N
ncjU19RJqjrCuHupvWPJ+aYQFvssAnGGuK2rbw3rzVQba/Vn/o5d5wr1gxRtNQjv
z60jbqllmjF0TWvPf/CM/5LVAQJs2x5Mqtvy3pbNvetFHjZrzVDobdVJpqzaZGnh
oP0+HUMdE+fyLa0LfaRKYNv7r/vxvzsHZvgJawHK1b/2VWtrkIMyhAgHYViih06j
2bfVI/f5tk7/UljzLOCB22IFIn05wh4jyKq6az7B2Xu1Kk0/eA12eRqG134P8OYe
hAPcuj4QEDwV0ESw5cueD2I0MxbXuH2vBG5ziSBfw2Phj7f9iYurmMsZew==
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIIFU5+Fa8cF2EwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UE
BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
Z1N3YW4gUm9vdCBDQTAeFw0xNDAyMDcwODUwMzVaFw0yMjA0MjYwODUwMzVaMEAx
CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRYwFAYDVQQD
Ew1zdHJvbmdTd2FuIEFBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
y6nSTRzCuTbfuv2FwnXC/R7+5L5WViVxBfCEkaxzW5GJJGTFFbSbpQJxWk603BJH
hlVAVj8jUNMKcOuj/l8UPNV8lcDslQfe/AZd6gqdCwP7uMsAQ3yWfkZZK1jxTdTP
dvcpLNozt7hmIroJVTGzmzI5YIvWbYT/zyEge6pEPaXr8IqYzdWFCUINTXUGEr/L
lt3IUKMTNnhabPHAbTIZ3i0c98Ci0ZzZjGx+JmVVvcY9lgNTjS2xaaklUCq2auR/
QzP7PxuSYkAF4qYhG7Ujeo7v4z79mXISFTlyqKe7k18wUKdf+7suyGczSRMP6+5N
jqNqab7l/SHwHQMVEE5ihwIDAQABoyMwITAfBgNVHSMEGDAWgBRdp91wBlEyfue2
bbO15eBg6i5N7zANBgkqhkiG9w0BAQUFAAOCAQEAakPgMKVjkQmpI1VROcetvZzM
ZHMWwdu9IcwNpi/8qs2qNh6wCYv9c4V6O4zRCB1u8TuAIQiwLNZgjk+OKKLzvUik
gBRogn/apXsvAtfu9ODv5GuS6F38OYWDu/c3fiCZB2MKTtmEro2EkxxMw4DkfJ02
R/xrhAnjeQlRQOChgQ3fHNmH9gVNaKXNq+JaoU2TfHFwuYMMe6q1L+vhOaBd58YA
6wPHOOLcIEaebHIqa4duAE5txJsZCEEySrr5stqo4j7929BAw+U6f+6Wb+UAEW6g
91PKAl5QVbAzgPFWoPkOTNdDOprT+B4eGx0EC2QTEtxxDv5589choF7BMRCzsQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0s5RX2Y9KUSoNewtwOhQunET9VRGrVYS+xDewmIuAHZt4jhb
ETSHS+r/qipV4mI+/orSzma0+GVcDwbHRT3oDCrpG/DMpPznki+OzHT9e/HHk0yx
b0Ti6vDDbZOM8y3r7ak0Dcq6BgGwPxwIW2u1YHRTj4yxlr5wj9iKU1SQGCwZIQZm
jqrjoQlcrThIXju2bqN3SOjuaN6A2GAvcbb/IeQEm8HBqulmyBuGV7Gk9umG/nr6
1rulNxEp+3Dsce5mv7JRdX5W8P6pv38A/f31Bh/EetEkv8qdnkH0aVAvd8Kb2yxc
8Ofdu0kJNoPHGjrnSywlkPh3z2pw6nOFpyFHoQIDAQABAoIBAQCRRwiDM2VhBGTc
THi3oiLIaldz0fGnUVNhXR33XkwPm45cwbPY5pd7NWeecPChRE3fg/KFtfhv2wKX
hHdd+6zofcYKsGeIKJa6gzXpJ5LtkRGWLNt3MEUl3mkAIhiYGoSmU96Axr5ul0lM
JNiJkG/+GgzgN/jHR1UxfOzPQs7PKIyzCE2N0v8dRxHWeyPCRxSavlhAoQKjWxCe
FfVBzLi+L1faidcwf4GWyeTfhvALXQnQGgVPH6PX0z3mwaeYHPWVXWJGcaF0bi3H
HaEb2YexTDkEVU0PUVYO40OgtmKVLmi5t+ZP+/dFasy9elzgM3sSmVc7IBp6BBCH
NgUcWcf1AoGBAOiti9raozwdA/wHAMaCCbgXq8Dg0+3LYnb0ob7w8OaHRl4Mvpup
7MtxPGmr9IOddf8/49+L9STsioMllGt0TrkMrlKyg/eglGMalvbJmUYw1kERtQZw
0CYYE8DXR3fvN+eMl1maZ4Wf048UugWQhsRGzOyUKcMXhAlIXwTevnCfAoGBAOfv
isxrw5vttRxfszZaWeomos9bk6NA9FJYG1rS6ocR+Ww2OpQSJVTmbjpYv1lTb9yr
PvcZtPbWP/6g8kjPTQQ+ZnJQB4RpWek0KlxwxC6JW5HzqMJFn68zX4/jE5kXqVow
Y+Sfgrkr4QXX8vjzp9GFRhAW6bA5DlswqH7XmB+/AoGARHYDx3I7Q026RWZ+GOpc
F7mHRKoiUT5di2ixSrA0AXBeCQAw+TZHQRjhUKpSuIMVG/RdhQH2MFYU7z+YawF+
xD3x8M0rvSmXX42MS7LHkXp/IAgovmtlI0BEV6JAGg7d4Rhh0/B1c0Cyi8/qaAa9
UHUQiK+Tlh6OL/kGVDWBzTsCgYBTW5Jk+e4pontPIU4FoN9j+lLVd7JOIFAvMB9U
uy0zMlCUhcDz6rmkE9VV/wN2lThE9P8CTCjv9fy2BR5O8MJbXhnvx7eL7Vk1KVx4
MMcxeoiAojPq7p7/ltUnn5MxmIFzOqUMTA/tgUm0kfJvaxLLiLyvl6yRe1AfkhNc
0xuHfQKBgQCyQEcvtmR1Qx82ob5uTvBbKFDbSniiJMi9kgMk266PNRdg85Q4RC7X
j5KNALOb5u2oMT6/Hzi4KruDBc/6viXRuMYM+L1JIy8y6wcVjCQetxyUIGgc9Ouh
59bOkD+SOth52Y+AYFyCaJOSoTFHlTcLwCvk9gVdbgVYJi7/jyohSQ==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAy6nSTRzCuTbfuv2FwnXC/R7+5L5WViVxBfCEkaxzW5GJJGTF
FbSbpQJxWk603BJHhlVAVj8jUNMKcOuj/l8UPNV8lcDslQfe/AZd6gqdCwP7uMsA
Q3yWfkZZK1jxTdTPdvcpLNozt7hmIroJVTGzmzI5YIvWbYT/zyEge6pEPaXr8IqY
zdWFCUINTXUGEr/Llt3IUKMTNnhabPHAbTIZ3i0c98Ci0ZzZjGx+JmVVvcY9lgNT
jS2xaaklUCq2auR/QzP7PxuSYkAF4qYhG7Ujeo7v4z79mXISFTlyqKe7k18wUKdf
+7suyGczSRMP6+5NjqNqab7l/SHwHQMVEE5ihwIDAQABAoIBAQCIvn5QfkYUG87+
eyirV2xTjdMw/Md1UfBgP4yTTsmpqr79K5fUqg5zLX+0VfJDbRaPEICBKCVrKDfz
d5QFwAsTiXf8CKwQqFdEunWmJfgppEQIYGzN40IciNloLHDghEnEI9GGpv9glLQn
DugjRprEUmWJ+HpB0LH9fc2Ums704Fcd8ud3bStCRxU1TA5VGBHmnyK5/n1Lb1oB
01LoW8ins8lATuV+MAaWZgmCbPajfXY9wQGq3IDMVlOUOTxRo742T1GTrwBZR8ot
mgs/Gs1XkJRC1x9Z9Z1Cej1iC5llv0zX8AUdejczGHQGHj1a1Dg8FpRneW6rrLyK
vvKR8jtRAoGBAOpyk63yCPM2LqU4US5aHXPoLyyGeo4v7okTKIuoUfosQ4XJvylM
lEYoFVFKYBKcXRQhmeWyILtto2BBDnG1HWAi1MbUWLxDNEYieurzJiv4i0XbR6cH
mLhMMlQyKmwLRF5v3EiupjKBZRk2iYcx4eeL3gsUWUzRPeWJHKDgYF4PAoGBAN5i
xyOsU/32gQ6vLQxt8us6n3OBr1PiFg8JIdADPnKOCxJ5uS8dkqOQHCMKyvS9MWrf
3Wj4MOBEgW7fBBAxkvjJdPhBW70/pGM46mb991dTHJ4gIAzGxgvJIqw/FjqEC7Oo
vWDRS4dxW56Rs2tdLn2GRvvlS3+3z90twqS/t6wJAoGBAJpzhzT2Gc1YaZxxIJI/
zd15HfLgWUbo7uWhGHoBFpiQpp8yDNzBVYFukLSwIeDA4FUN2dxH4GZ50ULtOP3S
Cps19yVR6W+Fep+lwYKdUw1uvRn1Xxv71jG8CQAM2IO7XHw2h1HetSDau+bDVhEZ
3LB1JX/5FOeVhYh9Lr4Rc4sjAoGBAJCTCv+oEtqyHOjc/Z5tBFXkwLCpCMCx5MFV
oIPI+BolOhGCzN9SjHiFQaWOaK9/J9dhPmH1qGDEaJkZp1yXvgK7ha23X9rCuy4+
XDUkul4tDBfIrs1flHUpB7+PK/ZSzgC4nJWKu12MVpHaCxirdYPpfdBZGyIm753N
GBNfCBtxAoGAKkrHlsfq7GVVU7Jj1AlNCwmlm21vSJ45G3cNR1GpgdplB5JR1ldV
2kxA4xm8uFVIJ60OQ9VZ5Svaovqh8iX2sndSOZMefjH3qiDu/4mJqRA3xV5ugon3
RAzinJzUU4tnk9pajOMD3FHOHvUO4hAJjVYEzqLIIRE7QhPuEpLevZ4=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation acert hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,13 @@
moon::ipsec stop
carol::ipsec stop
dave::ipsec stop
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
dave::iptables-restore < /etc/iptables.flush
carol::rm /etc/ipsec.d/acerts/carol-sales.pem
dave::rm /etc/ipsec.d/acerts/dave-expired-aa.pem
dave::rm /etc/ipsec.d/acerts/dave-marketing.pem
moon::rm /etc/ipsec.d/private/aa-expired.pem
moon::rm /etc/ipsec.d/private/aa.pem
moon::rm /etc/ipsec.d/aacerts/aa-expired.pem
moon::rm /etc/ipsec.d/aacerts/aa.pem

View File

@ -0,0 +1,9 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
dave::iptables-restore < /etc/iptables.rules
moon::ipsec start
carol::ipsec start
dave::ipsec start
carol::sleep 1
carol::ipsec up home
dave::ipsec up home

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou dave"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w-d.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol dave"