From 883a63adc16bb38a6c9dd158ae383ae91cce5b40 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Feb 2014 14:41:30 +0100 Subject: [PATCH 01/30] ac: Remove unimplemented equals_holder() method from ac_t --- src/libstrongswan/credentials/certificates/ac.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/libstrongswan/credentials/certificates/ac.h b/src/libstrongswan/credentials/certificates/ac.h index 57b44adca..0bf762017 100644 --- a/src/libstrongswan/credentials/certificates/ac.h +++ b/src/libstrongswan/credentials/certificates/ac.h @@ -75,14 +75,6 @@ struct ac_t { * @return object containing a list of IETF attributes */ 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); }; #endif /** AC_H_ @}*/ From 3134379ac7f155366ea3df1fb8660bd2d513582b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Feb 2014 15:05:26 +0100 Subject: [PATCH 02/30] x509: Fix some whitespaces and do some minor style cleanups in acert --- src/libstrongswan/plugins/x509/x509_ac.c | 148 ++++++++++++----------- 1 file changed, 76 insertions(+), 72 deletions(-) diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 7d83e48ea..ab89abad0 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -169,42 +169,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; } /** @@ -250,57 +249,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,7 +367,8 @@ 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; } @@ -377,13 +377,15 @@ static bool parse_certificate(private_x509_ac_t *this) this->holderSerial = 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; } @@ -446,8 +448,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 +493,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 +502,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 +519,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 +537,6 @@ static chunk_t build_attr_cert_validity(private_x509_ac_t *this) asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME)); } - /** * build attribute type */ @@ -548,7 +553,8 @@ static chunk_t build_attribute_type(int type, chunk_t content) static chunk_t build_attributes(private_x509_ac_t *this) { return asn1_wrap(ASN1_SEQUENCE, "m", - build_attribute_type(OID_GROUP, this->groups->get_encoding(this->groups))); + build_attribute_type(OID_GROUP, + this->groups->get_encoding(this->groups))); } /** @@ -621,14 +627,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), @@ -692,7 +695,8 @@ METHOD(certificate_t, has_subject, id_match_t, 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 +812,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)) { @@ -968,4 +973,3 @@ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args) destroy(ac); return NULL; } - From a9bfd4b0553c6b2eed295ef4e0791563d0928e16 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Feb 2014 15:16:26 +0100 Subject: [PATCH 03/30] x509: Skip parsing of acert chargingIdentity, as we don't use it anyway --- src/libstrongswan/plugins/x509/x509_ac.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index ab89abad0..b7da97da4 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -97,11 +97,6 @@ struct private_x509_ac_t { */ time_t notAfter; - /** - * List of charging attributes - */ - ietf_attributes_t *charging; - /** * List of groub attributes */ @@ -416,9 +411,7 @@ 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, "-- > --"); @@ -837,7 +830,6 @@ METHOD(certificate_t, destroy, void, DESTROY_IF(this->holderCert); DESTROY_IF(this->signerCert); DESTROY_IF(this->signerKey); - DESTROY_IF(this->charging); DESTROY_IF(this->groups); free(this->serialNumber.ptr); free(this->authKeyIdentifier.ptr); From 61b2d815b9af23261c479b552fb86faf212387fe Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Feb 2014 15:41:09 +0100 Subject: [PATCH 04/30] x509: Replace fixed acert group string getter by a more dynamic group enumerator --- src/libcharon/plugins/stroke/stroke_list.c | 84 +++++++++++++++---- .../credentials/certificates/ac.h | 16 +++- .../ietf_attributes/ietf_attributes.c | 84 +++++++++---------- .../ietf_attributes/ietf_attributes.h | 10 ++- src/libstrongswan/plugins/x509/x509_ac.c | 6 +- 5 files changed, 131 insertions(+), 69 deletions(-) diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index ea168058f..991bed116 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -31,8 +31,9 @@ #include #include #include -#include #include +#include +#include /* 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, ¬Before, ¬After); + fprintf(out, " validity: not before %T, ", ¬Before, utc); + if (now < notBefore) { - fprintf(out, "expired (%V ago)\n", &now, &nextUpdate); + fprintf(out, "not valid yet (valid in %V)\n", &now, ¬Before); + } + else + { + fprintf(out, "ok\n"); + } + fprintf(out, " not after %T, ", ¬After, utc); + if (now > notAfter) + { + fprintf(out, "expired (%V ago)\n", &now, ¬After); } 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, ¬After); } fprintf(out, " \n"); } diff --git a/src/libstrongswan/credentials/certificates/ac.h b/src/libstrongswan/credentials/certificates/ac.h index 0bf762017..1094cdcfd 100644 --- a/src/libstrongswan/credentials/certificates/ac.h +++ b/src/libstrongswan/credentials/certificates/ac.h @@ -27,6 +27,16 @@ #include 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,11 +80,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); + enumerator_t* (*create_group_enumerator)(ac_t *this); }; #endif /** AC_H_ @}*/ diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c index 49af5a079..6efbfb70e 100644 --- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c +++ b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c @@ -19,49 +19,26 @@ #include #include #include +#include #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; + ac_group_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); }; /** @@ -72,11 +49,11 @@ 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) + if (this->type != AC_GROUP_TYPE_OID && other->type == AC_GROUP_TYPE_OID) { return -1; } - if (this->type == IETF_ATTRIBUTE_OID && other->type != IETF_ATTRIBUTE_OID) + if (this->type == AC_GROUP_TYPE_OID && other->type != AC_GROUP_TYPE_OID) { return 1; } @@ -100,13 +77,11 @@ static void ietf_attr_destroy(ietf_attr_t *this) /** * Creates an ietf_attr_t object. */ -static ietf_attr_t* ietf_attr_create(ietf_attribute_type_t type, chunk_t value) +static ietf_attr_t* ietf_attr_create(ac_group_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), ); @@ -175,12 +150,12 @@ METHOD(ietf_attributes_t, get_string, char*, switch (attr->type) { - case IETF_ATTRIBUTE_OCTETS: - case IETF_ATTRIBUTE_STRING: + case AC_GROUP_TYPE_OCTETS: + case AC_GROUP_TYPE_STRING: written = snprintf(pos, len, "%.*s", (int)attr->value.len, attr->value.ptr); break; - case IETF_ATTRIBUTE_OID: + case AC_GROUP_TYPE_OID: { int oid = asn1_known_oid(attr->value); @@ -214,6 +189,24 @@ METHOD(ietf_attributes_t, get_string, char*, return this->string; } +/** + * Filter function for attribute enumeration + */ +static bool attr_filter(void *null, ietf_attr_t **in, ac_group_type_t *type, + void *in2, chunk_t *out) +{ + *type = (*in)->type; + *out = (*in)->value; + return TRUE; +} + +METHOD(ietf_attributes_t, create_enumerator, enumerator_t*, + private_ietf_attributes_t *this) +{ + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)attr_filter, NULL, NULL); +} + METHOD(ietf_attributes_t, get_encoding, chunk_t, private_ietf_attributes_t *this) { @@ -243,13 +236,13 @@ METHOD(ietf_attributes_t, get_encoding, chunk_t, switch (attr->type) { - case IETF_ATTRIBUTE_OCTETS: + case AC_GROUP_TYPE_OCTETS: type = ASN1_OCTET_STRING; break; - case IETF_ATTRIBUTE_STRING: + case AC_GROUP_TYPE_STRING: type = ASN1_UTF8STRING; break; - case IETF_ATTRIBUTE_OID: + case AC_GROUP_TYPE_OID: type = ASN1_OID; break; } @@ -290,7 +283,7 @@ static bool equals(private_ietf_attributes_t *this, while (enum_a->enumerate(enum_a, &attr_a) && enum_b->enumerate(enum_b, &attr_b)) { - if (attr_a->compare(attr_a, attr_b) != 0) + if (ietf_attr_compare(attr_a, attr_b) != 0) { /* we have a mismatch */ result = FALSE; @@ -334,8 +327,9 @@ static bool matches(private_ietf_attributes_t *this, /* look for at least one common attribute */ while (TRUE) { - int cmp = attr_a->compare(attr_a, attr_b); + int cmp; + cmp = ietf_attr_compare(attr_a, attr_b); if (cmp == 0) { /* we have a match */ @@ -379,7 +373,7 @@ METHOD(ietf_attributes_t, destroy, void, { if (ref_put(&this->ref)) { - this->list->destroy_offset(this->list, offsetof(ietf_attr_t, destroy)); + this->list->destroy_function(this->list, (void*)ietf_attr_destroy); free(this->string); free(this); } @@ -392,6 +386,7 @@ static private_ietf_attributes_t* create_empty(void) INIT(this, .public = { .get_string = _get_string, + .create_enumerator = _create_enumerator, .get_encoding = _get_encoding, .equals = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))equals, .matches = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))matches, @@ -417,13 +412,13 @@ static void ietf_attributes_add(private_ietf_attributes_t *this, enumerator = this->list->create_enumerator(this->list); while (enumerator->enumerate(enumerator, (void **)¤t_attr) && - (cmp = attr->compare(attr, current_attr)) > 0) + (cmp = ietf_attr_compare(attr, current_attr)) > 0) { continue; } if (cmp == 0) { - attr->destroy(attr); + ietf_attr_destroy(attr); } else { /* the enumerator either points to the end or to the attribute > attr */ @@ -461,7 +456,7 @@ ietf_attributes_t *ietf_attributes_create_from_string(char *string) /* add the group attribute to the list */ if (group.len > 0) { - ietf_attr_t *attr = ietf_attr_create(IETF_ATTRIBUTE_STRING, group); + ietf_attr_t *attr = ietf_attr_create(AC_GROUP_TYPE_STRING, group); ietf_attributes_add(this, attr); } @@ -515,7 +510,7 @@ ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded) case IETF_ATTR_OID: case IETF_ATTR_STRING: { - ietf_attribute_type_t type; + ac_group_type_t type; ietf_attr_t *attr; type = (objectID - IETF_ATTR_OCTETS) / 2; @@ -531,4 +526,3 @@ ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded) return &(this->public); } - diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h index ab6bae984..a34b23a3d 100644 --- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h +++ b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h @@ -40,6 +40,13 @@ struct ietf_attributes_t { */ char* (*get_string) (ietf_attributes_t *this); + /** + * Create an enumerator over attributes. + * + * @return enumerator over (ac_group_type_t, chunk_t) + */ + enumerator_t* (*create_enumerator)(ietf_attributes_t *this); + /** * Get the ASN.1 encoding of the IETF attributes. * @@ -58,7 +65,7 @@ struct ietf_attributes_t { /** * Check for common attributes between two lists. * - * @param other attribute list to be matched + * @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); @@ -89,4 +96,3 @@ ietf_attributes_t *ietf_attributes_create_from_string(char *string); ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded); #endif /** IETF_ATTRIBUTES_H_ @}*/ - diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index b7da97da4..9845b21a8 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -655,10 +655,10 @@ METHOD(ac_t, get_authKeyIdentifier, chunk_t, return this->authKeyIdentifier; } -METHOD(ac_t, get_groups, ietf_attributes_t*, +METHOD(ac_t, create_group_enumerator, enumerator_t*, private_x509_ac_t *this) { - return this->groups ? this->groups->get_ref(this->groups) : NULL; + return this->groups->create_enumerator(this->groups); } METHOD(certificate_t, get_type, certificate_type_t, @@ -866,7 +866,7 @@ 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, }, }, .ref = 1, From a17598bc69926f69a87eaf60c29a81b8e0d1e203 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Feb 2014 16:11:37 +0100 Subject: [PATCH 05/30] x509: Integrate IETF attribute handling, and obsolete ietf_attributes_t The ietf_attributes_t class is used for attribute certificates only these days, and integrating them to x509_ac_t simplifies things significantly. --- src/libstrongswan/Android.mk | 2 +- src/libstrongswan/Makefile.am | 3 +- .../credentials/certificates/ac.h | 1 - .../ietf_attributes/ietf_attributes.c | 528 ------------------ .../ietf_attributes/ietf_attributes.h | 98 ---- src/libstrongswan/plugins/x509/x509_ac.c | 193 ++++++- 6 files changed, 186 insertions(+), 639 deletions(-) delete mode 100644 src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c delete mode 100644 src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 440913071..2b58db554 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -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 \ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index b3a4eda99..50cac493d 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -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 \ diff --git a/src/libstrongswan/credentials/certificates/ac.h b/src/libstrongswan/credentials/certificates/ac.h index 1094cdcfd..9a3d8f0b9 100644 --- a/src/libstrongswan/credentials/certificates/ac.h +++ b/src/libstrongswan/credentials/certificates/ac.h @@ -24,7 +24,6 @@ #include #include -#include typedef struct ac_t ac_t; typedef enum ac_group_type_t ac_group_type_t; diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c deleted file mode 100644 index 6efbfb70e..000000000 --- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c +++ /dev/null @@ -1,528 +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 . - * - * 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 -#include -#include -#include -#include -#include - -#include "ietf_attributes.h" - -typedef struct ietf_attr_t ietf_attr_t; - -/** - * Private definition of an IETF attribute - */ -struct ietf_attr_t { - - /** - * IETF attribute type - */ - ac_group_type_t type; - - /** - * IETF attribute value - */ - chunk_t value; -}; - -/** - * 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 != AC_GROUP_TYPE_OID && other->type == AC_GROUP_TYPE_OID) - { - return -1; - } - if (this->type == AC_GROUP_TYPE_OID && other->type != AC_GROUP_TYPE_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(ac_group_type_t type, chunk_t value) -{ - ietf_attr_t *this; - - INIT(this, - .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 AC_GROUP_TYPE_OCTETS: - case AC_GROUP_TYPE_STRING: - written = snprintf(pos, len, "%.*s", (int)attr->value.len, - attr->value.ptr); - break; - case AC_GROUP_TYPE_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; -} - -/** - * Filter function for attribute enumeration - */ -static bool attr_filter(void *null, ietf_attr_t **in, ac_group_type_t *type, - void *in2, chunk_t *out) -{ - *type = (*in)->type; - *out = (*in)->value; - return TRUE; -} - -METHOD(ietf_attributes_t, create_enumerator, enumerator_t*, - private_ietf_attributes_t *this) -{ - return enumerator_create_filter(this->list->create_enumerator(this->list), - (void*)attr_filter, NULL, NULL); -} - -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 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; - } - 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 (ietf_attr_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; - - cmp = ietf_attr_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_function(this->list, (void*)ietf_attr_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, - .create_enumerator = _create_enumerator, - .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 **)¤t_attr) && - (cmp = ietf_attr_compare(attr, current_attr)) > 0) - { - continue; - } - if (cmp == 0) - { - ietf_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(AC_GROUP_TYPE_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: - { - ac_group_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); -} diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h deleted file mode 100644 index a34b23a3d..000000000 --- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h +++ /dev/null @@ -1,98 +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 . - * - * 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 - -/** - * - */ -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); - - /** - * Create an enumerator over attributes. - * - * @return enumerator over (ac_group_type_t, chunk_t) - */ - enumerator_t* (*create_enumerator)(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_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 9845b21a8..410b2e5ce 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -29,7 +29,6 @@ #include #include #include -#include #include extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, @@ -98,9 +97,9 @@ struct private_x509_ac_t { time_t notAfter; /** - * List of groub attributes + * List of group attributes, as group_t */ - ietf_attributes_t *groups; + linked_list_t *groups; /** * Authority Key Identifier @@ -148,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, @@ -237,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 */ @@ -415,7 +501,10 @@ static bool parse_certificate(private_x509_ac_t *this) 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: @@ -545,9 +634,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))); } /** @@ -655,10 +790,28 @@ METHOD(ac_t, get_authKeyIdentifier, chunk_t, return this->authKeyIdentifier; } +/** + * 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->create_enumerator(this->groups); + return enumerator_create_filter( + this->groups->create_enumerator(this->groups), + (void*)attr_filter, NULL, NULL); } METHOD(certificate_t, get_type, certificate_type_t, @@ -830,7 +983,7 @@ METHOD(certificate_t, destroy, void, DESTROY_IF(this->holderCert); DESTROY_IF(this->signerCert); DESTROY_IF(this->signerKey); - 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,6 +1022,7 @@ static private_x509_ac_t *create_empty(void) .create_group_enumerator = _create_group_enumerator, }, }, + .groups = linked_list_create(), .ref = 1, ); @@ -910,6 +1064,27 @@ x509_ac_t *x509_ac_load(certificate_type_t type, va_list args) return NULL; } +/** + * Parse a comma separated group list into AC group memberships + */ +static void add_groups_from_string(private_x509_ac_t *this, char *str) +{ + enumerator_t *enumerator; + group_t *group; + char *name; + + enumerator = enumerator_create_token(str, ",", " "); + 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. */ @@ -932,7 +1107,7 @@ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args) 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*)); + add_groups_from_string(ac, va_arg(args, char*)); continue; case BUILD_CERT: ac->holderCert = va_arg(args, certificate_t*); From 8f9e2dbcd581c5d69cba45158d51495100b2e813 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Feb 2014 16:24:03 +0100 Subject: [PATCH 06/30] x509: Replace the comma separated string AC group builder with a list based one --- src/libstrongswan/credentials/builder.c | 3 +-- src/libstrongswan/credentials/builder.h | 4 ++-- src/libstrongswan/plugins/x509/x509_ac.c | 10 +++++----- src/openac/openac.c | 15 ++++++++++++++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index 4e52272a7..ddb64ef88 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -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", ); - diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index 103b823c0..627e0934d 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -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* */ diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 410b2e5ce..97e2a941e 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -1065,15 +1065,15 @@ x509_ac_t *x509_ac_load(certificate_type_t type, va_list args) } /** - * Parse a comma separated group list into AC group memberships + * Add groups from a list into AC group memberships */ -static void add_groups_from_string(private_x509_ac_t *this, char *str) +static void add_groups_from_list(private_x509_ac_t *this, linked_list_t *list) { enumerator_t *enumerator; group_t *group; char *name; - enumerator = enumerator_create_token(str, ",", " "); + enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, &name)) { INIT(group, @@ -1106,8 +1106,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: - add_groups_from_string(ac, 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*); diff --git a/src/openac/openac.c b/src/openac/openac.c index 8862e9ab0..1424a7e72 100644 --- a/src/openac/openac.c +++ b/src/openac/openac.c @@ -495,6 +495,18 @@ int main(int argc, char **argv) if (userCert != NULL && signerCert != NULL && signerKey != NULL && outfile != NULL) { + linked_list_t *group_list; + enumerator_t *enumerator; + char *group; + + group_list = linked_list_create(); + enumerator = enumerator_create_token(groups, ",", " "); + while (enumerator->enumerate(enumerator, &group)) + { + group_list->insert_last(group_list, strdup(group)); + } + enumerator->destroy(enumerator); + /* read the serial number and increment it by one */ serial = read_serial(); @@ -504,10 +516,11 @@ int main(int argc, char **argv) BUILD_NOT_BEFORE_TIME, notBefore, BUILD_NOT_AFTER_TIME, notAfter, BUILD_SERIAL, serial, - BUILD_IETF_GROUP_ATTR, groups, + BUILD_AC_GROUP_STRINGS, group_list, BUILD_SIGNING_CERT, signerCert, BUILD_SIGNING_KEY, signerKey, BUILD_END); + group_list->destroy_function(group_list, free); if (!attr_cert) { goto end; From 0226ca886deb82e2cecd72706bedbf471911fec1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 12:19:34 +0100 Subject: [PATCH 07/30] pem: Support encoding of attribute certificates While there is no widely used PEM header for attribute certificates, at least IAIK-JCE uses BEGIN ATTRIBUTE CERTIFICATE: http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/utils/Util.html#toPemString(iaik.x509.attr.AttributeCertificate) --- src/libstrongswan/plugins/pem/pem_encoder.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/plugins/pem/pem_encoder.c b/src/libstrongswan/plugins/pem/pem_encoder.c index 9c8237e4d..df4b77cc3 100644 --- a/src/libstrongswan/plugins/pem/pem_encoder.c +++ b/src/libstrongswan/plugins/pem/pem_encoder.c @@ -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; } - From e49197f15eef80f5559fcb631d4a4c51ae7867e7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 11:05:28 +0100 Subject: [PATCH 08/30] pki: Don't generate negative random serial numbers in X.509 certificates According to RFC 5280 4.1.2.2 we MUST force non-negative serial numbers. --- src/pki/commands/issue.c | 1 + src/pki/commands/self.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index d5c33b89f..c2a120fca 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -363,6 +363,7 @@ static int issue() rng->destroy(rng); goto end; } + serial.ptr[0] &= 0x7F; rng->destroy(rng); } diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index c28c9c291..7d4bf1cc6 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -314,6 +314,7 @@ static int self() rng->destroy(rng); goto end; } + serial.ptr[0] &= 0x7F; rng->destroy(rng); } not_before = time(NULL); From 20ea84daece25cb166328bcb9c60fd6a4cbb8043 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 12:24:03 +0100 Subject: [PATCH 09/30] pki: Support printing attribute certificates --- src/pki/commands/print.c | 90 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/src/pki/commands/print.c b/src/pki/commands/print.c index 077c1ef3e..5b00db23c 100644 --- a/src/pki/commands/print.c +++ b/src/pki/commands/print.c @@ -16,9 +16,11 @@ #include "pki.h" #include +#include #include #include #include +#include #include #include @@ -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"}, From 35a783cff7b2516c3282ed45c6fccff5160579d4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 12:28:00 +0100 Subject: [PATCH 10/30] pki: Implement an acert command to issue attribute certificates --- src/pki/Makefile.am | 1 + src/pki/command.h | 2 +- src/pki/commands/acert.c | 273 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 src/pki/commands/acert.c diff --git a/src/pki/Makefile.am b/src/pki/Makefile.am index efbed9b2b..266802cf7 100644 --- a/src/pki/Makefile.am +++ b/src/pki/Makefile.am @@ -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 diff --git a/src/pki/command.h b/src/pki/command.h index 737f4658d..deb1ba535 100644 --- a/src/pki/command.h +++ b/src/pki/command.h @@ -24,7 +24,7 @@ /** * Maximum number of commands (+1). */ -#define MAX_COMMANDS 11 +#define MAX_COMMANDS 12 /** * Maximum number of options in a command (+3) diff --git a/src/pki/commands/acert.c b/src/pki/commands/acert.c new file mode 100644 index 000000000..1d0315a1c --- /dev/null +++ b/src/pki/commands/acert.c @@ -0,0 +1,273 @@ +/* + * 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 . + * + * 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 +#include + +#include "pki.h" + +#include +#include +#include +#include +#include +#include + +/** + * 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; + 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); + if (!lifetime) + { + error = "invalid --lifetime value"; + goto usage; + } + 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 (!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; + } + + not_before = time(NULL); + not_after = not_before + lifetime * 60 * 60; + + 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 [--lifetime hours] [--serial hex]", + "[--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"}, + {"lifetime", 'l', 1, "hours the acert is valid, default: 24"}, + {"serial", 's', 1, "serial number in hex, default: random"}, + {"digest", 'g', 1, "digest for signature creation, default: sha1"}, + {"outform", 'f', 1, "encoding of generated cert, default: der"}, + } + }); +} From 6e8c665a51f5d4ded9c94e52f6edc3d0e8cc4e2d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 12:49:10 +0100 Subject: [PATCH 11/30] pki: Add acert and extend pki/print manpages --- configure.ac | 1 + src/pki/man/Makefile.am | 1 + src/pki/man/pki---acert.1.in | 107 +++++++++++++++++++++++++++++++++++ src/pki/man/pki---print.1.in | 5 +- src/pki/man/pki.1.in | 4 ++ 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/pki/man/pki---acert.1.in diff --git a/configure.ac b/configure.ac index 15d00bdab..3b37ac967 100644 --- a/configure.ac +++ b/configure.ac @@ -1619,6 +1619,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 ]) diff --git a/src/pki/man/Makefile.am b/src/pki/man/Makefile.am index 618bd4093..4c901ae3c 100644 --- a/src/pki/man/Makefile.am +++ b/src/pki/man/Makefile.am @@ -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 \ diff --git a/src/pki/man/pki---acert.1.in b/src/pki/man/pki---acert.1.in new file mode 100644 index 000000000..3e23366bc --- /dev/null +++ b/src/pki/man/pki---acert.1.in @@ -0,0 +1,107 @@ +.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 \-\-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. +.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) diff --git a/src/pki/man/pki---print.1.in b/src/pki/man/pki---print.1.in index 8d3345edc..434d4ea16 100644 --- a/src/pki/man/pki---print.1.in +++ b/src/pki/man/pki---print.1.in @@ -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) \ No newline at end of file +.BR pki (1) diff --git a/src/pki/man/pki.1.in b/src/pki/man/pki.1.in index 8dfc53af3..f347031b4 100644 --- a/src/pki/man/pki.1.in +++ b/src/pki/man/pki.1.in @@ -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), From b06283f1e39273a7e2d98af0fa99469ad3cf47bd Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 14:45:47 +0100 Subject: [PATCH 12/30] x509: Match acert has_subject() against entityName or holder serial This allows us to find attribute certificates for a subject certificate in credential sets. --- src/libstrongswan/plugins/x509/x509_ac.c | 30 ++++++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 97e2a941e..30b871d42 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -74,7 +74,7 @@ struct private_x509_ac_t { /** * Serial number of the holder certificate */ - chunk_t holderSerial; + identification_t *holderSerial; /** * ID representing the holder @@ -455,7 +455,8 @@ static bool parse_certificate(private_x509_ac_t *this) } 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, @@ -775,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*, @@ -823,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*, @@ -835,7 +844,17 @@ 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, @@ -978,6 +997,7 @@ 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); From 5ac0e6687973e03d891141d4a9682db6a8cb80a0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 16:59:55 +0100 Subject: [PATCH 13/30] acert: Implement a plugin finding, validating and evaluating attribute certs This validator checks for any attribute certificate it can find for validated end entity certificates and tries to extract group membership information used for connection authorization rules. --- configure.ac | 4 + src/libstrongswan/Makefile.am | 7 + src/libstrongswan/plugins/acert/Makefile.am | 17 ++ .../plugins/acert/acert_plugin.c | 99 ++++++++++++ .../plugins/acert/acert_plugin.h | 42 +++++ .../plugins/acert/acert_validator.c | 149 ++++++++++++++++++ .../plugins/acert/acert_validator.h | 49 ++++++ 7 files changed, 367 insertions(+) create mode 100644 src/libstrongswan/plugins/acert/Makefile.am create mode 100644 src/libstrongswan/plugins/acert/acert_plugin.c create mode 100644 src/libstrongswan/plugins/acert/acert_plugin.h create mode 100644 src/libstrongswan/plugins/acert/acert_validator.c create mode 100644 src/libstrongswan/plugins/acert/acert_validator.h diff --git a/configure.ac b/configure.ac index 3b37ac967..bdcf397dd 100644 --- a/configure.ac +++ b/configure.ac @@ -165,6 +165,7 @@ ARG_ENABL_SET([mysql], [enable MySQL database support. Requires libmysq ARG_ENABL_SET([sqlite], [enable SQLite database support. Requires libsqlite3.]) # authentication/credential plugins ARG_ENABL_SET([addrblock], [enables RFC 3779 address block constraint support.]) +ARG_ENABL_SET([acert], [enable X509 attribute certificate checking plugin.]) ARG_ENABL_SET([agent], [enables the ssh-agent signing plugin.]) ARG_DISBL_SET([constraints], [disable advanced X509 constraint checking plugin.]) ARG_ENABL_SET([coupling], [enable IKEv2 plugin to couple peer certificates permanently to authentication.]) @@ -1090,6 +1091,7 @@ ADD_PLUGIN([nonce], [s charon nm cmd]) ADD_PLUGIN([x509], [s charon openac scepclient pki scripts attest nm cmd]) ADD_PLUGIN([revocation], [s charon nm cmd]) ADD_PLUGIN([constraints], [s charon nm cmd]) +ADD_PLUGIN([acert], [s charon]) ADD_PLUGIN([pubkey], [s charon cmd]) ADD_PLUGIN([pkcs1], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([pkcs7], [s charon scepclient pki scripts nm cmd]) @@ -1229,6 +1231,7 @@ AM_CONDITIONAL(USE_NONCE, test x$nonce = xtrue) AM_CONDITIONAL(USE_X509, test x$x509 = xtrue) AM_CONDITIONAL(USE_REVOCATION, test x$revocation = xtrue) AM_CONDITIONAL(USE_CONSTRAINTS, test x$constraints = xtrue) +AM_CONDITIONAL(USE_ACERT, test x$acert = xtrue) AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue) AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue) AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue) @@ -1454,6 +1457,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/x509/Makefile src/libstrongswan/plugins/revocation/Makefile src/libstrongswan/plugins/constraints/Makefile + src/libstrongswan/plugins/acert/Makefile src/libstrongswan/plugins/pubkey/Makefile src/libstrongswan/plugins/pkcs1/Makefile src/libstrongswan/plugins/pkcs7/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 50cac493d..3462d2ffc 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -307,6 +307,13 @@ if MONOLITHIC endif endif +if USE_ACERT + SUBDIRS += plugins/acert +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/acert/libstrongswan-acert.la +endif +endif + if USE_PUBKEY SUBDIRS += plugins/pubkey if MONOLITHIC diff --git a/src/libstrongswan/plugins/acert/Makefile.am b/src/libstrongswan/plugins/acert/Makefile.am new file mode 100644 index 000000000..ba16f413a --- /dev/null +++ b/src/libstrongswan/plugins/acert/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = \ + -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-acert.la +else +plugin_LTLIBRARIES = libstrongswan-acert.la +endif + +libstrongswan_acert_la_SOURCES = \ + acert_validator.h acert_validator.c \ + acert_plugin.h acert_plugin.c + +libstrongswan_acert_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/acert/acert_plugin.c b/src/libstrongswan/plugins/acert/acert_plugin.c new file mode 100644 index 000000000..01d9ae3b8 --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_plugin.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "acert_plugin.h" +#include "acert_validator.h" + +#include + +typedef struct private_acert_plugin_t private_acert_plugin_t; + +/** + * private data of acert_plugin + */ +struct private_acert_plugin_t { + + /** + * public functions + */ + acert_plugin_t public; + + /** + * Validator implementation instance. + */ + acert_validator_t *validator; +}; + +METHOD(plugin_t, get_name, char*, + private_acert_plugin_t *this) +{ + return "acert"; +} + +/** + * Register validator + */ +static bool plugin_cb(private_acert_plugin_t *this, + plugin_feature_t *feature, bool reg, void *cb_data) +{ + if (reg) + { + lib->credmgr->add_validator(lib->credmgr, &this->validator->validator); + } + else + { + lib->credmgr->remove_validator(lib->credmgr, &this->validator->validator); + } + return TRUE; +} + +METHOD(plugin_t, get_features, int, + private_acert_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL), + PLUGIN_PROVIDE(CUSTOM, "acert"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_acert_plugin_t *this) +{ + this->validator->destroy(this->validator); + free(this); +} + +/* + * see header file + */ +plugin_t *acert_plugin_create() +{ + private_acert_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + .validator = acert_validator_create(), + ); + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/acert/acert_plugin.h b/src/libstrongswan/plugins/acert/acert_plugin.h new file mode 100644 index 000000000..97d12936d --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup acert acert + * @ingroup plugins + * + * @defgroup acert_plugin acert_plugin + * @{ @ingroup acert + */ + +#ifndef ACERT_PLUGIN_H_ +#define ACERT_PLUGIN_H_ + +#include + +typedef struct acert_plugin_t acert_plugin_t; + +/** + * X.509 attribute certificate group membership checking. + */ +struct acert_plugin_t { + + /** + * Implements plugin_t. interface. + */ + plugin_t plugin; +}; + +#endif /** ACERT_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/acert/acert_validator.c b/src/libstrongswan/plugins/acert/acert_validator.c new file mode 100644 index 000000000..ab15dba98 --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_validator.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE +#include + +#include "acert_validator.h" + +#include +#include + +typedef struct private_acert_validator_t private_acert_validator_t; + +/** + * Private data of an acert_validator_t object. + */ +struct private_acert_validator_t { + + /** + * Public acert_validator_t interface. + */ + acert_validator_t public; +}; + +/** + * Check if an AC can be trusted + */ +static bool verify(private_acert_validator_t *this, certificate_t *ac) +{ + certificate_t *issuer; + enumerator_t *enumerator; + bool verified = FALSE; + + if (!ac->get_validity(ac, NULL, NULL, NULL)) + { + return FALSE; + } + DBG1(DBG_CFG, "verifying attribute certificate issued by \"%Y\"", + ac->get_issuer(ac)); + enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr, KEY_ANY, + ac->get_issuer(ac), TRUE); + while (enumerator->enumerate(enumerator, &issuer, NULL)) + { + if (issuer->get_validity(issuer, NULL, NULL, NULL)) + { + if (lib->credmgr->issued_by(lib->credmgr, ac, issuer, NULL)) + { + verified = TRUE; + break; + } + } + } + enumerator->destroy(enumerator); + + return verified; +} + +/** + * Apply AC group membership to auth config + */ +static void apply(private_acert_validator_t *this, ac_t *ac, auth_cfg_t *auth) +{ + enumerator_t *enumerator; + ac_group_type_t type; + chunk_t chunk; + + enumerator = ac->create_group_enumerator(ac); + while (enumerator->enumerate(enumerator, &type, &chunk)) + { + if (type == AC_GROUP_TYPE_STRING) + { + auth->add(auth, AUTH_RULE_GROUP, + identification_create_from_data(chunk)); + } + } + enumerator->destroy(enumerator); +} + +METHOD(cert_validator_t, validate, bool, + private_acert_validator_t *this, certificate_t *subject, + certificate_t *issuer, bool online, u_int pathlen, bool anchor, + auth_cfg_t *auth) +{ + /* for X.509 end entity certs only */ + if (pathlen == 0 && subject->get_type(subject) == CERT_X509) + { + x509_t *x509 = (x509_t*)subject; + enumerator_t *enumerator; + identification_t *id, *serial; + ac_t *ac; + + /* find attribute certificates by serial and issuer. A lookup by + * the holder DN would work as well, but RFC 5755 recommends the use + * of baseCertificateID. */ + serial = identification_create_from_encoding(ID_KEY_ID, + x509->get_serial(x509)); + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_X509_AC, KEY_ANY, serial, FALSE); + while (enumerator->enumerate(enumerator, &ac)) + { + id = ac->get_holderIssuer(ac); + if (id && id->equals(id, subject->get_issuer(subject))) + { + if (verify(this, &ac->certificate)) + { + apply(this, ac, auth); + } + } + } + enumerator->destroy(enumerator); + serial->destroy(serial); + } + return TRUE; +} + +METHOD(acert_validator_t, destroy, void, + private_acert_validator_t *this) +{ + free(this); +} + +/** + * See header + */ +acert_validator_t *acert_validator_create() +{ + private_acert_validator_t *this; + + INIT(this, + .public = { + .validator.validate = _validate, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/libstrongswan/plugins/acert/acert_validator.h b/src/libstrongswan/plugins/acert/acert_validator.h new file mode 100644 index 000000000..507776f18 --- /dev/null +++ b/src/libstrongswan/plugins/acert/acert_validator.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup acert_validator acert_validator + * @{ @ingroup acert + */ + +#ifndef ACERT_VALIDATOR_H_ +#define ACERT_VALIDATOR_H_ + +#include + +typedef struct acert_validator_t acert_validator_t; + +/** + * Attribute certificate group membership checking + */ +struct acert_validator_t { + + /** + * Implements cert_validator_t interface. + */ + cert_validator_t validator; + + /** + * Destroy a acert_validator_t. + */ + void (*destroy)(acert_validator_t *this); +}; + +/** + * Create a acert_validator instance. + */ +acert_validator_t *acert_validator_create(); + +#endif /** ACERT_VALIDATOR_H_ @}*/ From 83f8cdde4631272fdf69ccf2a9ee573a40faae65 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 17:15:45 +0100 Subject: [PATCH 14/30] auth-cfg: Declare an attribute certificate helper type to exchange acerts --- src/libstrongswan/credentials/auth_cfg.c | 12 +++++++++++- src/libstrongswan/credentials/auth_cfg.h | 2 ++ .../credentials/sets/auth_cfg_wrapper.c | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 2203519e2..4ff9aa6dd 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -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)); diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index d87935589..95b36d706 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -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, diff --git a/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c index 46bfb5c6e..c6b8d0c7e 100644 --- a/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c +++ b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c @@ -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; } From f316116c882e50d4c9e10b651a4a7a1235aa6027 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 17:46:01 +0100 Subject: [PATCH 15/30] ike: Support encoding of attribute certificates in CERT payloads --- src/libcharon/encoding/payloads/cert_payload.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index a32f5705d..05d41051b 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -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; } - From a14f7edfb28e48b97ca6deb80dd82ea0d76847aa Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 17:25:48 +0100 Subject: [PATCH 16/30] ikev2: Slightly refactor certificate payload construction to separate functions --- src/libcharon/sa/ikev2/tasks/ike_cert_post.c | 93 ++++++++++++-------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_post.c b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c index a93e5137e..1d1402bc7 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_cert_post.c +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c @@ -104,6 +104,58 @@ 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 certificates to message */ @@ -111,6 +163,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 +183,12 @@ 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); } - 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; } } From d417900335969a570aed49b41eecbe0b233d2c48 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 17:48:35 +0100 Subject: [PATCH 17/30] ikev2: Send all known and valid attribute certificates for subject cert --- src/libcharon/sa/ikev2/tasks/ike_cert_post.c | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_post.c b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c index 1d1402bc7..6dbc4dec3 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_cert_post.c +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c @@ -22,6 +22,7 @@ #include #include #include +#include typedef struct private_ike_cert_post_t private_ike_cert_post_t; @@ -156,6 +157,50 @@ static void add_im_certs(private_ike_cert_post_t *this, auth_cfg_t *auth, 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 */ @@ -187,6 +232,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) if (add_subject_cert(this, auth, message)) { add_im_certs(this, auth, message); + add_attribute_certs(this, auth, message); } break; } From 3a2deb98bcedfdeb1debc952c969cb9d1f52328c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Feb 2014 17:56:05 +0100 Subject: [PATCH 18/30] ikev2: Cache all received attribute certificates to auth config --- src/libcharon/sa/ikev2/tasks/ike_cert_pre.c | 28 ++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c index bd28b29d7..558b1e914 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c @@ -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: From c602ee65dc3bd42f221f9641fe5f9eab6e7634a3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 7 Feb 2014 10:26:08 +0100 Subject: [PATCH 19/30] testing: build strongSwan with acert plugin --- testing/scripts/recipes/013_strongswan.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/scripts/recipes/013_strongswan.mk b/testing/scripts/recipes/013_strongswan.mk index 438e6668a..c4142086f 100644 --- a/testing/scripts/recipes/013_strongswan.mk +++ b/testing/scripts/recipes/013_strongswan.mk @@ -76,6 +76,7 @@ CONFIG_OPTS = \ --enable-unbound \ --enable-ipseckey \ --enable-dnscert \ + --enable-acert \ --enable-cmd \ --enable-libipsec \ --enable-kernel-libipsec \ From 9f676321a9067e4b64df80966c9cb5db5dd49333 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 7 Feb 2014 10:28:50 +0100 Subject: [PATCH 20/30] testing: Add an acert test using locally cached attribute certificates --- .../tests/ikev2/acert-cached/description.txt | 11 ++++++++ testing/tests/ikev2/acert-cached/evaltest.dat | 12 +++++++++ .../acert-cached/hosts/carol/etc/ipsec.conf | 20 ++++++++++++++ .../hosts/carol/etc/strongswan.conf | 5 ++++ .../acert-cached/hosts/dave/etc/ipsec.conf | 20 ++++++++++++++ .../hosts/dave/etc/strongswan.conf | 5 ++++ .../acert-cached/hosts/moon/etc/ipsec.conf | 20 ++++++++++++++ .../hosts/moon/etc/ipsec.d/aacerts/aa.pem | 19 +++++++++++++ .../ipsec.d/acerts/carol-sales-finance.pem | 18 +++++++++++++ .../etc/ipsec.d/acerts/dave-marketing.pem | 18 +++++++++++++ .../etc/ipsec.d/acerts/dave-sales-expired.pem | 18 +++++++++++++ .../hosts/moon/etc/ipsec.d/private/aa.pem | 27 +++++++++++++++++++ .../hosts/moon/etc/strongswan.conf | 5 ++++ testing/tests/ikev2/acert-cached/posttest.dat | 11 ++++++++ testing/tests/ikev2/acert-cached/pretest.dat | 9 +++++++ testing/tests/ikev2/acert-cached/test.conf | 21 +++++++++++++++ 16 files changed, 239 insertions(+) create mode 100644 testing/tests/ikev2/acert-cached/description.txt create mode 100644 testing/tests/ikev2/acert-cached/evaltest.dat create mode 100644 testing/tests/ikev2/acert-cached/hosts/carol/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-cached/hosts/carol/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-cached/hosts/dave/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-cached/hosts/dave/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/aacerts/aa.pem create mode 100644 testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/carol-sales-finance.pem create mode 100644 testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-marketing.pem create mode 100644 testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-sales-expired.pem create mode 100644 testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/private/aa.pem create mode 100644 testing/tests/ikev2/acert-cached/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-cached/posttest.dat create mode 100644 testing/tests/ikev2/acert-cached/pretest.dat create mode 100644 testing/tests/ikev2/acert-cached/test.conf diff --git a/testing/tests/ikev2/acert-cached/description.txt b/testing/tests/ikev2/acert-cached/description.txt new file mode 100644 index 000000000..42f7432bc --- /dev/null +++ b/testing/tests/ikev2/acert-cached/description.txt @@ -0,0 +1,11 @@ +

The roadwarriors carol and dave set up a connection each +to gateway moon. The authentication is based on X.509 certificates. +To authorize clients, moon uses locally cached attribute certificates. +While for carol a valid attribute certificate for the group sales +is available, dave's attribute certificates are either expired or +do not grant permissions for the sales group.

+

Upon the successful establishment of the IPsec tunnels, leftfirewall=yes +automatically inserts iptables-based firewall rules that let pass the tunneled traffic. +In order to test both tunnel and firewall, both carol and dave try +to ping the client alice behind the gateway moon, but dave fails +to do so.

diff --git a/testing/tests/ikev2/acert-cached/evaltest.dat b/testing/tests/ikev2/acert-cached/evaltest.dat new file mode 100644 index 000000000..682c55ce2 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/evaltest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-cached/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/acert-cached/hosts/carol/etc/ipsec.conf new file mode 100644 index 000000000..e72f78742 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/carol/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-cached/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/acert-cached/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..dc937641c --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/carol/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-cached/hosts/dave/etc/ipsec.conf b/testing/tests/ikev2/acert-cached/hosts/dave/etc/ipsec.conf new file mode 100644 index 000000000..65c9819bb --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/dave/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-cached/hosts/dave/etc/strongswan.conf b/testing/tests/ikev2/acert-cached/hosts/dave/etc/strongswan.conf new file mode 100644 index 000000000..dc937641c --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/dave/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..fbffbad62 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/aacerts/aa.pem b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/aacerts/aa.pem new file mode 100644 index 000000000..fbfa7ee8b --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/aacerts/aa.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/carol-sales-finance.pem b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/carol-sales-finance.pem new file mode 100644 index 000000000..406c15700 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/carol-sales-finance.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-marketing.pem b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-marketing.pem new file mode 100644 index 000000000..2f646c39d --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-marketing.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-sales-expired.pem b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-sales-expired.pem new file mode 100644 index 000000000..d42038469 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/acerts/dave-sales-expired.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/private/aa.pem b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/private/aa.pem new file mode 100644 index 000000000..a4e001791 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/moon/etc/ipsec.d/private/aa.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-cached/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/acert-cached/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..cd836a2b7 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/hosts/moon/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-cached/posttest.dat b/testing/tests/ikev2/acert-cached/posttest.dat new file mode 100644 index 000000000..e5b8d291c --- /dev/null +++ b/testing/tests/ikev2/acert-cached/posttest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-cached/pretest.dat b/testing/tests/ikev2/acert-cached/pretest.dat new file mode 100644 index 000000000..8bbea1412 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/pretest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-cached/test.conf b/testing/tests/ikev2/acert-cached/test.conf new file mode 100644 index 000000000..f29298850 --- /dev/null +++ b/testing/tests/ikev2/acert-cached/test.conf @@ -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" From 1a4d3222be0a47c90b482bdd241c6c7e377b5e4d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 7 Feb 2014 11:22:39 +0100 Subject: [PATCH 21/30] testing: Add an acert test case sending attribute certificates inline --- .../tests/ikev2/acert-inline/description.txt | 12 +++++++++ testing/tests/ikev2/acert-inline/evaltest.dat | 15 +++++++++++ .../acert-inline/hosts/carol/etc/ipsec.conf | 20 ++++++++++++++ .../carol/etc/ipsec.d/acerts/carol-sales.pem | 18 +++++++++++++ .../hosts/carol/etc/strongswan.conf | 5 ++++ .../acert-inline/hosts/dave/etc/ipsec.conf | 20 ++++++++++++++ .../etc/ipsec.d/acerts/dave-expired-aa.pem | 18 +++++++++++++ .../etc/ipsec.d/acerts/dave-marketing.pem | 18 +++++++++++++ .../hosts/dave/etc/strongswan.conf | 5 ++++ .../acert-inline/hosts/moon/etc/ipsec.conf | 20 ++++++++++++++ .../moon/etc/ipsec.d/aacerts/aa-expired.pem | 19 +++++++++++++ .../hosts/moon/etc/ipsec.d/aacerts/aa.pem | 19 +++++++++++++ .../moon/etc/ipsec.d/private/aa-expired.pem | 27 +++++++++++++++++++ .../hosts/moon/etc/ipsec.d/private/aa.pem | 27 +++++++++++++++++++ .../hosts/moon/etc/strongswan.conf | 5 ++++ testing/tests/ikev2/acert-inline/posttest.dat | 13 +++++++++ testing/tests/ikev2/acert-inline/pretest.dat | 9 +++++++ testing/tests/ikev2/acert-inline/test.conf | 21 +++++++++++++++ 18 files changed, 291 insertions(+) create mode 100644 testing/tests/ikev2/acert-inline/description.txt create mode 100644 testing/tests/ikev2/acert-inline/evaltest.dat create mode 100644 testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem create mode 100644 testing/tests/ikev2/acert-inline/hosts/carol/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-expired-aa.pem create mode 100644 testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-marketing.pem create mode 100644 testing/tests/ikev2/acert-inline/hosts/dave/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa-expired.pem create mode 100644 testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa.pem create mode 100644 testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa-expired.pem create mode 100644 testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa.pem create mode 100644 testing/tests/ikev2/acert-inline/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-inline/posttest.dat create mode 100644 testing/tests/ikev2/acert-inline/pretest.dat create mode 100644 testing/tests/ikev2/acert-inline/test.conf diff --git a/testing/tests/ikev2/acert-inline/description.txt b/testing/tests/ikev2/acert-inline/description.txt new file mode 100644 index 000000000..948b84725 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/description.txt @@ -0,0 +1,12 @@ +

The roadwarriors carol and dave set up a connection each +to gateway moon. The authentication is based on X.509 certificates. +To authorize clients, moon expects attribute certificates sent inline in +IKEv2 CERT payloads. Carol provides a valid attribute certificate for +the group sales, but dave offers two invalid attribute +certificates: One is not for the sales group, and the other is issued by +an AA that has been expired.

+

Upon the successful establishment of the IPsec tunnels, leftfirewall=yes +automatically inserts iptables-based firewall rules that let pass the tunneled traffic. +In order to test both tunnel and firewall, both carol and dave try +to ping the client alice behind the gateway moon, but dave fails +to do so.

diff --git a/testing/tests/ikev2/acert-inline/evaltest.dat b/testing/tests/ikev2/acert-inline/evaltest.dat new file mode 100644 index 000000000..ba448f81b --- /dev/null +++ b/testing/tests/ikev2/acert-inline/evaltest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.conf new file mode 100644 index 000000000..e72f78742 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem b/testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem new file mode 100644 index 000000000..a188a1d3d --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-inline/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/acert-inline/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..dc937641c --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/carol/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.conf b/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.conf new file mode 100644 index 000000000..65c9819bb --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-expired-aa.pem b/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-expired-aa.pem new file mode 100644 index 000000000..e612607aa --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-expired-aa.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-marketing.pem b/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-marketing.pem new file mode 100644 index 000000000..2f646c39d --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/dave/etc/ipsec.d/acerts/dave-marketing.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-inline/hosts/dave/etc/strongswan.conf b/testing/tests/ikev2/acert-inline/hosts/dave/etc/strongswan.conf new file mode 100644 index 000000000..dc937641c --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/dave/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..e3abea51f --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa-expired.pem b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa-expired.pem new file mode 100644 index 000000000..20336fd79 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa-expired.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa.pem b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa.pem new file mode 100644 index 000000000..fbfa7ee8b --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/aacerts/aa.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa-expired.pem b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa-expired.pem new file mode 100644 index 000000000..0e694c4f1 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa-expired.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa.pem b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa.pem new file mode 100644 index 000000000..a4e001791 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/moon/etc/ipsec.d/private/aa.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-inline/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/acert-inline/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..cd836a2b7 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/hosts/moon/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-inline/posttest.dat b/testing/tests/ikev2/acert-inline/posttest.dat new file mode 100644 index 000000000..a0ef98440 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/posttest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-inline/pretest.dat b/testing/tests/ikev2/acert-inline/pretest.dat new file mode 100644 index 000000000..8bbea1412 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/pretest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-inline/test.conf b/testing/tests/ikev2/acert-inline/test.conf new file mode 100644 index 000000000..f29298850 --- /dev/null +++ b/testing/tests/ikev2/acert-inline/test.conf @@ -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" From babd8487786c2f6f0bb32cad990dcee275b79a7d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 7 Feb 2014 11:51:08 +0100 Subject: [PATCH 22/30] testing: Add an acert test that forces a fallback connection based on groups --- .../ikev2/acert-fallback/description.txt | 12 +++++++ .../tests/ikev2/acert-fallback/evaltest.dat | 8 +++++ .../acert-fallback/hosts/carol/etc/ipsec.conf | 20 ++++++++++++ .../ipsec.d/acerts/carol-finance-expired.pem | 18 +++++++++++ .../carol/etc/ipsec.d/acerts/carol-sales.pem | 18 +++++++++++ .../hosts/carol/etc/strongswan.conf | 5 +++ .../acert-fallback/hosts/moon/etc/ipsec.conf | 32 +++++++++++++++++++ .../hosts/moon/etc/ipsec.d/aacerts/aa.pem | 19 +++++++++++ .../hosts/moon/etc/ipsec.d/private/aa.pem | 27 ++++++++++++++++ .../hosts/moon/etc/strongswan.conf | 5 +++ .../tests/ikev2/acert-fallback/posttest.dat | 8 +++++ .../tests/ikev2/acert-fallback/pretest.dat | 6 ++++ testing/tests/ikev2/acert-fallback/test.conf | 21 ++++++++++++ 13 files changed, 199 insertions(+) create mode 100644 testing/tests/ikev2/acert-fallback/description.txt create mode 100644 testing/tests/ikev2/acert-fallback/evaltest.dat create mode 100644 testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-finance-expired.pem create mode 100644 testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem create mode 100644 testing/tests/ikev2/acert-fallback/hosts/carol/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.conf create mode 100644 testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/aacerts/aa.pem create mode 100644 testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/private/aa.pem create mode 100644 testing/tests/ikev2/acert-fallback/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/ikev2/acert-fallback/posttest.dat create mode 100644 testing/tests/ikev2/acert-fallback/pretest.dat create mode 100644 testing/tests/ikev2/acert-fallback/test.conf diff --git a/testing/tests/ikev2/acert-fallback/description.txt b/testing/tests/ikev2/acert-fallback/description.txt new file mode 100644 index 000000000..0008b105a --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/description.txt @@ -0,0 +1,12 @@ +

The roadwarrior carol sets up a connection to gateway moon. +The authentication is based on X.509 certificates. To authorize clients, +moon expects attribute certificates sent inline in IKEv2 CERT payloads. +Carol has attribute certificates for both the sales and +the finance groups. The attribute certificate for finance is not +valid anymore, hence carol gets access to the sales connection +only.

+

Upon the successful establishment of the IPsec tunnel, leftfirewall=yes +automatically inserts iptables-based firewall rules that let pass the tunneled traffic. +In order to test both tunnel and firewall, carol tries to ping both +alice and venus, but only the ping for the sales related +host venus succeeds.

diff --git a/testing/tests/ikev2/acert-fallback/evaltest.dat b/testing/tests/ikev2/acert-fallback/evaltest.dat new file mode 100644 index 000000000..985f3208e --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/evaltest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.conf new file mode 100644 index 000000000..e72f78742 --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-finance-expired.pem b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-finance-expired.pem new file mode 100644 index 000000000..3be000a3d --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-finance-expired.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem new file mode 100644 index 000000000..a188a1d3d --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/ipsec.d/acerts/carol-sales.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-fallback/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..dc937641c --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/carol/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..37e779fef --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.conf @@ -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 diff --git a/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/aacerts/aa.pem b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/aacerts/aa.pem new file mode 100644 index 000000000..fbfa7ee8b --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/aacerts/aa.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/private/aa.pem b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/private/aa.pem new file mode 100644 index 000000000..a4e001791 --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/ipsec.d/private/aa.pem @@ -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----- diff --git a/testing/tests/ikev2/acert-fallback/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..cd836a2b7 --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/hosts/moon/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/acert-fallback/posttest.dat b/testing/tests/ikev2/acert-fallback/posttest.dat new file mode 100644 index 000000000..2ccb86a41 --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/posttest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-fallback/pretest.dat b/testing/tests/ikev2/acert-fallback/pretest.dat new file mode 100644 index 000000000..baacc1605 --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/pretest.dat @@ -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 diff --git a/testing/tests/ikev2/acert-fallback/test.conf b/testing/tests/ikev2/acert-fallback/test.conf new file mode 100644 index 000000000..a6c21de09 --- /dev/null +++ b/testing/tests/ikev2/acert-fallback/test.conf @@ -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" From 06d3b6e9c98ed5064a3063db7a85cf38df28adf1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 27 Mar 2014 14:46:41 +0100 Subject: [PATCH 23/30] pki: Add a certificate lifetime calculation helper function --- src/pki/pki.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/pki/pki.h | 17 +++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/pki/pki.c b/src/pki/pki.c index eb614dd7f..ae4ef1cb0 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -13,9 +13,11 @@ * for more details. */ +#define _GNU_SOURCE #include "command.h" #include "pki.h" +#include #include #include @@ -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); } - diff --git a/src/pki/pki.h b/src/pki/pki.h index 09c50c6c2..616fac44a 100644 --- a/src/pki/pki.h +++ b/src/pki/pki.h @@ -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_ @}*/ From 6f90e8e6647e6d5c244140320ed29014f8c85aa5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 27 Mar 2014 14:47:18 +0100 Subject: [PATCH 24/30] pki: Support absolute --not-before/after acert lifetimes --- src/pki/commands/acert.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/pki/commands/acert.c b/src/pki/commands/acert.c index 1d0315a1c..d49365db5 100644 --- a/src/pki/commands/acert.c +++ b/src/pki/commands/acert.c @@ -39,7 +39,8 @@ static int acert() 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; + time_t not_before, not_after, lifetime = 24 * 60 * 60; + char *datenb = NULL, *datena = NULL, *dateform = NULL; rng_t *rng; char *arg; @@ -75,13 +76,22 @@ static int acert() keyid = arg; continue; case 'l': - lifetime = atoi(arg); + 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; @@ -100,6 +110,14 @@ static int acert() } break; } + + if (!calculate_lifetime(dateform, datenb, datena, lifetime, + ¬_before, ¬_after)) + { + error = "invalid --not-before/after datetime"; + goto usage; + } + if (!issuercert) { error = "--issuercert is required"; @@ -195,9 +213,6 @@ static int acert() goto end; } - not_before = time(NULL); - not_after = not_before + lifetime * 60 * 60; - ac = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_CERT, cert, @@ -255,7 +270,8 @@ static void __attribute__ ((constructor))reg() acert, 'z', "acert", "issue an attribute certificate", {"[--in file] [--group name]* --issuerkey file|--issuerkeyid hex", - " --issuercert file [--lifetime hours] [--serial 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"}, @@ -264,8 +280,11 @@ static void __attribute__ ((constructor))reg() {"issuercert", 'c', 1, "issuer certificate file"}, {"issuerkey", 'k', 1, "issuer private key file"}, {"issuerkeyid", 'x', 1, "keyid on smartcard of issuer private key"}, - {"lifetime", 'l', 1, "hours the acert is valid, default: 24"}, {"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"}, } From aa8732eb6832695de49cb3f9f741eeb35217c936 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 27 Mar 2014 15:45:32 +0100 Subject: [PATCH 25/30] pki: Support absolute --not-before/after self-signed certificate lifetimes --- src/pki/commands/self.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index 7d4bf1cc6..b684d54a7 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -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, + ¬_before, ¬_after)) + { + error = "invalid --not-before/after datetime"; + goto usage; + } id = identification_create_from_string(dn); if (id->get_type(id) != ID_DER_ASN1_DN) { @@ -317,8 +333,6 @@ static int self() 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, @@ -406,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"}, From d6e921181abfdd7dc89f0d16016bea5e098e562e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 27 Mar 2014 15:45:52 +0100 Subject: [PATCH 26/30] pki: Support absolute --not-before/after issued certificate lifetimes --- src/pki/command.h | 2 +- src/pki/commands/issue.c | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/pki/command.h b/src/pki/command.h index deb1ba535..9cf036bf2 100644 --- a/src/pki/command.h +++ b/src/pki/command.h @@ -29,7 +29,7 @@ /** * Maximum number of options in a command (+3) */ -#define MAX_OPTIONS 32 +#define MAX_OPTIONS 36 /** * Maximum number of usage summary lines (+1) diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index c2a120fca..8d38e2c5a 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -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, + ¬_before, ¬_after)) + { + error = "invalid --not-before/after datetime"; + goto usage; + } if (dn && *dn) { id = identification_create_from_string(dn); @@ -455,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, @@ -553,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"}, From 2769a22e1f9ed0dda63933254264bf9c4e3ef888 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 27 Mar 2014 15:56:20 +0100 Subject: [PATCH 27/30] pki: Support absolute --this/next-update CRL lifetimes --- src/pki/commands/signcrl.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/pki/commands/signcrl.c b/src/pki/commands/signcrl.c index 4f9dd291d..c9eebbf59 100644 --- a/src/pki/commands/signcrl.c +++ b/src/pki/commands/signcrl.c @@ -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"}, From 3941d55f0116b12646efaba6ed00ec09b5a246c2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 27 Mar 2014 16:12:29 +0100 Subject: [PATCH 28/30] pki: Document --not-before/after and --dateform options in manpages --- src/pki/man/pki---acert.1.in | 25 ++++++++++++++++++++++++- src/pki/man/pki---issue.1.in | 27 +++++++++++++++++++++++++-- src/pki/man/pki---self.1.in | 27 +++++++++++++++++++++++++-- src/pki/man/pki---signcrl.1.in | 27 +++++++++++++++++++++++++-- 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/src/pki/man/pki---acert.1.in b/src/pki/man/pki---acert.1.in index 3e23366bc..ec1d8be6e 100644 --- a/src/pki/man/pki---acert.1.in +++ b/src/pki/man/pki---acert.1.in @@ -12,6 +12,8 @@ pki \-\-acert \- Issue an attribute certificate .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 @@ -69,7 +71,28 @@ is required. Issuer certificate file. Required. .TP .BI "\-l, \-\-lifetime " hours -Hours the attribute certificate is valid, default: 24. +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. diff --git a/src/pki/man/pki---issue.1.in b/src/pki/man/pki---issue.1.in index 3fad1ae8a..375cb2fe4 100644 --- a/src/pki/man/pki---issue.1.in +++ b/src/pki/man/pki---issue.1.in @@ -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) \ No newline at end of file +.BR pki (1) diff --git a/src/pki/man/pki---self.1.in b/src/pki/man/pki---self.1.in index ee42cf9a0..5e6e78bd0 100644 --- a/src/pki/man/pki---self.1.in +++ b/src/pki/man/pki---self.1.in @@ -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) \ No newline at end of file +.BR pki (1) diff --git a/src/pki/man/pki---signcrl.1.in b/src/pki/man/pki---signcrl.1.in index 6ba96f6bc..bd6cba547 100644 --- a/src/pki/man/pki---signcrl.1.in +++ b/src/pki/man/pki---signcrl.1.in @@ -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) \ No newline at end of file +.BR pki (1) From dbd4fc074a791538e460d5ec29919c843721ede4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 31 Mar 2014 11:30:51 +0200 Subject: [PATCH 29/30] openac: Remove obsolete openac utility The same functionality is now provided by the pki --acert subcommand. --- conf/options/tools.opt | 3 - configure.ac | 43 +- .../debian/strongswan-tools.install | 2 - src/Makefile.am | 2 +- src/checksum/Makefile.am | 1 - src/ipsec/_ipsec.in | 1 - src/openac/.gitignore | 1 - src/openac/Makefile.am | 11 - src/openac/openac.8 | 165 ----- src/openac/openac.c | 564 ------------------ 10 files changed, 21 insertions(+), 772 deletions(-) delete mode 100644 src/openac/.gitignore delete mode 100644 src/openac/Makefile.am delete mode 100644 src/openac/openac.8 delete mode 100644 src/openac/openac.c diff --git a/conf/options/tools.opt b/conf/options/tools.opt index 23e6a1c9f..72a49de28 100644 --- a/conf/options/tools.opt +++ b/conf/options/tools.opt @@ -1,6 +1,3 @@ -openac.load = - Plugins to load in ipsec openac tool. - pki.load = Plugins to load in ipsec pki tool. diff --git a/configure.ac b/configure.ac index bdcf397dd..e8eb5a67c 100644 --- a/configure.ac +++ b/configure.ac @@ -265,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.]) @@ -1053,7 +1053,6 @@ charon_plugins= starter_plugins= pool_plugins= attest_plugins= -openac_plugins= scepclient_plugins= pki_plugins= scripts_plugins= @@ -1069,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]) @@ -1077,38 +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]) @@ -1190,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) @@ -1586,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 diff --git a/packages/strongswan/debian/strongswan-tools.install b/packages/strongswan/debian/strongswan-tools.install index 353a7db8d..1b7872d86 100644 --- a/packages/strongswan/debian/strongswan-tools.install +++ b/packages/strongswan/debian/strongswan-tools.install @@ -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/ diff --git a/src/Makefile.am b/src/Makefile.am index 7d11893d1..93da4893f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -73,7 +73,7 @@ if USE_UPDOWN endif if USE_TOOLS - SUBDIRS += openac scepclient pki + SUBDIRS += scepclient pki endif if USE_CONFTEST diff --git a/src/checksum/Makefile.am b/src/checksum/Makefile.am index d172b1545..82bbadcf1 100644 --- a/src/checksum/Makefile.am +++ b/src/checksum/Makefile.am @@ -100,7 +100,6 @@ if USE_CMD endif if USE_TOOLS - exes += $(DESTDIR)$(ipsecdir)/openac exes += $(DESTDIR)$(ipsecdir)/scepclient exes += $(DESTDIR)$(bindir)/pki endif diff --git a/src/ipsec/_ipsec.in b/src/ipsec/_ipsec.in index 3c1f99825..61632188a 100644 --- a/src/ipsec/_ipsec.in +++ b/src/ipsec/_ipsec.in @@ -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" diff --git a/src/openac/.gitignore b/src/openac/.gitignore deleted file mode 100644 index 9aa85775f..000000000 --- a/src/openac/.gitignore +++ /dev/null @@ -1 +0,0 @@ -openac diff --git a/src/openac/Makefile.am b/src/openac/Makefile.am deleted file mode 100644 index 78a466bd6..000000000 --- a/src/openac/Makefile.am +++ /dev/null @@ -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 diff --git a/src/openac/openac.8 b/src/openac/openac.8 deleted file mode 100644 index ed1b8ed6c..000000000 --- a/src/openac/openac.8 +++ /dev/null @@ -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 mailing list. diff --git a/src/openac/openac.c b/src/openac/openac.c deleted file mode 100644 index 1424a7e72..000000000 --- a/src/openac/openac.c +++ /dev/null @@ -1,564 +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 . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#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 ]" - " [--quiet]" - " \\\n\t" - " [--debug ]" - " \\\n\t" - " [--days ]" - " [--hours ]" - " \\\n\t" - " [--startdate ]" - " [--enddate ]" - " \\\n\t" - " --cert " - " --key " - " [--password ]" - " \\\n\t" - " --usercert " - " --groups " - " --out " - "\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 */ - { - 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(" 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(" 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) - { - linked_list_t *group_list; - enumerator_t *enumerator; - char *group; - - group_list = linked_list_create(); - enumerator = enumerator_create_token(groups, ",", " "); - while (enumerator->enumerate(enumerator, &group)) - { - group_list->insert_last(group_list, strdup(group)); - } - enumerator->destroy(enumerator); - - /* 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_AC_GROUP_STRINGS, group_list, - BUILD_SIGNING_CERT, signerCert, - BUILD_SIGNING_KEY, signerKey, - BUILD_END); - group_list->destroy_function(group_list, free); - 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); -} From 8101e6aa17228164bf3b7d4dc81e2488fa86ccd5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 31 Mar 2014 11:23:22 +0200 Subject: [PATCH 30/30] NEWS: Add acert and pki changes for 5.1.3 --- NEWS | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/NEWS b/NEWS index 0d22295d4..9dd0ed1b4 100644 --- a/NEWS +++ b/NEWS @@ -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 ----------------