From c8a0781334a1ebb43b31c613a0538d3ea364bf4c Mon Sep 17 00:00:00 2001 From: Thomas Egerer Date: Mon, 1 Feb 2016 18:15:15 +0100 Subject: [PATCH 1/6] ikev2: Diversify signature scheme rule This allows for different signature schemes for IKE authentication and trustchain verification. Signed-off-by: Thomas Egerer --- .../authenticators/pubkey_authenticator.c | 5 +- src/libcharon/sa/ikev2/tasks/ike_init.c | 2 +- src/libstrongswan/credentials/auth_cfg.c | 96 +++++++++++++------ src/libstrongswan/credentials/auth_cfg.h | 2 + 4 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c index 2929033aa..64cd775ad 100644 --- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -130,7 +130,7 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, enumerator = auth->create_enumerator(auth); while (enumerator->enumerate(enumerator, &rule, &config)) { - if (rule != AUTH_RULE_SIGNATURE_SCHEME) + if (rule != AUTH_RULE_IKE_SIGNATURE_SCHEME) { continue; } @@ -427,7 +427,8 @@ METHOD(authenticator_t, process, status_t, auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); if (this->store_signature_scheme) { - auth->add(auth, AUTH_RULE_SIGNATURE_SCHEME, (uintptr_t)scheme); + auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME, + (uintptr_t)scheme); } break; } diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c index 5cfb51807..78579be95 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_init.c +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -171,7 +171,7 @@ static void send_supported_hash_algorithms(private_ike_init_t *this, enumerator = auth->create_enumerator(auth); while (enumerator->enumerate(enumerator, &rule, &config)) { - if (rule == AUTH_RULE_SIGNATURE_SCHEME) + if (rule == AUTH_RULE_IKE_SIGNATURE_SCHEME) { hash = hasher_from_signature_scheme(config); if (hasher_algorithm_for_ikev2(hash)) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index e2047e88f..2f18cb6cd 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -51,6 +51,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_AC_CERT, "RULE_ECDSA_STRENGTH", "RULE_BLISS_STRENGTH", "RULE_SIGNATURE_SCHEME", + "RULE_IKE_SIGNATURE_SCHEME", "RULE_CERT_POLICY", "HELPER_IM_CERT", "HELPER_SUBJECT_CERT", @@ -91,6 +92,7 @@ static inline bool is_multi_value_rule(auth_rule_t type) case AUTH_RULE_IM_CERT: case AUTH_RULE_CERT_POLICY: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: case AUTH_HELPER_IM_CERT: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_REVOCATION_CERT: @@ -211,6 +213,7 @@ static void init_entry(entry_t *this, auth_rule_t type, va_list args) case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: /* integer type */ this->value = (void*)(uintptr_t)va_arg(args, u_int); break; @@ -260,6 +263,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2) case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: { return e1->value == e2->value; } @@ -351,6 +355,7 @@ static void destroy_entry_value(entry_t *entry) case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: case AUTH_RULE_MAX: break; } @@ -383,6 +388,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator, case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: /* integer type */ entry->value = (void*)(uintptr_t)va_arg(args, u_int); break; @@ -459,6 +465,7 @@ METHOD(auth_cfg_t, get, void*, case AUTH_RULE_BLISS_STRENGTH: return (void*)0; case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: return (void*)HASH_UNKNOWN; case AUTH_RULE_CRL_VALIDATION: case AUTH_RULE_OCSP_VALIDATION: @@ -619,6 +626,50 @@ METHOD(auth_cfg_t, add_pubkey_constraints, void, enumerator->destroy(enumerator); } +/** + * Check if signature schemes of a specific type are compliant + */ +static bool complies_scheme(private_auth_cfg_t *this, auth_cfg_t *constraints, + auth_rule_t type, bool log_error) +{ + enumerator_t *e1, *e2; + auth_rule_t t1, t2; + signature_scheme_t scheme; + void *value; + bool success = TRUE; + + e2 = create_enumerator(this); + while (e2->enumerate(e2, &t2, &scheme)) + { + if (t2 == type) + { + success = FALSE; + e1 = constraints->create_enumerator(constraints); + while (e1->enumerate(e1, &t1, &value)) + { + if (t1 == type && (uintptr_t)value == scheme) + { + success = TRUE; + break; + } + } + e1->destroy(e1); + if (!success) + { + if (log_error) + { + DBG1(DBG_CFG, "%s signature scheme %N not acceptable", + AUTH_RULE_SIGNATURE_SCHEME == type ? "X.509" : "IKE", + signature_scheme_names, (int)scheme); + } + break; + } + } + } + e2->destroy(e2); + return success; +} + METHOD(auth_cfg_t, complies, bool, private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error) { @@ -627,7 +678,7 @@ METHOD(auth_cfg_t, complies, bool, bool ca_match = FALSE, cert_match = FALSE; identification_t *require_group = NULL; certificate_t *require_ca = NULL, *require_cert = NULL; - signature_scheme_t scheme = SIGN_UNKNOWN; + signature_scheme_t ike_scheme = SIGN_UNKNOWN, scheme = SIGN_UNKNOWN; u_int strength = 0; auth_rule_t t1, t2; char *key_type; @@ -823,6 +874,11 @@ METHOD(auth_cfg_t, complies, bool, strength = (uintptr_t)value; break; } + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + { + ike_scheme = (uintptr_t)value; + break; + } case AUTH_RULE_SIGNATURE_SCHEME: { scheme = (uintptr_t)value; @@ -875,35 +931,13 @@ METHOD(auth_cfg_t, complies, bool, * signature schemes. */ if (success && scheme != SIGN_UNKNOWN) { - e2 = create_enumerator(this); - while (e2->enumerate(e2, &t2, &scheme)) - { - if (t2 == AUTH_RULE_SIGNATURE_SCHEME) - { - success = FALSE; - e1 = constraints->create_enumerator(constraints); - while (e1->enumerate(e1, &t1, &value)) - { - if (t1 == AUTH_RULE_SIGNATURE_SCHEME && - (uintptr_t)value == scheme) - { - success = TRUE; - break; - } - } - e1->destroy(e1); - if (!success) - { - if (log_error) - { - DBG1(DBG_CFG, "signature scheme %N not acceptable", - signature_scheme_names, (int)scheme); - } - break; - } - } - } - e2->destroy(e2); + success = complies_scheme(this, constraints, + AUTH_RULE_SIGNATURE_SCHEME, log_error); + } + if (success && ike_scheme != SIGN_UNKNOWN) + { + success = complies_scheme(this, constraints, + AUTH_RULE_IKE_SIGNATURE_SCHEME, log_error); } /* Check if we have a matching constraint (or none at all) for used @@ -1027,6 +1061,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: { add(this, type, (uintptr_t)value); break; @@ -1197,6 +1232,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: clone->add(clone, type, (uintptr_t)value); break; case AUTH_RULE_MAX: diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index 07e5a6bd3..f00e64f7e 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -106,6 +106,8 @@ enum auth_rule_t { AUTH_RULE_BLISS_STRENGTH, /** required signature scheme, signature_scheme_t */ AUTH_RULE_SIGNATURE_SCHEME, + /** required signature scheme for IKE authentication, signature_scheme_t */ + AUTH_RULE_IKE_SIGNATURE_SCHEME, /** certificatePolicy constraint, numerical OID as char* */ AUTH_RULE_CERT_POLICY, From e37e6d6dcaee842b6d8a5be2d271f560f86fabcc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 1 Feb 2016 18:15:57 +0100 Subject: [PATCH 2/6] ikev2: Always store signature scheme in auth-cfg As we use a different rule we can always store the scheme. --- .../sa/ikev2/authenticators/pubkey_authenticator.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c index 64cd775ad..110c50973 100644 --- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -55,11 +55,6 @@ struct private_pubkey_authenticator_t { * Reserved bytes of ID payload */ char reserved[3]; - - /** - * Whether to store signature schemes on remote auth configs. - */ - bool store_signature_scheme; }; /** @@ -425,11 +420,7 @@ METHOD(authenticator_t, process, status_t, status = SUCCESS; auth->merge(auth, current_auth, FALSE); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); - if (this->store_signature_scheme) - { - auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME, - (uintptr_t)scheme); - } + auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME, (uintptr_t)scheme); break; } else @@ -502,8 +493,6 @@ pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, .ike_sa = ike_sa, .ike_sa_init = received_init, .nonce = sent_nonce, - .store_signature_scheme = lib->settings->get_bool(lib->settings, - "%s.signature_authentication_constraints", TRUE, lib->ns), ); memcpy(this->reserved, reserved, sizeof(this->reserved)); From 3c23a75120c5b548383da439537cab956b15dafd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 1 Feb 2016 18:16:16 +0100 Subject: [PATCH 3/6] auth-cfg: Make IKE signature schemes configurable This also restores the charon.signature_authentication_constraints functionality, that is, if no explicit IKE signature schemes are configured we apply all regular signature constraints as IKE constraints. --- man/ipsec.conf.5.in | 13 +- src/libcharon/plugins/stroke/stroke_config.c | 7 +- src/libcharon/plugins/vici/vici_config.c | 5 +- src/libstrongswan/credentials/auth_cfg.c | 96 ++++++++------ src/libstrongswan/credentials/auth_cfg.h | 4 +- src/libstrongswan/tests/Makefile.am | 1 + .../tests/suites/test_auth_cfg.c | 122 ++++++++++++++++++ src/libstrongswan/tests/tests.h | 1 + 8 files changed, 203 insertions(+), 46 deletions(-) create mode 100644 src/libstrongswan/tests/suites/test_auth_cfg.c diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index 61804c8b3..f070eaa59 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -587,18 +587,23 @@ or a key strength definition (for example or .BR rsa-2048-ecdsa-256-sha256-sha384-sha512 ). Unless disabled in -.BR strongswan.conf (5) -such key types and hash algorithms are also applied as constraints against IKEv2 +.BR strongswan.conf (5), +or explicit IKEv2 signature constraints are configured (see below), such key +types and hash algorithms are also applied as constraints against IKEv2 signature authentication schemes used by the remote side. If both peers support RFC 7427 ("Signature Authentication in IKEv2") specific hash algorithms to be used during IKEv2 authentication may be configured. -The syntax is the same as above. For example, with -.B pubkey-sha384-sha256 +The syntax is the same as above, but with ike: prefix. For example, with +.B ike:pubkey-sha384-sha256 a public key signature scheme with either SHA-384 or SHA-256 would get used for authentication, in that order and depending on the hash algorithms supported by the peer. If no specific hash algorithms are configured, the default is to prefer an algorithm that matches or exceeds the strength of the signature key. +If no constraints with ike: prefix are configured any signature scheme +constraint (without ike: prefix) will also apply to IKEv2 authentication, unless +this is disabled in +.BR strongswan.conf (5). For .BR eap , diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 134abb955..d0eb2aac3 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -506,14 +506,15 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } /* authentication metod (class, actually) */ - if (strpfx(auth, "pubkey") || + if (strpfx(auth, "ike:") || + strpfx(auth, "pubkey") || strpfx(auth, "rsa") || strpfx(auth, "ecdsa") || strpfx(auth, "bliss")) { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); build_crl_policy(cfg, local, msg->add_conn.crl_policy); - cfg->add_pubkey_constraints(cfg, auth); + cfg->add_pubkey_constraints(cfg, auth, TRUE); } else if (streq(auth, "psk") || streq(auth, "secret")) { @@ -546,7 +547,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, if (pos) { *pos = 0; - cfg->add_pubkey_constraints(cfg, pos + 1); + cfg->add_pubkey_constraints(cfg, pos + 1, FALSE); } type = eap_vendor_type_from_string(auth); if (type) diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 6cbe5012e..7711fa0cb 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -955,13 +955,14 @@ CALLBACK(parse_auth, bool, { return FALSE; } - if (strpfx(buf, "pubkey") || + if (strpfx(buf, "ike:") || + strpfx(buf, "pubkey") || strpfx(buf, "rsa") || strpfx(buf, "ecdsa") || strpfx(buf, "bliss")) { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); - cfg->add_pubkey_constraints(cfg, buf); + cfg->add_pubkey_constraints(cfg, buf, TRUE); return TRUE; } if (strcaseeq(buf, "psk")) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 2f18cb6cd..5466a2e08 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2007-2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -518,13 +518,16 @@ static void add(private_auth_cfg_t *this, auth_rule_t type, ...) } METHOD(auth_cfg_t, add_pubkey_constraints, void, - private_auth_cfg_t *this, char* constraints) + private_auth_cfg_t *this, char* constraints, bool ike) { enumerator_t *enumerator; - bool rsa = FALSE, ecdsa = FALSE, bliss = FALSE, - rsa_len = FALSE, ecdsa_len = FALSE, bliss_strength = FALSE; + bool is_ike = FALSE, ike_added = FALSE; + key_type_t expected_type = -1; + auth_rule_t expected_strength = AUTH_RULE_MAX; int strength; char *token; + auth_rule_t type; + void *value; enumerator = enumerator_create_token(constraints, "-", ""); while (enumerator->enumerate(enumerator, &token)) @@ -554,46 +557,47 @@ METHOD(auth_cfg_t, add_pubkey_constraints, void, { "sha512", SIGN_BLISS_WITH_SHA2_512, KEY_BLISS, }, }; - if (rsa_len || ecdsa_len || bliss_strength) + if (expected_strength != AUTH_RULE_MAX) { /* expecting a key strength token */ strength = atoi(token); if (strength) { - if (rsa_len) - { - add(this, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength); - } - else if (ecdsa_len) - { - add(this, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength); - } - else if (bliss_strength) - { - add(this, AUTH_RULE_BLISS_STRENGTH, (uintptr_t)strength); - } + add(this, expected_strength, (uintptr_t)strength); } - rsa_len = ecdsa_len = bliss_strength = FALSE; + expected_strength = AUTH_RULE_MAX; if (strength) { continue; } } - if (streq(token, "rsa")) + if (streq(token, "rsa") || streq(token, "ike:rsa")) { - rsa = rsa_len = TRUE; + expected_type = KEY_RSA; + expected_strength = AUTH_RULE_RSA_STRENGTH; + is_ike = strpfx(token, "ike:"); continue; } - if (streq(token, "ecdsa")) + if (streq(token, "ecdsa") || streq(token, "ike:ecdsa")) { - ecdsa = ecdsa_len = TRUE; + expected_type = KEY_ECDSA; + expected_strength = AUTH_RULE_ECDSA_STRENGTH; + is_ike = strpfx(token, "ike:"); continue; } - if (streq(token, "bliss")) + if (streq(token, "bliss") || streq(token, "ike:bliss")) { - bliss = bliss_strength = TRUE; + expected_type = KEY_BLISS; + expected_strength = AUTH_RULE_BLISS_STRENGTH; + is_ike = strpfx(token, "ike:"); continue; } - if (streq(token, "pubkey")) + if (streq(token, "pubkey") || streq(token, "ike:pubkey")) + { + expected_type = KEY_ANY; + is_ike = strpfx(token, "ike:"); + continue; + } + if (is_ike && !ike) { continue; } @@ -602,18 +606,19 @@ METHOD(auth_cfg_t, add_pubkey_constraints, void, { if (streq(schemes[i].name, token)) { - /* for each matching string, allow the scheme, if: - * - it is an RSA scheme, and we enforced RSA - * - it is an ECDSA scheme, and we enforced ECDSA - * - it is not a key type specific scheme - */ - if ((rsa && schemes[i].key == KEY_RSA) || - (ecdsa && schemes[i].key == KEY_ECDSA) || - (bliss && schemes[i].key == KEY_BLISS) || - (!rsa && !ecdsa && !bliss)) + if (expected_type == KEY_ANY || expected_type == schemes[i].key) { - add(this, AUTH_RULE_SIGNATURE_SCHEME, - (uintptr_t)schemes[i].scheme); + if (is_ike) + { + add(this, AUTH_RULE_IKE_SIGNATURE_SCHEME, + (uintptr_t)schemes[i].scheme); + ike_added = TRUE; + } + else + { + add(this, AUTH_RULE_SIGNATURE_SCHEME, + (uintptr_t)schemes[i].scheme); + } } found = TRUE; } @@ -624,6 +629,25 @@ METHOD(auth_cfg_t, add_pubkey_constraints, void, } } enumerator->destroy(enumerator); + + /* if no explicit IKE signature contraints were added we add them for all + * configured signature contraints */ + if (ike && !ike_added && + lib->settings->get_bool(lib->settings, + "%s.signature_authentication_constraints", TRUE, + lib->ns)) + { + enumerator = create_enumerator(this); + while (enumerator->enumerate(enumerator, &type, &value)) + { + if (type == AUTH_RULE_SIGNATURE_SCHEME) + { + add(this, AUTH_RULE_IKE_SIGNATURE_SCHEME, + (uintptr_t)value); + } + } + enumerator->destroy(enumerator); + } } /** diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index f00e64f7e..75bc7e97b 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -187,8 +187,10 @@ struct auth_cfg_t { * Add public key and signature scheme constraints to the set. * * @param constraints constraints string (e.g. "rsa-sha384") + * @param ike whether to add/parse constraints for IKE signatures */ - void (*add_pubkey_constraints)(auth_cfg_t *this, char *constraints); + void (*add_pubkey_constraints)(auth_cfg_t *this, char *constraints, + bool ike); /** * Get a rule value. diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index d86584ad1..b2d456035 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -44,6 +44,7 @@ tests_SOURCES = tests.h tests.c \ suites/test_certpolicy.c \ suites/test_certnames.c \ suites/test_host.c \ + suites/test_auth_cfg.c \ suites/test_hasher.c \ suites/test_crypter.c \ suites/test_crypto_factory.c \ diff --git a/src/libstrongswan/tests/suites/test_auth_cfg.c b/src/libstrongswan/tests/suites/test_auth_cfg.c new file mode 100644 index 000000000..e046725b8 --- /dev/null +++ b/src/libstrongswan/tests/suites/test_auth_cfg.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 Tobias Brunner + * 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 "test_suite.h" + +#include + +struct { + char *constraints; + signature_scheme_t sig[5]; + signature_scheme_t ike[5]; +} sig_constraints_tests[] = { + { "rsa-sha256", { SIGN_RSA_EMSA_PKCS1_SHA256, 0 }, {0}}, + { "rsa-sha256-sha512", { SIGN_RSA_EMSA_PKCS1_SHA256, SIGN_RSA_EMSA_PKCS1_SHA512, 0 }, {0}}, + { "ecdsa-sha256", { SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_256, 0 }, {0}}, + { "rsa-sha256-ecdsa-sha256", { SIGN_RSA_EMSA_PKCS1_SHA256, SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_256, 0 }, {0}}, + { "pubkey-sha256", { SIGN_RSA_EMSA_PKCS1_SHA256, SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_256, SIGN_BLISS_WITH_SHA2_256, 0 }, {0}}, + { "ike:rsa-sha256", {0}, { SIGN_RSA_EMSA_PKCS1_SHA256, 0 }}, + { "ike:rsa-sha256-rsa-sha256", { SIGN_RSA_EMSA_PKCS1_SHA256, 0 }, { SIGN_RSA_EMSA_PKCS1_SHA256, 0 }}, + { "rsa-sha256-ike:rsa-sha256", { SIGN_RSA_EMSA_PKCS1_SHA256, 0 }, { SIGN_RSA_EMSA_PKCS1_SHA256, 0 }}, + { "ike:pubkey-sha256", {0}, { SIGN_RSA_EMSA_PKCS1_SHA256, SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_256, SIGN_BLISS_WITH_SHA2_256, 0 }}, + { "rsa-ecdsa-sha256", { SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_256, 0 }, {0}}, + { "rsa-4096-ecdsa-sha256", { SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_256, 0 }, {0}}, + { "rsa-4096-ecdsa-256-sha256", { SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_256, 0 }, {0}}, + { "rsa-ecdsa256-sha256", { SIGN_RSA_EMSA_PKCS1_SHA256, 0 }, {0}}, + { "rsa4096-sha256", {0}, {0}}, + { "sha256", {0}, {0}}, + { "ike:sha256", {0}, {0}}, +}; + +static void check_sig_constraints(auth_cfg_t *cfg, auth_rule_t type, + signature_scheme_t expected[]) +{ + enumerator_t *enumerator; + auth_rule_t t; + void *value; + int i = 0; + + enumerator = cfg->create_enumerator(cfg); + while (enumerator->enumerate(enumerator, &t, &value)) + { + if (t == type) + { + ck_assert(expected[i]); + ck_assert_int_eq(expected[i], (signature_scheme_t)value); + i++; + } + } + enumerator->destroy(enumerator); + ck_assert(!expected[i]); +} + +START_TEST(test_sig_contraints) +{ + auth_cfg_t *cfg; + signature_scheme_t none[] = {0}; + + cfg = auth_cfg_create(); + cfg->add_pubkey_constraints(cfg, sig_constraints_tests[_i].constraints, FALSE); + check_sig_constraints(cfg, AUTH_RULE_SIGNATURE_SCHEME, sig_constraints_tests[_i].sig); + check_sig_constraints(cfg, AUTH_RULE_IKE_SIGNATURE_SCHEME, none); + cfg->destroy(cfg); + + lib->settings->set_bool(lib->settings, "%s.signature_authentication_constraints", + FALSE, lib->ns); + + cfg = auth_cfg_create(); + cfg->add_pubkey_constraints(cfg, sig_constraints_tests[_i].constraints, TRUE); + check_sig_constraints(cfg, AUTH_RULE_SIGNATURE_SCHEME, sig_constraints_tests[_i].sig); + check_sig_constraints(cfg, AUTH_RULE_IKE_SIGNATURE_SCHEME, sig_constraints_tests[_i].ike); + cfg->destroy(cfg); +} +END_TEST + +START_TEST(test_ike_contraints_fallback) +{ + auth_cfg_t *cfg; + + lib->settings->set_bool(lib->settings, "%s.signature_authentication_constraints", + TRUE, lib->ns); + + cfg = auth_cfg_create(); + cfg->add_pubkey_constraints(cfg, sig_constraints_tests[_i].constraints, TRUE); + check_sig_constraints(cfg, AUTH_RULE_SIGNATURE_SCHEME, sig_constraints_tests[_i].sig); + if (sig_constraints_tests[_i].ike[0]) + { + check_sig_constraints(cfg, AUTH_RULE_IKE_SIGNATURE_SCHEME, sig_constraints_tests[_i].ike); + } + else + { + check_sig_constraints(cfg, AUTH_RULE_IKE_SIGNATURE_SCHEME, sig_constraints_tests[_i].sig); + } + cfg->destroy(cfg); +} +END_TEST + +Suite *auth_cfg_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("auth_cfg"); + + tc = tcase_create("add_pubkey_constraints"); + tcase_add_loop_test(tc, test_sig_contraints, 0, countof(sig_constraints_tests)); + tcase_add_loop_test(tc, test_ike_contraints_fallback, 0, countof(sig_constraints_tests)); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/tests.h b/src/libstrongswan/tests/tests.h index e1074b931..824c88022 100644 --- a/src/libstrongswan/tests/tests.h +++ b/src/libstrongswan/tests/tests.h @@ -37,6 +37,7 @@ TEST_SUITE_DEPEND(certpolicy_suite_create, CERT_ENCODE, CERT_X509) TEST_SUITE_DEPEND(certnames_suite_create, CERT_ENCODE, CERT_X509) TEST_SUITE(host_suite_create) TEST_SUITE(printf_suite_create) +TEST_SUITE(auth_cfg_suite_create) TEST_SUITE(hasher_suite_create) TEST_SUITE(crypter_suite_create) TEST_SUITE(crypto_factory_suite_create) From 1ecec95dff4036cf6a4a5d0347b3247fc71ce0b0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 3 Feb 2016 15:16:48 +0100 Subject: [PATCH 4/6] vici: Add support for pubkey constraints with EAP-TLS This is a feature currently supported by stroke. --- src/libcharon/plugins/vici/vici_config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 7711fa0cb..181b14b40 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -982,8 +982,16 @@ CALLBACK(parse_auth, bool, } if (strcasepfx(buf, "eap")) { + char *pos; + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); + pos = strchr(buf, ':'); + if (pos) + { + *pos = 0; + cfg->add_pubkey_constraints(cfg, pos + 1, FALSE); + } type = eap_vendor_type_from_string(buf); if (type) { From 130c485be6cb6647c02932999e1b60a114af391e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 3 Feb 2016 15:45:09 +0100 Subject: [PATCH 5/6] swanctl: Document signature scheme constraints --- src/swanctl/swanctl.opt | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index a3e3cd4eb..b053fe32a 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -309,6 +309,19 @@ connections..local.auth = pubkey An EAP module implementing the appropriate method is selected to perform the EAP conversation. + If both peers support RFC 7427 ("Signature Authentication in IKEv2") + specific hash algorithms to be used during IKEv2 authentication may be + configured. To do so use _ike:_ followed by a trust chain signature scheme + constraint (see description of the **remote** section's **auth** keyword). + For example, with _ike:pubkey-sha384-sha256_ a public key signature scheme + with either SHA-384 or SHA-256 would get used for authentication, in that + order and depending on the hash algorithms supported by the peer. If no + specific hash algorithms are configured, the default is to prefer an + algorithm that matches or exceeds the strength of the signature key. + If no constraints with _ike:_ prefix are configured any signature scheme + constraint (without _ike:_ prefix) will also apply to IKEv2 authentication, + unless this is disabled in **strongswan.conf**(5). + connections..local.id = IKE identity to use for authentication round. @@ -415,9 +428,25 @@ connections..remote.auth = pubkey Authentication to expect from remote (_pubkey_, _psk_, _xauth[-backend]_ or _eap[-method]_). - Authentication to expect from remote. See the **local** sections **auth** + Authentication to expect from remote. See the **local** section's **auth** keyword description about the details of supported mechanisms. + To require a trustchain public key strength for the remote side, specify the + key type followed by the minimum strength in bits (for example _ecdsa-384_ + or _rsa-2048-ecdsa-256_). To limit the acceptable set of hashing algorithms + for trustchain validation, append hash algorithms to _pubkey_ or a key + strength definition (for example _pubkey-sha1-sha256_ or + _rsa-2048-ecdsa-256-sha256-sha384-sha512_). + Unless disabled in **strongswan.conf**(5), or explicit IKEv2 signature + constraints are configured (refer to the description of the **local** + section's **auth** keyword for details), such key types and hash algorithms + are also applied as constraints against IKEv2 signature authentication + schemes used by the remote side. + + To specify trust chain constraints for EAP-(T)TLS, append a colon to the + EAP method, followed by the key type/size and hash algorithm as discussed + above (e.g. _eap-tls:ecdsa-384-sha384_). + connections..children. {} CHILD_SA configuration sub-section. From c171afeaedb37bc4f13eafb70f0daa7a34f672d2 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Mar 2016 16:29:32 +0100 Subject: [PATCH 6/6] NEWS: Add note about IKEv2 signature scheme constraints --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 100856e0a..fcb89f09e 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,10 @@ strongswan-5.4.0 on different selectors via VICI/swanctl. Unless disabled in strongswan.conf the charon daemon will follow redirect requests received from servers. +- The ike: prefix enables the explicit configuration of signature scheme + constraints against IKEv2 authentication in rightauth, which allows the use + of different signature schemes for trustchain verification and authentication. + - For the vici plugin a Vici:Session Perl CPAN module has been added to allow Perl applications to control and/or monitor the IKE daemon using the VICI interface, similar to the existing Python egg or Ruby gem.