diff --git a/src/libstrongswan/crypto/proposal/proposal.c b/src/libstrongswan/crypto/proposal/proposal.c index 97cb2471fe..4f1b260f2b 100644 --- a/src/libstrongswan/crypto/proposal/proposal.c +++ b/src/libstrongswan/crypto/proposal/proposal.c @@ -20,6 +20,7 @@ #include "proposal.h" #include +#include #include #include @@ -315,7 +316,7 @@ METHOD(proposal_t, promote_transform, bool, */ static bool select_algo(private_proposal_t *this, proposal_t *other, transform_type_t type, proposal_selection_flag_t flags, - bool log, uint16_t *alg, uint16_t *ks) + hashtable_t *kes, bool log, uint16_t *alg, uint16_t *ks) { enumerator_t *e1, *e2; uint16_t alg1, alg2, ks1, ks2; @@ -358,9 +359,13 @@ static bool select_algo(private_proposal_t *this, proposal_t *other, e1->destroy(e1); e1 = create_enumerator(this, type); - /* compare algs, order of algs in "first" is preferred */ + /* compare algs, order of algs in "e1" is preferred */ while (!found && e1->enumerate(e1, &alg1, &ks1)) { + if (is_ke_transform(type) && kes->get(kes, (void*)(uintptr_t)alg1)) + { + continue; + } e2->destroy(e2); e2 = other->create_enumerator(other, type); while (e2->enumerate(e2, &alg2, &ks2)) @@ -389,6 +394,23 @@ static bool select_algo(private_proposal_t *this, proposal_t *other, return found; } +/** + * Hash an algorithm identifier + */ +static u_int hash_alg(const void *key) +{ + uint16_t alg = (uint16_t)(uintptr_t)key; + return chunk_hash(chunk_from_thing(alg)); +} + +/** + * Compare two algorithm identifiers + */ +static bool equals_alg(const void *key, const void *other_key) +{ + return (uint16_t)(uintptr_t)key == (uint16_t)(uintptr_t)other_key; +} + /** * Select algorithms from the given proposals, if selected is given, the result * is stored there and errors are logged. @@ -397,10 +419,13 @@ static bool select_algos(private_proposal_t *this, proposal_t *other, proposal_t *selected, proposal_selection_flag_t flags) { transform_type_t type; + hashtable_t *kes; array_t *types; bool skip_integrity = FALSE; int i; + kes = hashtable_create(hash_alg, equals_alg, 8); + types = merge_types(this, (private_proposal_t*)other); for (i = 0; i < array_count(types); i++) { @@ -415,7 +440,8 @@ static bool select_algos(private_proposal_t *this, proposal_t *other, { continue; } - if (select_algo(this, other, type, flags, selected != NULL, &alg, &ks)) + if (select_algo(this, other, type, flags, kes, selected != NULL, + &alg, &ks)) { if (alg == 0 && type != EXTENDED_SEQUENCE_NUMBERS) { /* 0 is "valid" for extended sequence numbers, for other @@ -426,6 +452,10 @@ static bool select_algos(private_proposal_t *this, proposal_t *other, { selected->add_algorithm(selected, type, alg, ks); } + if (is_ke_transform(type)) + { + kes->put(kes, (void*)(uintptr_t)alg, (void*)(uintptr_t)alg); + } if (type == ENCRYPTION_ALGORITHM && encryption_algorithm_is_aead(alg)) { @@ -441,10 +471,12 @@ static bool select_algos(private_proposal_t *this, proposal_t *other, type); } array_destroy(types); + kes->destroy(kes); return FALSE; } } array_destroy(types); + kes->destroy(kes); return TRUE; } diff --git a/src/libstrongswan/tests/suites/test_proposal.c b/src/libstrongswan/tests/suites/test_proposal.c index af028c31a7..5bdc53fefd 100644 --- a/src/libstrongswan/tests/suites/test_proposal.c +++ b/src/libstrongswan/tests/suites/test_proposal.c @@ -142,6 +142,28 @@ static struct { { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072", "aes128-sha256-modp3072" }, { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072-none", "aes128-sha256-modp3072" }, { PROTO_IKE, "aes128-sha256-modp3072-none", "aes128-sha256-modp3072", "aes128-sha256-modp3072" }, + { PROTO_IKE, "aes128-sha256-modp3072-ke1_modp3072", + "aes128-sha256-modp3072-ke1_modp3072", NULL }, + { PROTO_IKE, "aes128-sha256-modp3072-ecp256-ecp384-ke1_modp3072-ke1_ecp256-ke1_ecp384-ke2_modp3072-ke2_ecp256-ke2_ecp384", + "aes128-sha256-modp3072-ecp256-ecp384-ke1_modp3072-ke1_ecp256-ke1_ecp384-ke2_modp3072-ke2_ecp256-ke2_ecp384", + "aes128-sha256-modp3072-ke1_ecp256-ke2_ecp384" }, + { PROTO_IKE, "aes128-sha256-modp3072-ke1_modp3072-ke1_none", + "aes128-sha256-modp3072-ke1_modp3072-ke1_none", + "aes128-sha256-modp3072" }, + { PROTO_IKE, "aes128-sha256-modp3072-ke1_modp3072-ke1_none-ke2_modp3072-ke2_none", + "aes128-sha256-modp3072-ke1_modp3072-ke1_none-ke2_modp3072-ke2_none", + "aes128-sha256-modp3072" }, + { PROTO_IKE, "aes128-sha256-modp3072-ke1_modp3072-ke1_ecp256", + "aes128-sha256-modp3072-ke1_modp3072-ke1_ecp256", + "aes128-sha256-modp3072-ke1_ecp256" }, + { PROTO_IKE, "aes128-sha256-modp3072-ke1_modp3072-ke1_ecp256", + "aes128-sha256-modp3072-ke1_ecp256", + "aes128-sha256-modp3072-ke1_ecp256" }, + { PROTO_IKE, "aes128-sha256-modp3072-ke1_ecp256", + "aes128-sha256-modp3072-ke1_modp3072-ke1_ecp256", + "aes128-sha256-modp3072-ke1_ecp256" }, + { PROTO_IKE, "aes128-sha256-ecp256-ke1_modp3072", + "aes128-sha256-modp3072-ecp256-ke1_ecp256-ke2_ecp384", NULL }, }; START_TEST(test_select)