aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/charon-tkm/src/tkm/tkm_keymat.c29
-rw-r--r--src/libcharon/encoding/payloads/notify_payload.c22
-rw-r--r--src/libcharon/encoding/payloads/notify_payload.h2
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c23
-rw-r--r--src/libcharon/sa/authenticator.c11
-rw-r--r--src/libcharon/sa/authenticator.h4
-rw-r--r--src/libcharon/sa/ike_sa.h5
-rw-r--r--src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c264
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.c31
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.h18
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c137
-rw-r--r--src/libstrongswan/Android.mk1
-rw-r--r--src/libstrongswan/Makefile.am4
-rw-r--r--src/libstrongswan/credentials/auth_cfg.c60
-rw-r--r--src/libstrongswan/credentials/auth_cfg.h4
-rw-r--r--src/libstrongswan/credentials/credential_manager.c3
-rw-r--r--src/libstrongswan/credentials/keys/public_key.c148
-rw-r--r--src/libstrongswan/credentials/keys/public_key.h30
-rw-r--r--src/libstrongswan/crypto/hashers/hash_algorithm_set.c113
-rw-r--r--src/libstrongswan/crypto/hashers/hash_algorithm_set.h76
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.c90
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.h40
-rw-r--r--src/libstrongswan/tests/suites/test_utils.c45
23 files changed, 1027 insertions, 133 deletions
diff --git a/src/charon-tkm/src/tkm/tkm_keymat.c b/src/charon-tkm/src/tkm/tkm_keymat.c
index 772fac8b0..80721fafe 100644
--- a/src/charon-tkm/src/tkm/tkm_keymat.c
+++ b/src/charon-tkm/src/tkm/tkm_keymat.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyrigth (C) 2012 Reto Buerki
* Copyright (C) 2012 Adrian-Ken Rueegsegger
* Hochschule fuer Technik Rapperswil
@@ -17,6 +18,7 @@
#include <daemon.h>
#include <tkm/constants.h>
#include <tkm/client.h>
+#include <crypto/hashers/hash_algorithm_set.h>
#include "tkm.h"
#include "tkm_types.h"
@@ -71,6 +73,10 @@ struct private_tkm_keymat_t {
*/
chunk_t other_init_msg;
+ /**
+ * Set of hash algorithms supported by peer for signature authentication
+ */
+ hash_algorithm_set_t *hash_algorithms;
};
/**
@@ -417,6 +423,26 @@ METHOD(keymat_v2_t, get_psk_sig, bool,
return FALSE;
}
+METHOD(keymat_v2_t, hash_algorithm_supported, bool,
+ private_tkm_keymat_t *this, hash_algorithm_t hash)
+{
+ if (!this->hash_algorithms)
+ {
+ return FALSE;
+ }
+ return this->hash_algorithms->contains(this->hash_algorithms, hash);
+}
+
+METHOD(keymat_v2_t, add_hash_algorithm, void,
+ private_tkm_keymat_t *this, hash_algorithm_t hash)
+{
+ if (!this->hash_algorithms)
+ {
+ this->hash_algorithms = hash_algorithm_set_create();
+ }
+ this->hash_algorithms->add(this->hash_algorithms, hash);
+}
+
METHOD(keymat_t, destroy, void,
private_tkm_keymat_t *this)
{
@@ -435,6 +461,7 @@ METHOD(keymat_t, destroy, void,
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_AE, this->ae_ctx_id);
}
+ DESTROY_IF(this->hash_algorithms);
DESTROY_IF(this->aead_in);
DESTROY_IF(this->aead_out);
chunk_free(&this->auth_payload);
@@ -488,6 +515,8 @@ tkm_keymat_t *tkm_keymat_create(bool initiator)
.get_skd = _get_skd,
.get_auth_octets = _get_auth_octets,
.get_psk_sig = _get_psk_sig,
+ .add_hash_algorithm = _add_hash_algorithm,
+ .hash_algorithm_supported = _hash_algorithm_supported,
},
.get_isa_id = _get_isa_id,
.set_auth_payload = _set_auth_payload,
diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c
index 94723ddd7..f32a1273f 100644
--- a/src/libcharon/encoding/payloads/notify_payload.c
+++ b/src/libcharon/encoding/payloads/notify_payload.c
@@ -65,7 +65,7 @@ ENUM_NEXT(notify_type_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_SA_NOT_
"ME_CONNECT_FAILED");
ENUM_NEXT(notify_type_names, MS_NOTIFY_STATUS, MS_NOTIFY_STATUS, ME_CONNECT_FAILED,
"MS_NOTIFY_STATUS");
-ENUM_NEXT(notify_type_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY_STATUS,
+ENUM_NEXT(notify_type_names, INITIAL_CONTACT, SIGNATURE_HASH_ALGORITHMS, MS_NOTIFY_STATUS,
"INITIAL_CONTACT",
"SET_WINDOW_SIZE",
"ADDITIONAL_TS_POSSIBLE",
@@ -112,8 +112,9 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY
"ERX_SUPPORTED",
"IFOM_CAPABILITY",
"SENDER_REQUEST_ID",
- "FRAGMENTATION_SUPPORTED");
-ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, FRAGMENTATION_SUPPORTED,
+ "FRAGMENTATION_SUPPORTED",
+ "SIGNATURE_HASH_ALGORITHMS");
+ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, SIGNATURE_HASH_ALGORITHMS,
"INITIAL_CONTACT");
ENUM_NEXT(notify_type_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1,
"DPD_R_U_THERE",
@@ -174,7 +175,7 @@ ENUM_NEXT(notify_type_short_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_S
"ME_CONN_FAIL");
ENUM_NEXT(notify_type_short_names, MS_NOTIFY_STATUS, MS_NOTIFY_STATUS, ME_CONNECT_FAILED,
"MS_STATUS");
-ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY_STATUS,
+ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, SIGNATURE_HASH_ALGORITHMS, MS_NOTIFY_STATUS,
"INIT_CONTACT",
"SET_WINSIZE",
"ADD_TS_POSS",
@@ -221,8 +222,9 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_
"ERX_SUP",
"IFOM_CAP",
"SENDER_REQ_ID",
- "FRAG_SUP");
-ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, FRAGMENTATION_SUPPORTED,
+ "FRAG_SUP",
+ "HASH_ALG");
+ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, SIGNATURE_HASH_ALGORITHMS,
"INITIAL_CONTACT");
ENUM_NEXT(notify_type_short_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1,
"DPD",
@@ -473,6 +475,14 @@ METHOD(payload_t, verify, status_t,
}
break;
}
+ case SIGNATURE_HASH_ALGORITHMS:
+ {
+ if (this->notify_data.len % 2)
+ {
+ bad_length = TRUE;
+ }
+ break;
+ }
case AUTH_LIFETIME:
{
if (this->notify_data.len != 4)
diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h
index 25521c2bb..690757383 100644
--- a/src/libcharon/encoding/payloads/notify_payload.h
+++ b/src/libcharon/encoding/payloads/notify_payload.h
@@ -151,6 +151,8 @@ enum notify_type_t {
SENDER_REQUEST_ID = 16429,
/* IKEv2 fragmentation supported, RFC 7383 */
FRAGMENTATION_SUPPORTED = 16430,
+ /* Signature Hash Algorithms, RFC 7427 */
+ SIGNATURE_HASH_ALGORITHMS = 16431,
/* IKEv1 initial contact */
INITIAL_CONTACT_IKEV1 = 24578,
/* IKEv1 DPD */
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index 88abe4951..0483ba2f5 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -301,7 +301,8 @@ static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
{
enumerator_t *enumerator;
- bool rsa = FALSE, ecdsa = FALSE, rsa_len = FALSE, ecdsa_len = FALSE;
+ bool rsa = FALSE, ecdsa = FALSE, bliss = FALSE,
+ rsa_len = FALSE, ecdsa_len = FALSE, bliss_strength = FALSE;
int strength;
char *token;
@@ -328,6 +329,9 @@ static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
{ "sha256", SIGN_ECDSA_256, KEY_ECDSA, },
{ "sha384", SIGN_ECDSA_384, KEY_ECDSA, },
{ "sha512", SIGN_ECDSA_521, KEY_ECDSA, },
+ { "sha256", SIGN_BLISS_WITH_SHA256, KEY_BLISS, },
+ { "sha384", SIGN_BLISS_WITH_SHA384, KEY_BLISS, },
+ { "sha512", SIGN_BLISS_WITH_SHA512, KEY_BLISS, },
};
if (rsa_len || ecdsa_len)
@@ -343,8 +347,12 @@ static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
{
cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength);
}
+ else if (bliss_strength)
+ {
+ cfg->add(cfg, AUTH_RULE_BLISS_STRENGTH, (uintptr_t)strength);
+ }
}
- rsa_len = ecdsa_len = FALSE;
+ rsa_len = ecdsa_len = bliss_strength = FALSE;
if (strength)
{
continue;
@@ -360,6 +368,11 @@ static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
ecdsa = ecdsa_len = TRUE;
continue;
}
+ if (streq(token, "bliss"))
+ {
+ bliss = bliss_strength = TRUE;
+ continue;
+ }
if (streq(token, "pubkey"))
{
continue;
@@ -376,7 +389,8 @@ static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
*/
if ((rsa && schemes[i].key == KEY_RSA) ||
(ecdsa && schemes[i].key == KEY_ECDSA) ||
- (!rsa && !ecdsa))
+ (bliss && schemes[i].key == KEY_BLISS) ||
+ (!rsa && !ecdsa && !bliss))
{
cfg->add(cfg, AUTH_RULE_SIGNATURE_SCHEME,
(uintptr_t)schemes[i].scheme);
@@ -590,7 +604,8 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
/* authentication metod (class, actually) */
if (strpfx(auth, "pubkey") ||
strpfx(auth, "rsa") ||
- strpfx(auth, "ecdsa"))
+ 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);
diff --git a/src/libcharon/sa/authenticator.c b/src/libcharon/sa/authenticator.c
index a3d67ed7a..6c3681a2d 100644
--- a/src/libcharon/sa/authenticator.c
+++ b/src/libcharon/sa/authenticator.c
@@ -31,15 +31,14 @@ ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS,
"RSA signature",
"pre-shared key",
"DSS signature");
-ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_NULL, AUTH_DSS,
+ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_DS, AUTH_DSS,
"ECDSA-256 signature",
"ECDSA-384 signature",
"ECDSA-521 signature",
"secure password method",
- "NULL authentication");
-ENUM_NEXT(auth_method_names, AUTH_BLISS, AUTH_BLISS, AUTH_NULL,
- "BLISS signature");
-ENUM_NEXT(auth_method_names, AUTH_XAUTH_INIT_PSK, AUTH_HYBRID_RESP_RSA, AUTH_BLISS,
+ "NULL authentication",
+ "digital signature");
+ENUM_NEXT(auth_method_names, AUTH_XAUTH_INIT_PSK, AUTH_HYBRID_RESP_RSA, AUTH_DS,
"XAuthInitPSK",
"XAuthRespPSK",
"XAuthInitRSA",
@@ -102,7 +101,7 @@ authenticator_t *authenticator_create_verifier(
case AUTH_ECDSA_256:
case AUTH_ECDSA_384:
case AUTH_ECDSA_521:
- case AUTH_BLISS:
+ case AUTH_DS:
return (authenticator_t*)pubkey_authenticator_create_verifier(ike_sa,
sent_nonce, received_init, reserved);
case AUTH_PSK:
diff --git a/src/libcharon/sa/authenticator.h b/src/libcharon/sa/authenticator.h
index aefb94294..97c042e71 100644
--- a/src/libcharon/sa/authenticator.h
+++ b/src/libcharon/sa/authenticator.h
@@ -85,9 +85,9 @@ enum auth_method_t {
AUTH_NULL = 13,
/**
- * BLISS Authentication Method
+ * Digital Signature as specified in RFC 7427
*/
- AUTH_BLISS = 220,
+ AUTH_DS = 14,
/**
* IKEv1 initiator XAUTH with PSK, outside of IANA range
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index f65efd81f..9dbc805c9 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -131,6 +131,11 @@ enum ike_extension_t {
* peer supports proprietary IKEv1 or standardized IKEv2 fragmentation
*/
EXT_IKE_FRAGMENTATION = (1<<11),
+
+ /**
+ * Signature Authentication, RFC 7427
+ */
+ EXT_SIGNATURE_AUTH = (1<<12),
};
/**
diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
index 2188fb2e8..965f70aa5 100644
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -20,6 +20,8 @@
#include <daemon.h>
#include <encoding/payloads/auth_payload.h>
#include <sa/ikev2/keymat_v2.h>
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
@@ -52,8 +54,136 @@ 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;
};
+/**
+ * Parse authentication data used for Signature Authentication as per RFC 7427
+ */
+static bool parse_signature_auth_data(chunk_t *auth_data, key_type_t *key_type,
+ signature_scheme_t *scheme)
+{
+ u_int8_t len;
+ int oid;
+
+ if (!auth_data->len)
+ {
+ return FALSE;
+ }
+ len = auth_data->ptr[0];
+ *auth_data = chunk_skip(*auth_data, 1);
+ /* we currently don't support schemes that require parameters */
+ oid = asn1_parse_algorithmIdentifier(*auth_data, 1, NULL);
+ *scheme = signature_scheme_from_oid(oid);
+ if (*scheme == SIGN_UNKNOWN)
+ {
+ return FALSE;
+ }
+ *key_type = key_type_from_signature_scheme(*scheme);
+ *auth_data = chunk_skip(*auth_data, len);
+ return TRUE;
+}
+
+/**
+ * Build authentication data used for Signature Authentication as per RFC 7427
+ */
+static bool build_signature_auth_data(chunk_t *auth_data,
+ signature_scheme_t scheme)
+{
+ chunk_t data;
+ u_int8_t len;
+ int oid;
+
+ oid = signature_scheme_to_oid(scheme);
+ if (oid == OID_UNKNOWN)
+ {
+ return FALSE;
+ }
+ data = asn1_algorithmIdentifier(oid);
+ len = data.len;
+ *auth_data = chunk_cat("cmm", chunk_from_thing(len), data, *auth_data);
+ return TRUE;
+}
+
+/**
+ * Select a signature scheme based on our configuration, the other peer's
+ * capabilities and the private key
+ */
+static signature_scheme_t select_signature_scheme(keymat_v2_t *keymat,
+ auth_cfg_t *auth, private_key_t *private)
+{
+ enumerator_t *enumerator;
+ signature_scheme_t selected = SIGN_UNKNOWN, scheme;
+ uintptr_t config;
+ auth_rule_t rule;
+ key_type_t key_type;
+ bool have_config = FALSE;
+
+ key_type = private->get_type(private);
+ enumerator = auth->create_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &rule, &config))
+ {
+ if (rule != AUTH_RULE_SIGNATURE_SCHEME)
+ {
+ continue;
+ }
+ have_config = TRUE;
+ if (key_type == key_type_from_signature_scheme(config) &&
+ keymat->hash_algorithm_supported(keymat,
+ hasher_from_signature_scheme(config)))
+ {
+ selected = config;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (selected == SIGN_UNKNOWN && !have_config)
+ {
+ /* if no specific configuration, find a scheme appropriate for the key
+ * and supported by the other peer */
+ enumerator = signature_schemes_for_key(key_type,
+ private->get_keysize(private));
+ while (enumerator->enumerate(enumerator, &scheme))
+ {
+ if (keymat->hash_algorithm_supported(keymat,
+ hasher_from_signature_scheme(scheme)))
+ {
+ selected = scheme;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ /* for RSA we tried at least SHA-512, also try other schemes down to
+ * what we'd use with classic authentication */
+ if (selected == SIGN_UNKNOWN && key_type == KEY_RSA)
+ {
+ signature_scheme_t schemes[] = {
+ SIGN_RSA_EMSA_PKCS1_SHA384,
+ SIGN_RSA_EMSA_PKCS1_SHA256,
+ SIGN_RSA_EMSA_PKCS1_SHA1,
+ };
+ int i;
+
+ for (i = 0; i < countof(schemes); i++)
+ {
+ if (keymat->hash_algorithm_supported(keymat,
+ hasher_from_signature_scheme(schemes[i])))
+ {
+ selected = scheme;
+ break;
+ }
+ }
+ }
+ }
+ return selected;
+}
+
METHOD(authenticator_t, build, status_t,
private_pubkey_authenticator_t *this, message_t *message)
{
@@ -64,7 +194,7 @@ METHOD(authenticator_t, build, status_t,
auth_cfg_t *auth;
auth_payload_t *auth_payload;
auth_method_t auth_method;
- signature_scheme_t scheme;
+ signature_scheme_t scheme = SIGN_UNKNOWN;
keymat_v2_t *keymat;
id = this->ike_sa->get_my_id(this->ike_sa);
@@ -75,62 +205,75 @@ METHOD(authenticator_t, build, status_t,
DBG1(DBG_IKE, "no private key found for '%Y'", id);
return NOT_FOUND;
}
+ keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
- switch (private->get_type(private))
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_SIGNATURE_AUTH))
{
- case KEY_RSA:
- /* we currently use always SHA1 for signatures,
- * TODO: support other hashes depending on configuration/auth */
- scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
- auth_method = AUTH_RSA;
- break;
- case KEY_ECDSA:
- /* we try to deduct the signature scheme from the keysize */
- switch (private->get_keysize(private))
- {
- case 256:
- scheme = SIGN_ECDSA_256;
- auth_method = AUTH_ECDSA_256;
- break;
- case 384:
- scheme = SIGN_ECDSA_384;
- auth_method = AUTH_ECDSA_384;
- break;
- case 521:
- scheme = SIGN_ECDSA_521;
- auth_method = AUTH_ECDSA_521;
- break;
- default:
- DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
- private->get_keysize(private));
- return status;
- }
- break;
- case KEY_BLISS:
- /* we currently use SHA512 only */
- scheme = SIGN_BLISS_WITH_SHA512;
- auth_method = AUTH_BLISS;
- break;
- default:
- DBG1(DBG_IKE, "private key of type %N not supported",
- key_type_names, private->get_type(private));
+ scheme = select_signature_scheme(keymat, auth, private);
+ auth_method = AUTH_DS;
+ if (scheme == SIGN_UNKNOWN)
+ {
+ DBG1(DBG_IKE, "no common hash algorithm found to create signature "
+ "with %N key", key_type_names, private->get_type(private));
return status;
+ }
}
- keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+ else
+ {
+ switch (private->get_type(private))
+ {
+ case KEY_RSA:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ auth_method = AUTH_RSA;
+ break;
+ case KEY_ECDSA:
+ /* deduct the signature scheme from the keysize */
+ switch (private->get_keysize(private))
+ {
+ case 256:
+ scheme = SIGN_ECDSA_256;
+ auth_method = AUTH_ECDSA_256;
+ break;
+ case 384:
+ scheme = SIGN_ECDSA_384;
+ auth_method = AUTH_ECDSA_384;
+ break;
+ case 521:
+ scheme = SIGN_ECDSA_521;
+ auth_method = AUTH_ECDSA_521;
+ break;
+ default:
+ DBG1(DBG_IKE, "%d bit ECDSA private key size not "
+ "supported", private->get_keysize(private));
+ return status;
+ }
+ break;
+ default:
+ DBG1(DBG_IKE, "private key of type %N not supported",
+ key_type_names, private->get_type(private));
+ return status;
+ }
+ }
+
if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init,
this->nonce, id, this->reserved, &octets) &&
private->sign(private, scheme, octets, &auth_data))
{
- auth_payload = auth_payload_create();
- auth_payload->set_auth_method(auth_payload, auth_method);
- auth_payload->set_data(auth_payload, auth_data);
- chunk_free(&auth_data);
- message->add_payload(message, (payload_t*)auth_payload);
- status = SUCCESS;
+ if (auth_method != AUTH_DS ||
+ build_signature_auth_data(&auth_data, scheme))
+ {
+ auth_payload = auth_payload_create();
+ auth_payload->set_auth_method(auth_payload, auth_method);
+ auth_payload->set_data(auth_payload, auth_data);
+ chunk_free(&auth_data);
+ message->add_payload(message, (payload_t*)auth_payload);
+ status = SUCCESS;
+ }
}
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
- auth_method_names, auth_method,
- (status == SUCCESS)? "successful":"failed");
+ auth_method == AUTH_DS ? signature_scheme_names : auth_method_names,
+ auth_method == AUTH_DS ? scheme : auth_method,
+ status == SUCCESS ? "successful" : "failed");
chunk_free(&octets);
private->destroy(private);
@@ -158,11 +301,10 @@ METHOD(authenticator_t, process, status_t,
return FAILED;
}
auth_method = auth_payload->get_auth_method(auth_payload);
+ auth_data = auth_payload->get_data(auth_payload);
switch (auth_method)
{
case AUTH_RSA:
- /* We currently accept SHA1 signatures only
- * TODO: allow other hash algorithms and note it in "auth" */
key_type = KEY_RSA;
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
@@ -175,14 +317,15 @@ METHOD(authenticator_t, process, status_t,
case AUTH_ECDSA_521:
scheme = SIGN_ECDSA_521;
break;
- case AUTH_BLISS:
- key_type = KEY_BLISS;
- scheme = SIGN_BLISS_WITH_SHA512;
- break;
+ case AUTH_DS:
+ if (parse_signature_auth_data(&auth_data, &key_type, &scheme))
+ {
+ break;
+ }
+ /* fall-through */
default:
return INVALID_ARG;
}
- auth_data = auth_payload->get_data(auth_payload);
id = this->ike_sa->get_other_id(this->ike_sa);
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
if (!keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init,
@@ -197,11 +340,16 @@ METHOD(authenticator_t, process, status_t,
{
if (public->verify(public, scheme, octets, auth_data))
{
- DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
- id, auth_method_names, auth_method);
+ DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id,
+ auth_method == AUTH_DS ? signature_scheme_names : auth_method_names,
+ auth_method == AUTH_DS ? scheme : auth_method);
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_SIGNATURE_SCHEME, (uintptr_t)scheme);
+ }
break;
}
else
@@ -274,6 +422,8 @@ 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));
diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c
index 88ad14faf..f237f7059 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.c
+++ b/src/libcharon/sa/ikev2/keymat_v2.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -17,6 +18,7 @@
#include <daemon.h>
#include <crypto/prf_plus.h>
+#include <crypto/hashers/hash_algorithm_set.h>
typedef struct private_keymat_v2_t private_keymat_v2_t;
@@ -69,6 +71,11 @@ struct private_keymat_v2_t {
* Key to verify incoming authentication data (SKp)
*/
chunk_t skp_verify;
+
+ /**
+ * Set of hash algorithms supported by peer for signature authentication
+ */
+ hash_algorithm_set_t *hash_algorithms;
};
METHOD(keymat_t, get_version, ike_version_t,
@@ -676,6 +683,26 @@ METHOD(keymat_v2_t, get_psk_sig, bool,
return TRUE;
}
+METHOD(keymat_v2_t, hash_algorithm_supported, bool,
+ private_keymat_v2_t *this, hash_algorithm_t hash)
+{
+ if (!this->hash_algorithms)
+ {
+ return FALSE;
+ }
+ return this->hash_algorithms->contains(this->hash_algorithms, hash);
+}
+
+METHOD(keymat_v2_t, add_hash_algorithm, void,
+ private_keymat_v2_t *this, hash_algorithm_t hash)
+{
+ if (!this->hash_algorithms)
+ {
+ this->hash_algorithms = hash_algorithm_set_create();
+ }
+ this->hash_algorithms->add(this->hash_algorithms, hash);
+}
+
METHOD(keymat_t, destroy, void,
private_keymat_v2_t *this)
{
@@ -685,6 +712,7 @@ METHOD(keymat_t, destroy, void,
chunk_clear(&this->skd);
chunk_clear(&this->skp_verify);
chunk_clear(&this->skp_build);
+ DESTROY_IF(this->hash_algorithms);
free(this);
}
@@ -709,6 +737,9 @@ keymat_v2_t *keymat_v2_create(bool initiator)
.get_skd = _get_skd,
.get_auth_octets = _get_auth_octets,
.get_psk_sig = _get_psk_sig,
+ .add_hash_algorithm = _add_hash_algorithm,
+ .hash_algorithm_supported = _hash_algorithm_supported,
+
},
.initiator = initiator,
.prf_alg = PRF_UNDEFINED,
diff --git a/src/libcharon/sa/ikev2/keymat_v2.h b/src/libcharon/sa/ikev2/keymat_v2.h
index 04432f05b..927b62b03 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.h
+++ b/src/libcharon/sa/ikev2/keymat_v2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Tobias Brunner
+ * Copyright (C) 2011-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -124,6 +124,22 @@ struct keymat_v2_t {
bool (*get_psk_sig)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
chunk_t nonce, chunk_t secret,
identification_t *id, char reserved[3], chunk_t *sig);
+
+ /**
+ * Add a hash algorithm supported by the peer for signature authentication.
+ *
+ * @param hash hash algorithm
+ */
+ void (*add_hash_algorithm)(keymat_v2_t *this, hash_algorithm_t hash);
+
+ /**
+ * Check if a given hash algorithm is supported by the peer for signature
+ * authentication.
+ *
+ * @param hash hash algorithm
+ * @return TRUE if supported, FALSE otherwise
+ */
+ bool (*hash_algorithm_supported)(keymat_v2_t *this, hash_algorithm_t hash);
};
/**
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index b3e92d8ca..ab3d57af6 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -20,8 +20,11 @@
#include <string.h>
#include <daemon.h>
+#include <bio/bio_reader.h>
+#include <bio/bio_writer.h>
#include <sa/ikev2/keymat_v2.h>
#include <crypto/diffie_hellman.h>
+#include <crypto/hashers/hash_algorithm_set.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/nonce_payload.h>
@@ -100,9 +103,111 @@ struct private_ike_init_t {
* retries done so far after failure (cookie or bad dh group)
*/
u_int retry;
+
+ /**
+ * Whether to use Signature Authentication as per RFC 7427
+ */
+ bool signature_authentication;
};
/**
+ * Notify the peer about the hash algorithms we support or expect,
+ * as per RFC 7427
+ */
+static void send_supported_hash_algorithms(private_ike_init_t *this,
+ message_t *message)
+{
+ hash_algorithm_set_t *algos;
+ enumerator_t *enumerator, *rounds;
+ bio_writer_t *writer;
+ hash_algorithm_t hash;
+ peer_cfg_t *peer;
+ auth_cfg_t *auth;
+ auth_rule_t rule;
+ uintptr_t config;
+ char *plugin_name;
+
+ algos = hash_algorithm_set_create();
+ peer = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (peer)
+ {
+ rounds = peer->create_auth_cfg_enumerator(peer, FALSE);
+ while (rounds->enumerate(rounds, &auth))
+ {
+ enumerator = auth->create_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &rule, &config))
+ {
+ if (rule == AUTH_RULE_SIGNATURE_SCHEME)
+ {
+ hash = hasher_from_signature_scheme(config);
+ if (hasher_algorithm_for_ikev2(hash))
+ {
+ algos->add(algos, hash);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ rounds->destroy(rounds);
+ }
+
+ if (!algos->count(algos))
+ {
+ enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &hash, &plugin_name))
+ {
+ if (hasher_algorithm_for_ikev2(hash))
+ {
+ algos->add(algos, hash);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+
+ if (algos->count(algos))
+ {
+ writer = bio_writer_create(0);
+ enumerator = algos->create_enumerator(algos);
+ while (enumerator->enumerate(enumerator, &hash))
+ {
+ writer->write_uint16(writer, hash);
+ }
+ enumerator->destroy(enumerator);
+ message->add_notify(message, FALSE, SIGNATURE_HASH_ALGORITHMS,
+ writer->get_buf(writer));
+ writer->destroy(writer);
+ }
+ algos->destroy(algos);
+}
+
+/**
+ * Store algorithms supported by other peer
+ */
+static void handle_supported_hash_algorithms(private_ike_init_t *this,
+ notify_payload_t *notify)
+{
+ bio_reader_t *reader;
+ u_int16_t algo;
+ bool added = FALSE;
+
+ reader = bio_reader_create(notify->get_notification_data(notify));
+ while (reader->remaining(reader) >= 2 && reader->read_uint16(reader, &algo))
+ {
+ if (hasher_algorithm_for_ikev2(algo))
+ {
+ this->keymat->add_hash_algorithm(this->keymat, algo);
+ added = TRUE;
+ }
+ }
+ reader->destroy(reader);
+
+ if (added)
+ {
+ this->ike_sa->enable_extension(this->ike_sa, EXT_SIGNATURE_AUTH);
+ }
+}
+
+/**
* build the payloads for the message
*/
static void build_payloads(private_ike_init_t *this, message_t *message)
@@ -174,6 +279,16 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
chunk_empty);
}
}
+ /* submit supported hash algorithms for signature authentication */
+ if (!this->old_sa && this->signature_authentication)
+ {
+ if (this->initiator ||
+ this->ike_sa->supports_extension(this->ike_sa,
+ EXT_SIGNATURE_AUTH))
+ {
+ send_supported_hash_algorithms(this, message);
+ }
+ }
}
/**
@@ -228,11 +343,23 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
{
notify_payload_t *notify = (notify_payload_t*)payload;
- if (notify->get_notify_type(notify) == FRAGMENTATION_SUPPORTED)
+ switch (notify->get_notify_type(notify))
{
- this->ike_sa->enable_extension(this->ike_sa,
- EXT_IKE_FRAGMENTATION);
+ case FRAGMENTATION_SUPPORTED:
+ this->ike_sa->enable_extension(this->ike_sa,
+ EXT_IKE_FRAGMENTATION);
+ break;
+ case SIGNATURE_HASH_ALGORITHMS:
+ if (this->signature_authentication)
+ {
+ handle_supported_hash_algorithms(this, notify);
+ }
+ break;
+ default:
+ /* other notifies are handled elsewhere */
+ break;
}
+
}
default:
break;
@@ -637,6 +764,8 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
.dh_group = MODP_NONE,
.keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa),
.old_sa = old_sa,
+ .signature_authentication = lib->settings->get_bool(lib->settings,
+ "%s.signature_authentication", TRUE, lib->ns),
);
if (initiator)
diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk
index 9b775f9b3..9b6f3f03c 100644
--- a/src/libstrongswan/Android.mk
+++ b/src/libstrongswan/Android.mk
@@ -8,6 +8,7 @@ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
collections/array.c \
collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
+crypto/hashers/hash_algorithm_set.c \
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index 91d92c3f3..47477de12 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -6,6 +6,7 @@ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
collections/array.c \
collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
+crypto/hashers/hash_algorithm_set.c \
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \
@@ -61,7 +62,8 @@ library.h \
asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \
collections/blocking_queue.h collections/enumerator.h collections/hashtable.h \
collections/linked_list.h collections/array.h collections/dictionary.h \
-crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \
+crypto/crypters/crypter.h crypto/hashers/hasher.h \
+crypto/hashers/hash_algorithm_set.h crypto/mac.h \
crypto/proposal/proposal_keywords.h crypto/proposal/proposal_keywords_static.h \
crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \
crypto/prf_plus.h crypto/signers/signer.h crypto/signers/mac_signer.h \
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
index db08c6b96..0ca45a15b 100644
--- a/src/libstrongswan/credentials/auth_cfg.c
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
* Copyright (C) 2007-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -49,6 +49,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_AC_CERT,
"RULE_GROUP",
"RULE_RSA_STRENGTH",
"RULE_ECDSA_STRENGTH",
+ "RULE_BLISS_STRENGTH",
"RULE_SIGNATURE_SCHEME",
"RULE_CERT_POLICY",
"HELPER_IM_CERT",
@@ -71,6 +72,7 @@ static inline bool is_multi_value_rule(auth_rule_t type)
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_IDENTITY:
case AUTH_RULE_IDENTITY_LOOSE:
case AUTH_RULE_EAP_IDENTITY:
@@ -207,6 +209,7 @@ static void init_entry(entry_t *this, auth_rule_t type, va_list args)
case AUTH_RULE_OCSP_VALIDATION:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
/* integer type */
this->value = (void*)(uintptr_t)va_arg(args, u_int);
@@ -255,6 +258,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2)
case AUTH_RULE_OCSP_VALIDATION:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
{
return e1->value == e2->value;
@@ -345,6 +349,7 @@ static void destroy_entry_value(entry_t *entry)
case AUTH_RULE_OCSP_VALIDATION:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
case AUTH_RULE_MAX:
break;
@@ -376,6 +381,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator,
case AUTH_RULE_OCSP_VALIDATION:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
/* integer type */
entry->value = (void*)(uintptr_t)va_arg(args, u_int);
@@ -450,6 +456,7 @@ METHOD(auth_cfg_t, get, void*,
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
return (void*)0;
case AUTH_RULE_SIGNATURE_SCHEME:
return (void*)HASH_UNKNOWN;
@@ -513,6 +520,7 @@ METHOD(auth_cfg_t, complies, bool,
signature_scheme_t scheme = SIGN_UNKNOWN;
u_int strength = 0;
auth_rule_t t1, t2;
+ char *key_type;
void *value;
e1 = constraints->create_enumerator(constraints);
@@ -703,6 +711,7 @@ METHOD(auth_cfg_t, complies, bool,
}
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
{
strength = (uintptr_t)value;
break;
@@ -797,30 +806,39 @@ METHOD(auth_cfg_t, complies, bool,
e2 = create_enumerator(this);
while (e2->enumerate(e2, &t2, &strength))
{
- if (t2 == AUTH_RULE_RSA_STRENGTH ||
- t2 == AUTH_RULE_ECDSA_STRENGTH)
+ switch (t2)
{
- success = FALSE;
- e1 = constraints->create_enumerator(constraints);
- while (e1->enumerate(e1, &t1, &value))
+ default:
+ continue;
+ case AUTH_RULE_RSA_STRENGTH:
+ key_type = "RSA";
+ break;
+ case AUTH_RULE_ECDSA_STRENGTH:
+ key_type = "ECDSA";
+ break;
+ case AUTH_RULE_BLISS_STRENGTH:
+ key_type = "BLISS";
+ break;
+ }
+ success = FALSE;
+ e1 = constraints->create_enumerator(constraints);
+ while (e1->enumerate(e1, &t1, &value))
+ {
+ if (t1 == t2 && (uintptr_t)value <= strength)
{
- if (t1 == t2 && (uintptr_t)value <= strength)
- {
- success = TRUE;
- break;
- }
+ success = TRUE;
+ break;
}
- e1->destroy(e1);
- if (!success)
+ }
+ e1->destroy(e1);
+ if (!success)
+ {
+ if (log_error)
{
- if (log_error)
- {
- DBG1(DBG_CFG, "%s-%d signatures not acceptable",
- t2 == AUTH_RULE_RSA_STRENGTH ? "RSA" : "ECDSA",
- strength);
- }
- break;
+ DBG1(DBG_CFG, "%s-%d signatures not acceptable",
+ key_type, strength);
}
+ break;
}
}
e2->destroy(e2);
@@ -891,6 +909,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
{
add(this, type, (uintptr_t)value);
@@ -1060,6 +1079,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*,
case AUTH_RULE_OCSP_VALIDATION:
case AUTH_RULE_RSA_STRENGTH:
case AUTH_RULE_ECDSA_STRENGTH:
+ case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
clone->add(clone, type, (uintptr_t)value);
break;
diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h
index 95b36d706..53f1b3805 100644
--- a/src/libstrongswan/credentials/auth_cfg.h
+++ b/src/libstrongswan/credentials/auth_cfg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
* Copyright (C) 2007-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -102,6 +102,8 @@ enum auth_rule_t {
AUTH_RULE_RSA_STRENGTH,
/** required ECDSA public key strength, u_int in bits */
AUTH_RULE_ECDSA_STRENGTH,
+ /** required BLISS public key strength, u_int in bits */
+ AUTH_RULE_BLISS_STRENGTH,
/** required signature scheme, signature_scheme_t */
AUTH_RULE_SIGNATURE_SCHEME,
/** certificatePolicy constraint, numerical OID as char* */
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c
index b0c8e48ba..371e6404d 100644
--- a/src/libstrongswan/credentials/credential_manager.c
+++ b/src/libstrongswan/credentials/credential_manager.c
@@ -698,6 +698,9 @@ static void get_key_strength(certificate_t *cert, auth_cfg_t *auth)
case KEY_ECDSA:
auth->add(auth, AUTH_RULE_ECDSA_STRENGTH, strength);
break;
+ case KEY_BLISS:
+ auth->add(auth, AUTH_RULE_BLISS_STRENGTH, strength);
+ break;
default:
break;
}
diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c
index c342ac128..bd5915e60 100644
--- a/src/libstrongswan/credentials/keys/public_key.c
+++ b/src/libstrongswan/credentials/keys/public_key.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
@@ -142,8 +143,151 @@ signature_scheme_t signature_scheme_from_oid(int oid)
return SIGN_BLISS_WITH_SHA256;
case OID_BLISS_WITH_SHA384:
return SIGN_BLISS_WITH_SHA384;
- default:
- return SIGN_UNKNOWN;
}
+ return SIGN_UNKNOWN;
}
+/*
+ * Defined in header.
+ */
+int signature_scheme_to_oid(signature_scheme_t scheme)
+{
+ switch (scheme)
+ {
+ case SIGN_UNKNOWN:
+ case SIGN_RSA_EMSA_PKCS1_NULL:
+ case SIGN_ECDSA_WITH_NULL:
+ case SIGN_ECDSA_256:
+ case SIGN_ECDSA_384:
+ case SIGN_ECDSA_521:
+ break;
+ case SIGN_RSA_EMSA_PKCS1_MD5:
+ return OID_MD5_WITH_RSA;
+ case SIGN_RSA_EMSA_PKCS1_SHA1:
+ return OID_SHA1_WITH_RSA;
+ case SIGN_RSA_EMSA_PKCS1_SHA224:
+ return OID_SHA224_WITH_RSA;
+ case SIGN_RSA_EMSA_PKCS1_SHA256:
+ return OID_SHA256_WITH_RSA;
+ case SIGN_RSA_EMSA_PKCS1_SHA384:
+ return OID_SHA384_WITH_RSA;
+ case SIGN_RSA_EMSA_PKCS1_SHA512:
+ return OID_SHA512_WITH_RSA;
+ case SIGN_ECDSA_WITH_SHA1_DER:
+ return OID_ECDSA_WITH_SHA1;
+ case SIGN_ECDSA_WITH_SHA256_DER:
+ return OID_ECDSA_WITH_SHA256;
+ case SIGN_ECDSA_WITH_SHA384_DER:
+ return OID_ECDSA_WITH_SHA384;
+ case SIGN_ECDSA_WITH_SHA512_DER:
+ return OID_ECDSA_WITH_SHA512;
+ case SIGN_BLISS_WITH_SHA256:
+ return OID_BLISS_WITH_SHA256;
+ case SIGN_BLISS_WITH_SHA384:
+ return OID_BLISS_WITH_SHA384;
+ case SIGN_BLISS_WITH_SHA512:
+ return OID_BLISS_WITH_SHA512;
+ }
+ return OID_UNKNOWN;
+}
+
+/**
+ * Map for signature schemes to the key type and maximum key size allowed.
+ * We only cover schemes with hash algorithms supported by IKEv2 signature
+ * authentication.
+ */
+static struct {
+ signature_scheme_t scheme;
+ key_type_t type;
+ int max_keysize;
+} scheme_map[] = {
+ { SIGN_RSA_EMSA_PKCS1_SHA256, KEY_RSA, 3072 },
+ { SIGN_RSA_EMSA_PKCS1_SHA384, KEY_RSA, 7680 },
+ { SIGN_RSA_EMSA_PKCS1_SHA512, KEY_RSA, 0 },
+ { SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, 256 },
+ { SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, 384 },
+ { SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, 0 },
+ { SIGN_BLISS_WITH_SHA256, KEY_BLISS, 128 },
+ { SIGN_BLISS_WITH_SHA384, KEY_BLISS, 192 },
+ { SIGN_BLISS_WITH_SHA512, KEY_BLISS, 0 },
+};
+
+/**
+ * Private data for signature scheme enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ int index;
+ key_type_t type;
+ int size;
+} private_enumerator_t;
+
+METHOD(enumerator_t, signature_schemes_enumerate, bool,
+ private_enumerator_t *this, signature_scheme_t *scheme)
+{
+ while (++this->index < countof(scheme_map))
+ {
+ if (this->type == scheme_map[this->index].type &&
+ (this->size <= scheme_map[this->index].max_keysize ||
+ !scheme_map[this->index].max_keysize))
+ {
+ *scheme = scheme_map[this->index].scheme;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Defined in header.
+ */
+enumerator_t *signature_schemes_for_key(key_type_t type, int size)
+{
+ private_enumerator_t *this;
+
+ INIT(this,
+ .public = {
+ .enumerate = (void*)_signature_schemes_enumerate,
+ .destroy = (void*)free,
+ },
+ .index = -1,
+ .type = type,
+ .size = size,
+ );
+
+ return &this->public;
+}
+
+/*
+ * Defined in header.
+ */
+key_type_t key_type_from_signature_scheme(signature_scheme_t scheme)
+{
+ switch (scheme)
+ {
+ case SIGN_UNKNOWN:
+ break;
+ case SIGN_RSA_EMSA_PKCS1_NULL:
+ case SIGN_RSA_EMSA_PKCS1_MD5:
+ case SIGN_RSA_EMSA_PKCS1_SHA1:
+ case SIGN_RSA_EMSA_PKCS1_SHA224:
+ case SIGN_RSA_EMSA_PKCS1_SHA256:
+ case SIGN_RSA_EMSA_PKCS1_SHA384:
+ case SIGN_RSA_EMSA_PKCS1_SHA512:
+ return KEY_RSA;
+ case SIGN_ECDSA_WITH_SHA1_DER:
+ case SIGN_ECDSA_WITH_SHA256_DER:
+ case SIGN_ECDSA_WITH_SHA384_DER:
+ case SIGN_ECDSA_WITH_SHA512_DER:
+ case SIGN_ECDSA_WITH_NULL:
+ case SIGN_ECDSA_256:
+ case SIGN_ECDSA_384:
+ case SIGN_ECDSA_521:
+ return KEY_ECDSA;
+ case SIGN_BLISS_WITH_SHA256:
+ case SIGN_BLISS_WITH_SHA384:
+ case SIGN_BLISS_WITH_SHA512:
+ return KEY_BLISS;
+ }
+ return KEY_ANY;
+}
diff --git a/src/libstrongswan/credentials/keys/public_key.h b/src/libstrongswan/credentials/keys/public_key.h
index 9cdcc8e6c..66e98b294 100644
--- a/src/libstrongswan/credentials/keys/public_key.h
+++ b/src/libstrongswan/credentials/keys/public_key.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
@@ -243,8 +244,35 @@ bool public_key_has_fingerprint(public_key_t *public, chunk_t fingerprint);
* Conversion of ASN.1 signature or hash OID to signature scheme.
*
* @param oid ASN.1 OID
- * @return signature_scheme, SIGN_UNKNOWN if OID is unsupported
+ * @return signature scheme, SIGN_UNKNOWN if OID is unsupported
*/
signature_scheme_t signature_scheme_from_oid(int oid);
+/**
+ * Conversion of signature scheme to ASN.1 signature OID.
+ *
+ * @param scheme signature scheme
+ * @return ASN.1 OID, OID_UNKNOWN if not supported
+ */
+int signature_scheme_to_oid(signature_scheme_t scheme);
+
+/**
+ * Enumerate signature schemes that are appropriate for a key of the given type
+ * and size|strength.
+ *
+ * @param type type of the key
+ * @param size size or strength of the key
+ * @return enumerator over signature_scheme_t (increasing strength)
+ */
+enumerator_t *signature_schemes_for_key(key_type_t type, int size);
+
+/**
+ * Determine the type of key associated with a given signature scheme.
+ *
+ * @param scheme signature scheme
+ * @return key type (could be KEY_ANY)
+ */
+key_type_t key_type_from_signature_scheme(signature_scheme_t scheme);
+
+
#endif /** PUBLIC_KEY_H_ @}*/
diff --git a/src/libstrongswan/crypto/hashers/hash_algorithm_set.c b/src/libstrongswan/crypto/hashers/hash_algorithm_set.c
new file mode 100644
index 000000000..93b67cb13
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/hash_algorithm_set.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hash_algorithm_set.h"
+
+#include <collections/array.h>
+
+typedef struct private_hash_algorithm_set_t private_hash_algorithm_set_t;
+
+struct private_hash_algorithm_set_t {
+
+ /**
+ * Public interface
+ */
+ hash_algorithm_set_t public;
+
+ /**
+ * Algorithms contained in the set
+ */
+ array_t *algorithms;
+};
+
+/**
+ * Sort hash algorithms
+ */
+static int hash_sort(const void *a, const void *b, void *user)
+{
+ const hash_algorithm_t *ha = a, *hb = b;
+ return *ha - *hb;
+}
+
+/**
+ * Find a hash algorithm
+ */
+static int hash_find(const void *a, const void *b)
+{
+ return hash_sort(a, b, NULL);
+}
+
+METHOD(hash_algorithm_set_t, contains, bool,
+ private_hash_algorithm_set_t *this, hash_algorithm_t hash)
+{
+ return array_bsearch(this->algorithms, &hash, hash_find, NULL) != -1;
+}
+
+METHOD(hash_algorithm_set_t, add, void,
+ private_hash_algorithm_set_t *this, hash_algorithm_t hash)
+{
+ if (!contains(this, hash))
+ {
+ array_insert(this->algorithms, ARRAY_TAIL, &hash);
+ array_sort(this->algorithms, hash_sort, NULL);
+ }
+}
+
+METHOD(hash_algorithm_set_t, count, int,
+ private_hash_algorithm_set_t *this)
+{
+ return array_count(this->algorithms);
+}
+
+static bool hash_filter(void *data, void **in, hash_algorithm_t *out)
+{
+ *out = **(hash_algorithm_t**)in;
+ return TRUE;
+}
+
+METHOD(hash_algorithm_set_t, create_enumerator, enumerator_t*,
+ private_hash_algorithm_set_t *this)
+{
+ return enumerator_create_filter(array_create_enumerator(this->algorithms),
+ (void*)hash_filter, NULL, NULL);
+}
+
+METHOD(hash_algorithm_set_t, destroy, void,
+ private_hash_algorithm_set_t *this)
+{
+ array_destroy(this->algorithms);
+ free(this);
+}
+
+/**
+ * Described in header
+ */
+hash_algorithm_set_t *hash_algorithm_set_create()
+{
+ private_hash_algorithm_set_t *this;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .contains = _contains,
+ .count = _count,
+ .create_enumerator = _create_enumerator,
+ .destroy = _destroy,
+ },
+ .algorithms = array_create(sizeof(hash_algorithm_t), 0),
+ );
+
+ return &this->public;
+} \ No newline at end of file
diff --git a/src/libstrongswan/crypto/hashers/hash_algorithm_set.h b/src/libstrongswan/crypto/hashers/hash_algorithm_set.h
new file mode 100644
index 000000000..00e90cc2e
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/hash_algorithm_set.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup hash_algorithm_set hash_algorithm_set
+ * @{ @ingroup crypto
+ */
+
+#ifndef HASH_ALGORITHM_SET_H_
+#define HASH_ALGORITHM_SET_H_
+
+typedef struct hash_algorithm_set_t hash_algorithm_set_t;
+
+#include <library.h>
+#include <crypto/hashers/hasher.h>
+
+/**
+ * A set of hash algorithms
+ */
+struct hash_algorithm_set_t {
+
+ /**
+ * Add the given algorithm to the set.
+ *
+ * @param alg hash algorithm
+ */
+ void (*add)(hash_algorithm_set_t *this, hash_algorithm_t alg);
+
+ /**
+ * Check if the given algorithm is contained in the set.
+ *
+ * @param alg hash algorithm
+ * @return TRUE if contained in set
+ */
+ bool (*contains)(hash_algorithm_set_t *this, hash_algorithm_t alg);
+
+ /**
+ * Number of hash algorithms contained in the set.
+ *
+ * @return number of algorithms
+ */
+ int (*count)(hash_algorithm_set_t *this);
+
+ /**
+ * Enumerate the algorithms contained in the set.
+ *
+ * @return enumerator over hash_algorithm_t (sorted by identifier)
+ */
+ enumerator_t *(*create_enumerator)(hash_algorithm_set_t *this);
+
+ /**
+ * Destroy a hash_algorithm_set_t instance
+ */
+ void (*destroy)(hash_algorithm_set_t *this);
+};
+
+/**
+ * Create a set of hash algorithms.
+ *
+ * @return hash_algorithm_set_t instance
+ */
+hash_algorithm_set_t *hash_algorithm_set_create();
+
+#endif /** HASH_ALGORITHM_SET_H_ @}*/
diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c
index a56930325..38eebea9c 100644
--- a/src/libstrongswan/crypto/hashers/hasher.c
+++ b/src/libstrongswan/crypto/hashers/hasher.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -19,29 +19,31 @@
#include <asn1/oid.h>
-ENUM(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA512,
+ENUM_BEGIN(hash_algorithm_names, HASH_SHA1, HASH_SHA512,
+ "HASH_SHA1",
+ "HASH_SHA256",
+ "HASH_SHA384",
+ "HASH_SHA512");
+ENUM_NEXT(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA224, HASH_SHA512,
"HASH_UNKNOWN",
"HASH_MD2",
"HASH_MD4",
"HASH_MD5",
- "HASH_SHA1",
- "HASH_SHA224",
- "HASH_SHA256",
- "HASH_SHA384",
- "HASH_SHA512"
-);
+ "HASH_SHA224");
+ENUM_END(hash_algorithm_names, HASH_SHA224);
-ENUM(hash_algorithm_short_names, HASH_UNKNOWN, HASH_SHA512,
+ENUM_BEGIN(hash_algorithm_short_names, HASH_SHA1, HASH_SHA512,
+ "sha1",
+ "sha256",
+ "sha384",
+ "sha512");
+ENUM_NEXT(hash_algorithm_short_names, HASH_UNKNOWN, HASH_SHA224, HASH_SHA512,
"unknown",
"md2",
"md4",
"md5",
- "sha1",
- "sha224",
- "sha256",
- "sha384",
- "sha512"
-);
+ "sha224");
+ENUM_END(hash_algorithm_short_names, HASH_SHA224);
/*
* Described in header.
@@ -249,6 +251,28 @@ integrity_algorithm_t hasher_algorithm_to_integrity(hash_algorithm_t alg,
/*
* Described in header.
*/
+bool hasher_algorithm_for_ikev2(hash_algorithm_t alg)
+{
+ switch (alg)
+ {
+ case HASH_SHA1:
+ case HASH_SHA256:
+ case HASH_SHA384:
+ case HASH_SHA512:
+ return TRUE;
+ case HASH_UNKNOWN:
+ case HASH_MD2:
+ case HASH_MD4:
+ case HASH_MD5:
+ case HASH_SHA224:
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * Described in header.
+ */
int hasher_algorithm_to_oid(hash_algorithm_t alg)
{
int oid;
@@ -340,3 +364,39 @@ int hasher_signature_algorithm_to_oid(hash_algorithm_t alg, key_type_t key)
}
}
+/*
+ * Defined in header.
+ */
+hash_algorithm_t hasher_from_signature_scheme(signature_scheme_t scheme)
+{
+ switch (scheme)
+ {
+ case SIGN_UNKNOWN:
+ case SIGN_RSA_EMSA_PKCS1_NULL:
+ case SIGN_ECDSA_WITH_NULL:
+ break;
+ case SIGN_RSA_EMSA_PKCS1_MD5:
+ return HASH_MD5;
+ case SIGN_RSA_EMSA_PKCS1_SHA1:
+ case SIGN_ECDSA_WITH_SHA1_DER:
+ return HASH_SHA1;
+ case SIGN_RSA_EMSA_PKCS1_SHA224:
+ return HASH_SHA224;
+ case SIGN_RSA_EMSA_PKCS1_SHA256:
+ case SIGN_ECDSA_WITH_SHA256_DER:
+ case SIGN_ECDSA_256:
+ case SIGN_BLISS_WITH_SHA256:
+ return HASH_SHA256;
+ case SIGN_RSA_EMSA_PKCS1_SHA384:
+ case SIGN_ECDSA_WITH_SHA384_DER:
+ case SIGN_ECDSA_384:
+ case SIGN_BLISS_WITH_SHA384:
+ return HASH_SHA384;
+ case SIGN_RSA_EMSA_PKCS1_SHA512:
+ case SIGN_ECDSA_WITH_SHA512_DER:
+ case SIGN_ECDSA_521:
+ case SIGN_BLISS_WITH_SHA512:
+ return HASH_SHA512;
+ }
+ return HASH_UNKNOWN;
+}
diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h
index 37ef0b6ab..772586308 100644
--- a/src/libstrongswan/crypto/hashers/hasher.h
+++ b/src/libstrongswan/crypto/hashers/hasher.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -32,19 +32,19 @@ typedef struct hasher_t hasher_t;
#include <credentials/keys/public_key.h>
/**
- * Algorithms to use for hashing.
+ * Hash algorithms as defined for IKEv2 by RFC 7427
*/
enum hash_algorithm_t {
- /** not specified hash function */
- HASH_UNKNOWN = 0,
- HASH_MD2 = 1,
- HASH_MD4 = 2,
- HASH_MD5 = 3,
- HASH_SHA1 = 4,
- HASH_SHA224 = 5,
- HASH_SHA256 = 6,
- HASH_SHA384 = 7,
- HASH_SHA512 = 8
+ HASH_SHA1 = 1,
+ HASH_SHA256 = 2,
+ HASH_SHA384 = 3,
+ HASH_SHA512 = 4,
+ /* use private use range for algorithms not defined/permitted by RFC 7427 */
+ HASH_UNKNOWN = 1024,
+ HASH_MD2 = 1025,
+ HASH_MD4 = 1026,
+ HASH_MD5 = 1027,
+ HASH_SHA224 = 1028,
};
#define HASH_SIZE_MD2 16
@@ -163,6 +163,14 @@ integrity_algorithm_t hasher_algorithm_to_integrity(hash_algorithm_t alg,
size_t length);
/**
+ * Check if the given algorithm may be used for IKEv2 signature authentication.
+ *
+ * @param alg hash algorithm
+ * @return TRUE if algorithm may be used, FALSE otherwise
+ */
+bool hasher_algorithm_for_ikev2(hash_algorithm_t alg);
+
+/**
* Conversion of hash algorithm into ASN.1 OID.
*
* @param alg hash algorithm
@@ -179,4 +187,12 @@ int hasher_algorithm_to_oid(hash_algorithm_t alg);
*/
int hasher_signature_algorithm_to_oid(hash_algorithm_t alg, key_type_t key);
+/**
+ * Determine the hash algorithm associated with a given signature scheme.
+ *
+ * @param scheme signature scheme
+ * @return hash algorithm (could be HASH_UNKNOWN)
+ */
+hash_algorithm_t hasher_from_signature_scheme(signature_scheme_t scheme);
+
#endif /** HASHER_H_ @}*/
diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c
index abca4620e..85a854456 100644
--- a/src/libstrongswan/tests/suites/test_utils.c
+++ b/src/libstrongswan/tests/suites/test_utils.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2013-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,6 +18,7 @@
#include <library.h>
#include <utils/utils.h>
#include <ipsec/ipsec_types.h>
+#include <credentials/keys/public_key.h>
#include <time.h>
@@ -695,6 +696,44 @@ START_TEST(test_mark_from_string)
}
END_TEST
+/*******************************************************************************
+ * signature_schemes_for_key
+ */
+
+static struct {
+ key_type_t type;
+ int size;
+ signature_scheme_t expected[4];
+} scheme_data[] = {
+ {KEY_RSA, 1024, { SIGN_RSA_EMSA_PKCS1_SHA256, SIGN_RSA_EMSA_PKCS1_SHA384, SIGN_RSA_EMSA_PKCS1_SHA512, SIGN_UNKNOWN }},
+ {KEY_RSA, 2048, { SIGN_RSA_EMSA_PKCS1_SHA256, SIGN_RSA_EMSA_PKCS1_SHA384, SIGN_RSA_EMSA_PKCS1_SHA512, SIGN_UNKNOWN }},
+ {KEY_RSA, 4096, { SIGN_RSA_EMSA_PKCS1_SHA384, SIGN_RSA_EMSA_PKCS1_SHA512, SIGN_UNKNOWN }},
+ {KEY_RSA, 8192, { SIGN_RSA_EMSA_PKCS1_SHA512, SIGN_UNKNOWN }},
+ {KEY_ECDSA, 256, { SIGN_ECDSA_WITH_SHA256_DER, SIGN_ECDSA_WITH_SHA384_DER, SIGN_ECDSA_WITH_SHA512_DER, SIGN_UNKNOWN }},
+ {KEY_ECDSA, 384, { SIGN_ECDSA_WITH_SHA384_DER, SIGN_ECDSA_WITH_SHA512_DER, SIGN_UNKNOWN }},
+ {KEY_ECDSA, 512, { SIGN_ECDSA_WITH_SHA512_DER, SIGN_UNKNOWN }},
+ {KEY_BLISS, 128, { SIGN_BLISS_WITH_SHA256, SIGN_BLISS_WITH_SHA384, SIGN_BLISS_WITH_SHA512, SIGN_UNKNOWN }},
+ {KEY_BLISS, 192, { SIGN_BLISS_WITH_SHA384, SIGN_BLISS_WITH_SHA512, SIGN_UNKNOWN }},
+ {KEY_BLISS, 256, { SIGN_BLISS_WITH_SHA512, SIGN_UNKNOWN }},
+};
+
+START_TEST(test_signature_schemes_for_key)
+{
+ enumerator_t *enumerator;
+ signature_scheme_t scheme;
+ int i;
+
+ enumerator = signature_schemes_for_key(scheme_data[_i].type, scheme_data[_i].size);
+ for (i = 0; scheme_data[_i].expected[i] != SIGN_UNKNOWN; i++)
+ {
+ ck_assert(enumerator->enumerate(enumerator, &scheme));
+ ck_assert_int_eq(scheme_data[_i].expected[i], scheme);
+ }
+ ck_assert(!enumerator->enumerate(enumerator, &scheme));
+ enumerator->destroy(enumerator);
+}
+END_TEST
+
Suite *utils_suite_create()
{
Suite *s;
@@ -777,5 +816,9 @@ Suite *utils_suite_create()
tcase_add_loop_test(tc, test_mark_from_string, 0, countof(mark_data));
suite_add_tcase(s, tc);
+ tc = tcase_create("signature_schemes_for_key");
+ tcase_add_loop_test(tc, test_signature_schemes_for_key, 0, countof(scheme_data));
+ suite_add_tcase(s, tc);
+
return s;
}