summaryrefslogtreecommitdiff
path: root/src/libstrongswan/crypto/proposal/proposal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/crypto/proposal/proposal.c')
-rw-r--r--src/libstrongswan/crypto/proposal/proposal.c236
1 files changed, 199 insertions, 37 deletions
diff --git a/src/libstrongswan/crypto/proposal/proposal.c b/src/libstrongswan/crypto/proposal/proposal.c
index bb0a02b59..d671879c0 100644
--- a/src/libstrongswan/crypto/proposal/proposal.c
+++ b/src/libstrongswan/crypto/proposal/proposal.c
@@ -58,6 +58,11 @@ struct private_proposal_t {
array_t *transforms;
/**
+ * Types of transforms contained, as transform_type_t
+ */
+ array_t *types;
+
+ /**
* senders SPI
*/
uint64_t spi;
@@ -69,6 +74,101 @@ struct private_proposal_t {
};
/**
+ * This is a hack to not change the previous order when printing proposals
+ */
+static transform_type_t type_for_sort(const void *type)
+{
+ const transform_type_t *t = type;
+
+ switch (*t)
+ {
+ case PSEUDO_RANDOM_FUNCTION:
+ return INTEGRITY_ALGORITHM;
+ case INTEGRITY_ALGORITHM:
+ return PSEUDO_RANDOM_FUNCTION;
+ default:
+ return *t;
+ }
+}
+
+/**
+ * Sort transform types
+ */
+static int type_sort(const void *a, const void *b, void *user)
+{
+ transform_type_t ta = type_for_sort(a), tb = type_for_sort(b);
+ return ta - tb;
+}
+
+/**
+ * Find a transform type
+ */
+static int type_find(const void *a, const void *b)
+{
+ return type_sort(a, b, NULL);
+}
+
+/**
+ * Check if the given transform type is already in the set
+ */
+static bool contains_type(array_t *types, transform_type_t type)
+{
+ return array_bsearch(types, &type, type_find, NULL) != -1;
+}
+
+/**
+ * Add the given transform type to the set
+ */
+static void add_type(array_t *types, transform_type_t type)
+{
+ if (!contains_type(types, type))
+ {
+ array_insert(types, ARRAY_TAIL, &type);
+ array_sort(types, type_sort, NULL);
+ }
+}
+
+/**
+ * Merge two sets of transform types into a new array
+ */
+static array_t *merge_types(private_proposal_t *this, private_proposal_t *other)
+{
+ array_t *types;
+ transform_type_t type;
+ int i, count;
+
+ count = max(array_count(this->types), array_count(other->types));
+ types = array_create(sizeof(transform_type_t), count);
+
+ for (i = 0; i < count; i++)
+ {
+ if (array_get(this->types, i, &type))
+ {
+ add_type(types, type);
+ }
+ if (array_get(other->types, i, &type))
+ {
+ add_type(types, type);
+ }
+ }
+ return types;
+}
+
+/**
+ * Remove the given transform type from the set
+ */
+static void remove_type(private_proposal_t *this, transform_type_t type)
+{
+ int i;
+
+ i = array_bsearch(this->types, &type, type_find, NULL);
+ if (i >= 0)
+ {
+ array_remove(this->types, i, NULL);
+ }
+}
+
+/**
* Struct used to store different kinds of algorithms.
*/
typedef struct {
@@ -91,6 +191,7 @@ METHOD(proposal_t, add_algorithm, void,
};
array_insert(this->transforms, ARRAY_TAIL, &entry);
+ add_type(this->types, type);
}
CALLBACK(alg_filter, bool,
@@ -206,17 +307,31 @@ METHOD(proposal_t, strip_dh, void,
{
enumerator_t *enumerator;
entry_t *entry;
+ bool found = FALSE;
enumerator = array_create_enumerator(this->transforms);
while (enumerator->enumerate(enumerator, &entry))
{
- if (entry->type == DIFFIE_HELLMAN_GROUP &&
- entry->alg != keep)
+ if (entry->type == DIFFIE_HELLMAN_GROUP)
{
- array_remove_at(this->transforms, enumerator);
+ if (entry->alg != keep)
+ {
+ array_remove_at(this->transforms, enumerator);
+ }
+ else
+ {
+ found = TRUE;
+ }
}
}
enumerator->destroy(enumerator);
+ array_compress(this->transforms);
+
+ if (keep == MODP_NONE || !found)
+ {
+ remove_type(this, DIFFIE_HELLMAN_GROUP);
+ array_compress(this->types);
+ }
}
/**
@@ -310,6 +425,9 @@ METHOD(proposal_t, select_proposal, proposal_t*,
bool private)
{
proposal_t *selected;
+ transform_type_t type;
+ array_t *types;
+ int i;
DBG2(DBG_CFG, "selecting proposal:");
@@ -328,18 +446,20 @@ METHOD(proposal_t, select_proposal, proposal_t*,
{
selected = proposal_create(this->protocol, this->number);
selected->set_spi(selected, this->spi);
-
}
- if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
- !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
- !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
- !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
- !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
+ types = merge_types(this, (private_proposal_t*)other);
+ for (i = 0; i < array_count(types); i++)
{
- selected->destroy(selected);
- return NULL;
+ array_get(types, i, &type);
+ if (!select_algo(this, other, selected, type, private))
+ {
+ selected->destroy(selected);
+ array_destroy(types);
+ return NULL;
+ }
}
+ array_destroy(types);
DBG2(DBG_CFG, " proposal matches");
return selected;
@@ -409,16 +529,27 @@ METHOD(proposal_t, get_number, u_int,
METHOD(proposal_t, equals, bool,
private_proposal_t *this, proposal_t *other)
{
+ transform_type_t type;
+ array_t *types;
+ int i;
+
if (&this->public == other)
{
return TRUE;
}
- return (
- algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
- algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
- algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
- algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
- algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
+
+ types = merge_types(this, (private_proposal_t*)other);
+ for (i = 0; i < array_count(types); i++)
+ {
+ array_get(types, i, &type);
+ if (!algo_list_equals(this, other, type))
+ {
+ array_destroy(types);
+ return FALSE;
+ }
+ }
+ array_destroy(types);
+ return TRUE;
}
METHOD(proposal_t, clone_, proposal_t*,
@@ -427,6 +558,7 @@ METHOD(proposal_t, clone_, proposal_t*,
private_proposal_t *clone;
enumerator_t *enumerator;
entry_t *entry;
+ transform_type_t *type;
clone = (private_proposal_t*)proposal_create(this->protocol, 0);
@@ -436,6 +568,12 @@ METHOD(proposal_t, clone_, proposal_t*,
array_insert(clone->transforms, ARRAY_TAIL, entry);
}
enumerator->destroy(enumerator);
+ enumerator = array_create_enumerator(this->types);
+ while (enumerator->enumerate(enumerator, &type))
+ {
+ array_insert(clone->types, ARRAY_TAIL, type);
+ }
+ enumerator->destroy(enumerator);
clone->spi = this->spi;
clone->number = this->number;
@@ -479,6 +617,7 @@ static void remove_transform(private_proposal_t *this, transform_type_t type)
}
}
e->destroy(e);
+ remove_type(this, type);
}
/**
@@ -571,6 +710,14 @@ static bool check_proposal(private_proposal_t *this)
* we MUST NOT propose any integrity algorithms */
remove_transform(this, INTEGRITY_ALGORITHM);
}
+ else if (this->protocol == PROTO_IKE &&
+ !get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
+ {
+ DBG1(DBG_CFG, "an integrity algorithm is mandatory in %N proposals "
+ "with classic (non-AEAD) encryption algorithms",
+ protocol_id_names, this->protocol);
+ return FALSE;
+ }
}
else
{ /* AES-GMAC is parsed as encryption algorithm, so we map that to the
@@ -605,6 +752,7 @@ static bool check_proposal(private_proposal_t *this)
}
}
e->destroy(e);
+ remove_type(this, ENCRYPTION_ALGORITHM);
if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
{
@@ -623,6 +771,7 @@ static bool check_proposal(private_proposal_t *this)
}
array_compress(this->transforms);
+ array_compress(this->types);
return TRUE;
}
@@ -646,30 +795,44 @@ static bool add_string_algo(private_proposal_t *this, const char *alg)
}
/**
- * print all algorithms of a kind to buffer
+ * Print all algorithms of the given type
*/
static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
- u_int kind, void *names, bool *first)
+ transform_type_t type, bool *first)
{
enumerator_t *enumerator;
size_t written = 0;
- uint16_t alg, size;
+ entry_t *entry;
+ enum_name_t *names;
+
+ names = transform_get_enum_names(type);
- enumerator = create_enumerator(this, kind);
- while (enumerator->enumerate(enumerator, &alg, &size))
+ enumerator = array_create_enumerator(this->transforms);
+ while (enumerator->enumerate(enumerator, &entry))
{
+ char *prefix = "/";
+
+ if (type != entry->type)
+ {
+ continue;
+ }
if (*first)
{
- written += print_in_hook(data, "%N", names, alg);
+ prefix = "";
*first = FALSE;
}
+ if (names)
+ {
+ written += print_in_hook(data, "%s%N", prefix, names, entry->alg);
+ }
else
{
- written += print_in_hook(data, "/%N", names, alg);
+ written += print_in_hook(data, "%sUNKNOWN_%u_%u", prefix,
+ entry->type, entry->alg);
}
- if (size)
+ if (entry->key_size)
{
- written += print_in_hook(data, "_%u", size);
+ written += print_in_hook(data, "_%u", entry->key_size);
}
}
enumerator->destroy(enumerator);
@@ -685,6 +848,7 @@ int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
private_proposal_t *this = *((private_proposal_t**)(args[0]));
linked_list_t *list = *((linked_list_t**)(args[0]));
enumerator_t *enumerator;
+ transform_type_t *type;
size_t written = 0;
bool first = TRUE;
@@ -713,16 +877,12 @@ int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
}
written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
- written += print_alg(this, data, ENCRYPTION_ALGORITHM,
- encryption_algorithm_names, &first);
- written += print_alg(this, data, INTEGRITY_ALGORITHM,
- integrity_algorithm_names, &first);
- written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION,
- pseudo_random_function_names, &first);
- written += print_alg(this, data, DIFFIE_HELLMAN_GROUP,
- diffie_hellman_group_names, &first);
- written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS,
- extended_sequence_numbers_names, &first);
+ enumerator = array_create_enumerator(this->types);
+ while (enumerator->enumerate(enumerator, &type))
+ {
+ written += print_alg(this, data, *type, &first);
+ }
+ enumerator->destroy(enumerator);
return written;
}
@@ -730,6 +890,7 @@ METHOD(proposal_t, destroy, void,
private_proposal_t *this)
{
array_destroy(this->transforms);
+ array_destroy(this->types);
free(this);
}
@@ -760,6 +921,7 @@ proposal_t *proposal_create(protocol_id_t protocol, u_int number)
.protocol = protocol,
.number = number,
.transforms = array_create(sizeof(entry_t), 0),
+ .types = array_create(sizeof(transform_type_t), 0),
);
return &this->public;
@@ -794,7 +956,7 @@ static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
break;
case ENCR_CHACHA20_POLY1305:
- add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
break;
default:
break;