proposal: Move proposal_t from libcharon to libstrongswan
authorTobias Brunner <tobias@strongswan.org>
Fri, 17 Nov 2017 16:15:14 +0000 (17:15 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 17 Nov 2017 17:09:54 +0000 (18:09 +0100)
This allows us to use it without having to initialize libcharon, which
was required for the logging (we probably could have included debug.h
instead of daemon.h to workaround that but this seems more correct).

29 files changed:
src/charon-tkm/tests/keymat_tests.c
src/conftest/hooks/custom_proposal.c
src/libcharon/Android.mk
src/libcharon/Makefile.am
src/libcharon/config/child_cfg.h
src/libcharon/config/ike_cfg.h
src/libcharon/config/peer_cfg.h
src/libcharon/config/proposal.c [deleted file]
src/libcharon/config/proposal.h [deleted file]
src/libcharon/daemon.c
src/libcharon/encoding/payloads/proposal_substructure.h
src/libcharon/encoding/payloads/transform_substructure.h
src/libcharon/processing/jobs/delete_child_sa_job.h
src/libcharon/processing/jobs/rekey_child_sa_job.h
src/libcharon/processing/jobs/update_sa_job.h
src/libcharon/sa/child_sa.h
src/libcharon/sa/keymat.h
src/libcharon/tests/Makefile.am
src/libcharon/tests/libcharon_tests.h
src/libcharon/tests/suites/test_proposal.c [deleted file]
src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/crypto/proposal/proposal.c [new file with mode: 0644]
src/libstrongswan/crypto/proposal/proposal.h [new file with mode: 0644]
src/libstrongswan/crypto/proposal/proposal_keywords.h
src/libstrongswan/library.c
src/libstrongswan/tests/Makefile.am
src/libstrongswan/tests/suites/test_proposal.c [new file with mode: 0644]
src/libstrongswan/tests/tests.h

index 8bba1f9..d4751f7 100644 (file)
@@ -17,7 +17,7 @@
 #include <tests/test_suite.h>
 
 #include <daemon.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <encoding/payloads/ike_header.h>
 #include <tkm/client.h>
 
index c4f8385..5e1cec0 100644 (file)
@@ -18,7 +18,7 @@
 #include <errno.h>
 
 #include <encoding/payloads/sa_payload.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 typedef struct private_custom_proposal_t private_custom_proposal_t;
 
index f381860..d1fb337 100644 (file)
@@ -16,7 +16,6 @@ config/backend_manager.c config/backend_manager.h config/backend.h \
 config/child_cfg.c config/child_cfg.h \
 config/ike_cfg.c config/ike_cfg.h \
 config/peer_cfg.c config/peer_cfg.h \
-config/proposal.c config/proposal.h \
 control/controller.c control/controller.h \
 daemon.c daemon.h \
 encoding/generator.c encoding/generator.h \
index 964a19e..fe28f1e 100644 (file)
@@ -14,7 +14,6 @@ config/backend_manager.c config/backend_manager.h config/backend.h \
 config/child_cfg.c config/child_cfg.h \
 config/ike_cfg.c config/ike_cfg.h \
 config/peer_cfg.c config/peer_cfg.h \
-config/proposal.c config/proposal.h \
 control/controller.c control/controller.h \
 daemon.c daemon.h \
 encoding/generator.c encoding/generator.h \
index 93904ec..e2834fa 100644 (file)
@@ -31,7 +31,7 @@ typedef struct child_cfg_create_t child_cfg_create_t;
 
 #include <library.h>
 #include <selectors/traffic_selector.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <kernel/kernel_ipsec.h>
 
 /**
index 034996f..3020244 100644 (file)
@@ -31,7 +31,7 @@ typedef struct ike_cfg_t ike_cfg_t;
 #include <networking/host.h>
 #include <collections/linked_list.h>
 #include <utils/identification.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <crypto/diffie_hellman.h>
 
 /**
index b294ae7..6074a7c 100644 (file)
@@ -32,7 +32,7 @@ typedef struct peer_cfg_create_t peer_cfg_create_t;
 #include <utils/identification.h>
 #include <collections/enumerator.h>
 #include <selectors/traffic_selector.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <config/ike_cfg.h>
 #include <config/child_cfg.h>
 #include <credentials/auth_cfg.h>
diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c
deleted file mode 100644 (file)
index 46c3c94..0000000
+++ /dev/null
@@ -1,1103 +0,0 @@
-/*
- * Copyright (C) 2008-2016 Tobias Brunner
- * Copyright (C) 2006-2010 Martin Willi
- * Copyright (C) 2013-2015 Andreas Steffen
- * 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 <string.h>
-
-#include "proposal.h"
-
-#include <daemon.h>
-#include <collections/array.h>
-#include <utils/identification.h>
-
-#include <crypto/transform.h>
-#include <crypto/prfs/prf.h>
-#include <crypto/crypters/crypter.h>
-#include <crypto/signers/signer.h>
-
-ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
-       "PROTO_NONE",
-       "IKE",
-       "AH",
-       "ESP",
-       "IPCOMP",
-);
-
-typedef struct private_proposal_t private_proposal_t;
-
-/**
- * Private data of an proposal_t object
- */
-struct private_proposal_t {
-
-       /**
-        * Public part
-        */
-       proposal_t public;
-
-       /**
-        * protocol (ESP or AH)
-        */
-       protocol_id_t protocol;
-
-       /**
-        * Priority ordered list of transforms, as entry_t
-        */
-       array_t *transforms;
-
-       /**
-        * senders SPI
-        */
-       uint64_t spi;
-
-       /**
-        * Proposal number
-        */
-       u_int number;
-};
-
-/**
- * Struct used to store different kinds of algorithms.
- */
-typedef struct {
-       /** Type of the transform */
-       transform_type_t type;
-       /** algorithm identifier */
-       uint16_t alg;
-       /** key size in bits, or zero if not needed */
-       uint16_t key_size;
-} entry_t;
-
-METHOD(proposal_t, add_algorithm, void,
-       private_proposal_t *this, transform_type_t type,
-       uint16_t alg, uint16_t key_size)
-{
-       entry_t entry = {
-               .type = type,
-               .alg = alg,
-               .key_size = key_size,
-       };
-
-       array_insert(this->transforms, ARRAY_TAIL, &entry);
-}
-
-CALLBACK(alg_filter, bool,
-       uintptr_t type, enumerator_t *orig, va_list args)
-{
-       entry_t *entry;
-       uint16_t *alg, *key_size;
-
-       VA_ARGS_VGET(args, alg, key_size);
-
-       while (orig->enumerate(orig, &entry))
-       {
-               if (entry->type != type)
-               {
-                       continue;
-               }
-               if (alg)
-               {
-                       *alg = entry->alg;
-               }
-               if (key_size)
-               {
-                       *key_size = entry->key_size;
-               }
-               return TRUE;
-       }
-       return FALSE;
-}
-
-METHOD(proposal_t, create_enumerator, enumerator_t*,
-       private_proposal_t *this, transform_type_t type)
-{
-       return enumerator_create_filter(
-                                               array_create_enumerator(this->transforms),
-                                               alg_filter, (void*)(uintptr_t)type, NULL);
-}
-
-METHOD(proposal_t, get_algorithm, bool,
-       private_proposal_t *this, transform_type_t type,
-       uint16_t *alg, uint16_t *key_size)
-{
-       enumerator_t *enumerator;
-       bool found = FALSE;
-
-       enumerator = create_enumerator(this, type);
-       if (enumerator->enumerate(enumerator, alg, key_size))
-       {
-               found = TRUE;
-       }
-       enumerator->destroy(enumerator);
-
-       return found;
-}
-
-METHOD(proposal_t, has_dh_group, bool,
-       private_proposal_t *this, diffie_hellman_group_t group)
-{
-       bool found = FALSE, any = FALSE;
-       enumerator_t *enumerator;
-       uint16_t current;
-
-       enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
-       while (enumerator->enumerate(enumerator, &current, NULL))
-       {
-               any = TRUE;
-               if (current == group)
-               {
-                       found = TRUE;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       if (!any && group == MODP_NONE)
-       {
-               found = TRUE;
-       }
-       return found;
-}
-
-METHOD(proposal_t, strip_dh, void,
-       private_proposal_t *this, diffie_hellman_group_t keep)
-{
-       enumerator_t *enumerator;
-       entry_t *entry;
-
-       enumerator = array_create_enumerator(this->transforms);
-       while (enumerator->enumerate(enumerator, &entry))
-       {
-               if (entry->type == DIFFIE_HELLMAN_GROUP &&
-                       entry->alg != keep)
-               {
-                       array_remove_at(this->transforms, enumerator);
-               }
-       }
-       enumerator->destroy(enumerator);
-}
-
-/**
- * Select a matching proposal from this and other, insert into selected.
- */
-static bool select_algo(private_proposal_t *this, proposal_t *other,
-                                               proposal_t *selected, transform_type_t type, bool priv)
-{
-       enumerator_t *e1, *e2;
-       uint16_t alg1, alg2, ks1, ks2;
-       bool found = FALSE, optional = FALSE;
-
-       if (type == INTEGRITY_ALGORITHM &&
-               selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
-               encryption_algorithm_is_aead(alg1))
-       {
-               /* no integrity algorithm required, we have an AEAD */
-               return TRUE;
-       }
-       if (type == DIFFIE_HELLMAN_GROUP)
-       {
-               optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
-       }
-
-       e1 = create_enumerator(this, type);
-       e2 = other->create_enumerator(other, type);
-       if (!e1->enumerate(e1, &alg1, NULL))
-       {
-               if (!e2->enumerate(e2, &alg2, NULL))
-               {
-                       found = TRUE;
-               }
-               else if (optional)
-               {
-                       do
-                       {       /* if NONE is proposed, we accept the proposal */
-                               found = !alg2;
-                       }
-                       while (!found && e2->enumerate(e2, &alg2, NULL));
-               }
-       }
-       else if (!e2->enumerate(e2, NULL, NULL))
-       {
-               if (optional)
-               {
-                       do
-                       {       /* if NONE is proposed, we accept the proposal */
-                               found = !alg1;
-                       }
-                       while (!found && e1->enumerate(e1, &alg1, NULL));
-               }
-       }
-
-       e1->destroy(e1);
-       e1 = create_enumerator(this, type);
-       /* compare algs, order of algs in "first" is preferred */
-       while (!found && e1->enumerate(e1, &alg1, &ks1))
-       {
-               e2->destroy(e2);
-               e2 = other->create_enumerator(other, type);
-               while (e2->enumerate(e2, &alg2, &ks2))
-               {
-                       if (alg1 == alg2 && ks1 == ks2)
-                       {
-                               if (!priv && alg1 >= 1024)
-                               {
-                                       /* accept private use algorithms only if requested */
-                                       DBG1(DBG_CFG, "an algorithm from private space would match, "
-                                                "but peer implementation is unknown, skipped");
-                                       continue;
-                               }
-                               selected->add_algorithm(selected, type, alg1, ks1);
-                               found = TRUE;
-                               break;
-                       }
-               }
-       }
-       /* no match in all comparisons */
-       e1->destroy(e1);
-       e2->destroy(e2);
-
-       if (!found)
-       {
-               DBG2(DBG_CFG, "  no acceptable %N found", transform_type_names, type);
-       }
-       return found;
-}
-
-METHOD(proposal_t, select_proposal, proposal_t*,
-       private_proposal_t *this, proposal_t *other, bool other_remote,
-       bool private)
-{
-       proposal_t *selected;
-
-       DBG2(DBG_CFG, "selecting proposal:");
-
-       if (this->protocol != other->get_protocol(other))
-       {
-               DBG2(DBG_CFG, "  protocol mismatch, skipping");
-               return NULL;
-       }
-
-       if (other_remote)
-       {
-               selected = proposal_create(this->protocol, other->get_number(other));
-               selected->set_spi(selected, other->get_spi(other));
-       }
-       else
-       {
-               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))
-       {
-               selected->destroy(selected);
-               return NULL;
-       }
-
-       DBG2(DBG_CFG, "  proposal matches");
-       return selected;
-}
-
-METHOD(proposal_t, get_protocol, protocol_id_t,
-       private_proposal_t *this)
-{
-       return this->protocol;
-}
-
-METHOD(proposal_t, set_spi, void,
-       private_proposal_t *this, uint64_t spi)
-{
-       this->spi = spi;
-}
-
-METHOD(proposal_t, get_spi, uint64_t,
-       private_proposal_t *this)
-{
-       return this->spi;
-}
-
-/**
- * Check if two proposals have the same algorithms for a given transform type
- */
-static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
-                                                        transform_type_t type)
-{
-       enumerator_t *e1, *e2;
-       uint16_t alg1, alg2, ks1, ks2;
-       bool equals = TRUE;
-
-       e1 = create_enumerator(this, type);
-       e2 = other->create_enumerator(other, type);
-       while (e1->enumerate(e1, &alg1, &ks1))
-       {
-               if (!e2->enumerate(e2, &alg2, &ks2))
-               {
-                       /* this has more algs */
-                       equals = FALSE;
-                       break;
-               }
-               if (alg1 != alg2 || ks1 != ks2)
-               {
-                       equals = FALSE;
-                       break;
-               }
-       }
-       if (e2->enumerate(e2, &alg2, &ks2))
-       {
-               /* other has more algs */
-               equals = FALSE;
-       }
-       e1->destroy(e1);
-       e2->destroy(e2);
-
-       return equals;
-}
-
-METHOD(proposal_t, get_number, u_int,
-       private_proposal_t *this)
-{
-       return this->number;
-}
-
-METHOD(proposal_t, equals, bool,
-       private_proposal_t *this, proposal_t *other)
-{
-       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));
-}
-
-METHOD(proposal_t, clone_, proposal_t*,
-       private_proposal_t *this)
-{
-       private_proposal_t *clone;
-       enumerator_t *enumerator;
-       entry_t *entry;
-
-       clone = (private_proposal_t*)proposal_create(this->protocol, 0);
-
-       enumerator = array_create_enumerator(this->transforms);
-       while (enumerator->enumerate(enumerator, &entry))
-       {
-               array_insert(clone->transforms, ARRAY_TAIL, entry);
-       }
-       enumerator->destroy(enumerator);
-
-       clone->spi = this->spi;
-       clone->number = this->number;
-
-       return &clone->public;
-}
-
-/**
- * Map integrity algorithms to the PRF functions using the same algorithm.
- */
-static const struct {
-       integrity_algorithm_t integ;
-       pseudo_random_function_t prf;
-} integ_prf_map[] = {
-       {AUTH_HMAC_SHA1_96,                                     PRF_HMAC_SHA1                                   },
-       {AUTH_HMAC_SHA1_160,                            PRF_HMAC_SHA1                                   },
-       {AUTH_HMAC_SHA2_256_128,                        PRF_HMAC_SHA2_256                               },
-       {AUTH_HMAC_SHA2_384_192,                        PRF_HMAC_SHA2_384                               },
-       {AUTH_HMAC_SHA2_512_256,                        PRF_HMAC_SHA2_512                               },
-       {AUTH_HMAC_MD5_96,                                      PRF_HMAC_MD5                                    },
-       {AUTH_HMAC_MD5_128,                                     PRF_HMAC_MD5                                    },
-       {AUTH_AES_XCBC_96,                                      PRF_AES128_XCBC                                 },
-       {AUTH_CAMELLIA_XCBC_96,                         PRF_CAMELLIA128_XCBC                    },
-       {AUTH_AES_CMAC_96,                                      PRF_AES128_CMAC                                 },
-};
-
-/**
- * Remove all entries of the given transform type
- */
-static void remove_transform(private_proposal_t *this, transform_type_t type)
-{
-       enumerator_t *e;
-       entry_t *entry;
-
-       e = array_create_enumerator(this->transforms);
-       while (e->enumerate(e, &entry))
-       {
-               if (entry->type == type)
-               {
-                       array_remove_at(this->transforms, e);
-               }
-       }
-       e->destroy(e);
-}
-
-/**
- * Checks the proposal read from a string.
- */
-static bool check_proposal(private_proposal_t *this)
-{
-       enumerator_t *e;
-       entry_t *entry;
-       uint16_t alg, ks;
-       bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
-       int i;
-
-       if (this->protocol == PROTO_IKE)
-       {
-               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
-               {       /* No explicit PRF found. We assume the same algorithm as used
-                        * for integrity checking. */
-                       e = create_enumerator(this, INTEGRITY_ALGORITHM);
-                       while (e->enumerate(e, &alg, &ks))
-                       {
-                               for (i = 0; i < countof(integ_prf_map); i++)
-                               {
-                                       if (alg == integ_prf_map[i].integ)
-                                       {
-                                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
-                                                                         integ_prf_map[i].prf, 0);
-                                               break;
-                                       }
-                               }
-                       }
-                       e->destroy(e);
-               }
-               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
-               {
-                       DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
-                       return FALSE;
-               }
-               /* remove MODP_NONE from IKE proposal */
-               e = array_create_enumerator(this->transforms);
-               while (e->enumerate(e, &entry))
-               {
-                       if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
-                       {
-                               array_remove_at(this->transforms, e);
-                       }
-               }
-               e->destroy(e);
-               if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
-               {
-                       DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
-                       return FALSE;
-               }
-       }
-       else
-       {       /* remove PRFs from ESP/AH proposals */
-               remove_transform(this, PSEUDO_RANDOM_FUNCTION);
-       }
-
-       if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
-       {
-               e = create_enumerator(this, ENCRYPTION_ALGORITHM);
-               while (e->enumerate(e, &alg, &ks))
-               {
-                       any_enc = TRUE;
-                       if (encryption_algorithm_is_aead(alg))
-                       {
-                               any_aead = TRUE;
-                               continue;
-                       }
-                       all_aead = FALSE;
-               }
-               e->destroy(e);
-
-               if (!any_enc)
-               {
-                       DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
-                                protocol_id_names, this->protocol);
-                       return FALSE;
-               }
-               else if (any_aead && !all_aead)
-               {
-                       DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
-                                "algorithms can't be contained in the same %N proposal",
-                                protocol_id_names, this->protocol);
-                       return FALSE;
-               }
-               else if (all_aead)
-               {       /* if all encryption algorithms in the proposal are AEADs,
-                        * we MUST NOT propose any integrity algorithms */
-                       remove_transform(this, INTEGRITY_ALGORITHM);
-               }
-       }
-       else
-       {       /* AES-GMAC is parsed as encryption algorithm, so we map that to the
-                * proper integrity algorithm */
-               e = array_create_enumerator(this->transforms);
-               while (e->enumerate(e, &entry))
-               {
-                       if (entry->type == ENCRYPTION_ALGORITHM)
-                       {
-                               if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
-                               {
-                                       entry->type = INTEGRITY_ALGORITHM;
-                                       ks = entry->key_size;
-                                       entry->key_size = 0;
-                                       switch (ks)
-                                       {
-                                               case 128:
-                                                       entry->alg = AUTH_AES_128_GMAC;
-                                                       continue;
-                                               case 192:
-                                                       entry->alg = AUTH_AES_192_GMAC;
-                                                       continue;
-                                               case 256:
-                                                       entry->alg = AUTH_AES_256_GMAC;
-                                                       continue;
-                                               default:
-                                                       break;
-                                       }
-                               }
-                               /* remove all other encryption algorithms */
-                               array_remove_at(this->transforms, e);
-                       }
-               }
-               e->destroy(e);
-
-               if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
-               {
-                       DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
-                                "proposals");
-                       return FALSE;
-               }
-       }
-
-       if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
-       {
-               if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
-               {       /* ESN not specified, assume not supported */
-                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
-               }
-       }
-
-       array_compress(this->transforms);
-       return TRUE;
-}
-
-/**
- * add a algorithm identified by a string to the proposal.
- */
-static bool add_string_algo(private_proposal_t *this, const char *alg)
-{
-       const proposal_token_t *token;
-
-       token = lib->proposal->get_token(lib->proposal, alg);
-       if (token == NULL)
-       {
-               DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
-               return FALSE;
-       }
-
-       add_algorithm(this, token->type, token->algorithm, token->keysize);
-
-       return TRUE;
-}
-
-/**
- * print all algorithms of a kind to buffer
- */
-static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
-                                        u_int kind, void *names, bool *first)
-{
-       enumerator_t *enumerator;
-       size_t written = 0;
-       uint16_t alg, size;
-
-       enumerator = create_enumerator(this, kind);
-       while (enumerator->enumerate(enumerator, &alg, &size))
-       {
-               if (*first)
-               {
-                       written += print_in_hook(data, "%N", names, alg);
-                       *first = FALSE;
-               }
-               else
-               {
-                       written += print_in_hook(data, "/%N", names, alg);
-               }
-               if (size)
-               {
-                       written += print_in_hook(data, "_%u", size);
-               }
-       }
-       enumerator->destroy(enumerator);
-       return written;
-}
-
-/**
- * Described in header.
- */
-int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
-                                                const void *const *args)
-{
-       private_proposal_t *this = *((private_proposal_t**)(args[0]));
-       linked_list_t *list = *((linked_list_t**)(args[0]));
-       enumerator_t *enumerator;
-       size_t written = 0;
-       bool first = TRUE;
-
-       if (this == NULL)
-       {
-               return print_in_hook(data, "(null)");
-       }
-
-       if (spec->hash)
-       {
-               enumerator = list->create_enumerator(list);
-               while (enumerator->enumerate(enumerator, &this))
-               {       /* call recursivly */
-                       if (first)
-                       {
-                               written += print_in_hook(data, "%P", this);
-                               first = FALSE;
-                       }
-                       else
-                       {
-                               written += print_in_hook(data, ", %P", this);
-                       }
-               }
-               enumerator->destroy(enumerator);
-               return written;
-       }
-
-       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);
-       return written;
-}
-
-METHOD(proposal_t, destroy, void,
-       private_proposal_t *this)
-{
-       array_destroy(this->transforms);
-       free(this);
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create(protocol_id_t protocol, u_int number)
-{
-       private_proposal_t *this;
-
-       INIT(this,
-               .public = {
-                       .add_algorithm = _add_algorithm,
-                       .create_enumerator = _create_enumerator,
-                       .get_algorithm = _get_algorithm,
-                       .has_dh_group = _has_dh_group,
-                       .strip_dh = _strip_dh,
-                       .select = _select_proposal,
-                       .get_protocol = _get_protocol,
-                       .set_spi = _set_spi,
-                       .get_spi = _get_spi,
-                       .get_number = _get_number,
-                       .equals = _equals,
-                       .clone = _clone_,
-                       .destroy = _destroy,
-               },
-               .protocol = protocol,
-               .number = number,
-               .transforms = array_create(sizeof(entry_t), 0),
-       );
-
-       return &this->public;
-}
-
-/**
- * Add supported IKE algorithms to proposal
- */
-static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
-{
-       enumerator_t *enumerator;
-       encryption_algorithm_t encryption;
-       integrity_algorithm_t integrity;
-       pseudo_random_function_t prf;
-       diffie_hellman_group_t group;
-       const char *plugin_name;
-
-       if (aead)
-       {
-               /* Round 1 adds algorithms with at least 128 bit security strength */
-               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_AES_GCM_ICV16:
-                               case ENCR_AES_CCM_ICV16:
-                               case ENCR_CAMELLIA_CCM_ICV16:
-                                       /* we assume that we support all AES/Camellia sizes */
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               case ENCR_CHACHA20_POLY1305:
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               /* Round 2 adds algorithms with less than 128 bit security strength */
-               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_AES_GCM_ICV12:
-                               case ENCR_AES_GCM_ICV8:
-                               case ENCR_AES_CCM_ICV12:
-                               case ENCR_AES_CCM_ICV8:
-                               case ENCR_CAMELLIA_CCM_ICV12:
-                               case ENCR_CAMELLIA_CCM_ICV8:
-                                       /* we assume that we support all AES/Camellia sizes */
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               if (!array_count(this->transforms))
-               {
-                       return FALSE;
-               }
-       }
-       else
-       {
-               /* Round 1 adds algorithms with at least 128 bit security strength */
-               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_AES_CBC:
-                               case ENCR_AES_CTR:
-                               case ENCR_CAMELLIA_CBC:
-                               case ENCR_CAMELLIA_CTR:
-                                       /* we assume that we support all AES/Camellia sizes */
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               /* Round 2 adds algorithms with less than 128 bit security strength */
-               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_3DES:
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
-                                       break;
-                               case ENCR_DES:
-                                       /* no, thanks */
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               if (!array_count(this->transforms))
-               {
-                       return FALSE;
-               }
-
-               /* Round 1 adds algorithms with at least 128 bit security strength */
-               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
-               {
-                       switch (integrity)
-                       {
-                               case AUTH_HMAC_SHA2_256_128:
-                               case AUTH_HMAC_SHA2_384_192:
-                               case AUTH_HMAC_SHA2_512_256:
-                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               /* Round 2 adds algorithms with less than 128 bit security strength */
-               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
-               {
-                       switch (integrity)
-                       {
-                               case AUTH_AES_XCBC_96:
-                               case AUTH_AES_CMAC_96:
-                               case AUTH_HMAC_SHA1_96:
-                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
-                                       break;
-                               case AUTH_HMAC_MD5_96:
-                                       /* no, thanks */
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-       }
-
-       /* Round 1 adds algorithms with at least 128 bit security strength */
-       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
-       {
-               switch (prf)
-               {
-                       case PRF_HMAC_SHA2_256:
-                       case PRF_HMAC_SHA2_384:
-                       case PRF_HMAC_SHA2_512:
-                       case PRF_AES128_XCBC:
-                       case PRF_AES128_CMAC:
-                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 2 adds algorithms with less than 128 bit security strength */
-       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
-       {
-               switch (prf)
-               {
-                       case PRF_HMAC_SHA1:
-                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
-                               break;
-                       case PRF_HMAC_MD5:
-                               /* no, thanks */
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
-       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &group, &plugin_name))
-       {
-               switch (group)
-               {
-                       case ECP_256_BIT:
-                       case ECP_384_BIT:
-                       case ECP_521_BIT:
-                       case ECP_256_BP:
-                       case ECP_384_BP:
-                       case ECP_512_BP:
-                       case CURVE_25519:
-                       case CURVE_448:
-                       case NTRU_128_BIT:
-                       case NTRU_192_BIT:
-                       case NTRU_256_BIT:
-                       case NH_128_BIT:
-                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 2 adds other algorithms with at least 128 bit security strength */
-       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &group, &plugin_name))
-       {
-               switch (group)
-               {
-                       case MODP_3072_BIT:
-                       case MODP_4096_BIT:
-                       case MODP_8192_BIT:
-                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 3 adds algorithms with less than 128 bit security strength */
-       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &group, &plugin_name))
-       {
-               switch (group)
-               {
-                       case MODP_NULL:
-                               /* only for testing purposes */
-                               break;
-                       case MODP_768_BIT:
-                       case MODP_1024_BIT:
-                       case MODP_1536_BIT:
-                               /* weak */
-                               break;
-                       case MODP_1024_160:
-                       case MODP_2048_224:
-                       case MODP_2048_256:
-                               /* RFC 5114 primes are of questionable source */
-                               break;
-                       case ECP_224_BIT:
-                       case ECP_224_BP:
-                       case ECP_192_BIT:
-                       case NTRU_112_BIT:
-                               /* rarely used */
-                               break;
-                       case MODP_2048_BIT:
-                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       return TRUE;
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create_default(protocol_id_t protocol)
-{
-       private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
-
-       switch (protocol)
-       {
-               case PROTO_IKE:
-                       if (!proposal_add_supported_ike(this, FALSE))
-                       {
-                               destroy(this);
-                               return NULL;
-                       }
-                       break;
-               case PROTO_ESP:
-                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          128);
-                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          192);
-                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          256);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
-                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
-                       break;
-               case PROTO_AH:
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
-                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
-                       break;
-               default:
-                       break;
-       }
-       return &this->public;
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create_default_aead(protocol_id_t protocol)
-{
-       private_proposal_t *this;
-
-       switch (protocol)
-       {
-               case PROTO_IKE:
-                       this = (private_proposal_t*)proposal_create(protocol, 0);
-                       if (!proposal_add_supported_ike(this, TRUE))
-                       {
-                               destroy(this);
-                               return NULL;
-                       }
-                       return &this->public;
-               case PROTO_ESP:
-                       /* we currently don't include any AEAD proposal for ESP, as we
-                        * don't know if our kernel backend actually supports it. */
-                       return NULL;
-               case PROTO_AH:
-               default:
-                       return NULL;
-       }
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
-{
-       private_proposal_t *this;
-       enumerator_t *enumerator;
-       bool failed = TRUE;
-       char *alg;
-
-       this = (private_proposal_t*)proposal_create(protocol, 0);
-
-       /* get all tokens, separated by '-' */
-       enumerator = enumerator_create_token(algs, "-", " ");
-       while (enumerator->enumerate(enumerator, &alg))
-       {
-               if (!add_string_algo(this, alg))
-               {
-                       failed = TRUE;
-                       break;
-               }
-               failed = FALSE;
-       }
-       enumerator->destroy(enumerator);
-
-       if (failed || !check_proposal(this))
-       {
-               destroy(this);
-               return NULL;
-       }
-
-       return &this->public;
-}
diff --git a/src/libcharon/config/proposal.h b/src/libcharon/config/proposal.h
deleted file mode 100644 (file)
index 0dc70f4..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2009-2016 Tobias Brunner
- * Copyright (C) 2006 Martin Willi
- * HSR Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <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 proposal proposal
- * @{ @ingroup config
- */
-
-#ifndef PROPOSAL_H_
-#define PROPOSAL_H_
-
-typedef enum protocol_id_t protocol_id_t;
-typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
-typedef struct proposal_t proposal_t;
-
-#include <library.h>
-#include <utils/identification.h>
-#include <collections/linked_list.h>
-#include <networking/host.h>
-#include <crypto/transform.h>
-#include <crypto/crypters/crypter.h>
-#include <crypto/signers/signer.h>
-#include <crypto/diffie_hellman.h>
-#include <selectors/traffic_selector.h>
-
-/**
- * Protocol ID of a proposal.
- */
-enum protocol_id_t {
-       PROTO_NONE = 0,
-       PROTO_IKE = 1,
-       PROTO_AH = 2,
-       PROTO_ESP = 3,
-       PROTO_IPCOMP = 4, /* IKEv1 only */
-};
-
-/**
- * enum names for protocol_id_t
- */
-extern enum_name_t *protocol_id_names;
-
-/**
- * Stores a set of algorithms used for an SA.
- *
- * A proposal stores algorithms for a specific
- * protocol. It can store algorithms for one protocol.
- * Proposals with multiple protocols are not supported,
- * as it's not specified in RFC4301 anymore.
- */
-struct proposal_t {
-
-       /**
-        * Add an algorithm to the proposal.
-        *
-        * The algorithms are stored by priority, first added
-        * is the most preferred.
-        * Key size is only needed for encryption algorithms
-        * with variable key size (such as AES). Must be set
-        * to zero if key size is not specified.
-        * The alg parameter accepts encryption_algorithm_t,
-        * integrity_algorithm_t, dh_group_number_t and
-        * extended_sequence_numbers_t.
-        *
-        * @param type                  kind of algorithm
-        * @param alg                   identifier for algorithm
-        * @param key_size              key size to use
-        */
-       void (*add_algorithm) (proposal_t *this, transform_type_t type,
-                                                  uint16_t alg, uint16_t key_size);
-
-       /**
-        * Get an enumerator over algorithms for a specific algo type.
-        *
-        * @param type                  kind of algorithm
-        * @return                              enumerator over uint16_t alg, uint16_t key_size
-        */
-       enumerator_t *(*create_enumerator) (proposal_t *this, transform_type_t type);
-
-       /**
-        * Get the algorithm for a type to use.
-        *
-        * If there are multiple algorithms, only the first is returned.
-        *
-        * @param type                  kind of algorithm
-        * @param alg                   pointer which receives algorithm
-        * @param key_size              pointer which receives the key size
-        * @return                              TRUE if algorithm of this kind available
-        */
-       bool (*get_algorithm) (proposal_t *this, transform_type_t type,
-                                                  uint16_t *alg, uint16_t *key_size);
-
-       /**
-        * Check if the proposal has a specific DH group.
-        *
-        * @param group                 group to check for
-        * @return                              TRUE if algorithm included
-        */
-       bool (*has_dh_group) (proposal_t *this, diffie_hellman_group_t group);
-
-       /**
-        * Strip DH groups from proposal to use it without PFS.
-        *
-        * @param keep                  group to keep (MODP_NONE to remove all)
-        */
-       void (*strip_dh)(proposal_t *this, diffie_hellman_group_t keep);
-
-       /**
-        * Compare two proposal, and select a matching subset.
-        *
-        * If the proposals are for the same protocols (AH/ESP), they are
-        * compared. If they have at least one algorithm of each type
-        * in common, a resulting proposal of this kind is created.
-        *
-        * @param other                 proposal to compare against
-        * @param other_remote  whether other is the remote proposal from which to
-        *                                              copy SPI and proposal number to the result,
-        *                                              otherwise copy from this proposal
-        * @param private               accepts algorithms allocated in a private range
-        * @return                              selected proposal, NULL if proposals don't match
-        */
-       proposal_t *(*select)(proposal_t *this, proposal_t *other,
-                                                 bool other_remote, bool private);
-
-       /**
-        * Get the protocol ID of the proposal.
-        *
-        * @return                              protocol of the proposal
-        */
-       protocol_id_t (*get_protocol) (proposal_t *this);
-
-       /**
-        * Get the SPI of the proposal.
-        *
-        * @return                              spi for proto
-        */
-       uint64_t (*get_spi) (proposal_t *this);
-
-       /**
-        * Set the SPI of the proposal.
-        *
-        * @param spi                   spi to set for proto
-        */
-       void (*set_spi) (proposal_t *this, uint64_t spi);
-
-       /**
-        * Get the proposal number, as encoded in SA payload
-        *
-        * @return                              proposal number
-        */
-       u_int (*get_number)(proposal_t *this);
-
-       /**
-        * Check for the eqality of two proposals.
-        *
-        * @param other                 other proposal to check for equality
-        * @return                              TRUE if other equal to this
-        */
-       bool (*equals)(proposal_t *this, proposal_t *other);
-
-       /**
-        * Clone a proposal.
-        *
-        * @return                              clone of proposal
-        */
-       proposal_t *(*clone) (proposal_t *this);
-
-       /**
-        * Destroys the proposal object.
-        */
-       void (*destroy) (proposal_t *this);
-};
-
-/**
- * Create a child proposal for AH, ESP or IKE.
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @param number                       proposal number, as encoded in SA payload
- * @return                                     proposal_t object
- */
-proposal_t *proposal_create(protocol_id_t protocol, u_int number);
-
-/**
- * Create a default proposal if nothing further specified.
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @return                                     proposal_t object
- */
-proposal_t *proposal_create_default(protocol_id_t protocol);
-
-/**
- * Create a default proposal for supported AEAD algorithms
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @return                                     proposal_t object, NULL if none supported
- */
-proposal_t *proposal_create_default_aead(protocol_id_t protocol);
-
-/**
- * Create a proposal from a string identifying the algorithms.
- *
- * The string is in the same form as a in the ipsec.conf file.
- * E.g.:       aes128-sha2_256-modp2048
- *               3des-md5
- * An additional '!' at the end of the string forces this proposal,
- * without it the peer may choose another algorithm we support.
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @param algs                         algorithms as string
- * @return                                     proposal_t object
- */
-proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs);
-
-/**
- * printf hook function for proposal_t.
- *
- * Arguments are:
- *     proposal_t *proposal
- * With the #-specifier, arguments are:
- *     linked_list_t *list containing proposal_t*
- */
-int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
-                                                const void *const *args);
-
-#endif /** PROPOSAL_H_ @}*/
index 7c9f83d..e4b8197 100644 (file)
@@ -55,7 +55,6 @@
 #include <bus/listeners/sys_logger.h>
 #include <bus/listeners/file_logger.h>
 #include <collections/array.h>
-#include <config/proposal.h>
 #include <plugins/plugin_feature.h>
 #include <kernel/kernel_handler.h>
 #include <processing/jobs/start_action_job.h>
@@ -989,11 +988,6 @@ bool libcharon_init()
        dbg_old = dbg;
        dbg = dbg_bus;
 
-       lib->printf_hook->add_handler(lib->printf_hook, 'P',
-                                                                 proposal_printf_hook,
-                                                                 PRINTF_HOOK_ARGTYPE_POINTER,
-                                                                 PRINTF_HOOK_ARGTYPE_END);
-
        if (lib->integrity &&
                !lib->integrity->check(lib->integrity, "libcharon", libcharon_init))
        {
index 796c108..cad597e 100644 (file)
@@ -29,7 +29,7 @@ typedef struct proposal_substructure_t proposal_substructure_t;
 #include <library.h>
 #include <encoding/payloads/payload.h>
 #include <encoding/payloads/transform_substructure.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <collections/linked_list.h>
 #include <kernel/kernel_ipsec.h>
 #include <sa/authenticator.h>
index cb75f1e..a9d4f9f 100644 (file)
@@ -32,7 +32,7 @@ typedef struct transform_substructure_t transform_substructure_t;
 #include <crypto/signers/signer.h>
 #include <crypto/prfs/prf.h>
 #include <crypto/crypters/crypter.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 /**
  * IKEv1 Value for a transform payload.
index b2d5a11..b33ea61 100644 (file)
@@ -27,7 +27,7 @@ typedef struct delete_child_sa_job_t delete_child_sa_job_t;
 #include <library.h>
 #include <sa/ike_sa_id.h>
 #include <processing/jobs/job.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 
 /**
index 1de06fd..1c9d9b4 100644 (file)
@@ -26,7 +26,7 @@ typedef struct rekey_child_sa_job_t rekey_child_sa_job_t;
 #include <library.h>
 #include <sa/ike_sa_id.h>
 #include <processing/jobs/job.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 /**
  * Class representing an REKEY_CHILD_SA Job.
@@ -50,4 +50,5 @@ struct rekey_child_sa_job_t {
  */
 rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol,
                                                                                                uint32_t spi, host_t *dst);
+
 #endif /** REKEY_CHILD_SA_JOB_H_ @}*/
index ed978dc..17beb68 100644 (file)
@@ -26,7 +26,7 @@ typedef struct update_sa_job_t update_sa_job_t;
 #include <library.h>
 #include <networking/host.h>
 #include <processing/jobs/job.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 /**
  * Update the addresses of an IKE and its CHILD_SAs.
index 082404d..85c1a42 100644 (file)
@@ -30,7 +30,7 @@ typedef struct child_sa_t child_sa_t;
 #include <library.h>
 #include <crypto/prf_plus.h>
 #include <encoding/payloads/proposal_substructure.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <config/child_cfg.h>
 
 /**
index bc40b3d..17d2efe 100644 (file)
@@ -27,7 +27,7 @@ typedef struct keymat_t keymat_t;
 #include <utils/identification.h>
 #include <crypto/prfs/prf.h>
 #include <crypto/aead.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <config/peer_cfg.h>
 #include <sa/ike_sa_id.h>
 
index 8f762a2..5ebd045 100644 (file)
@@ -3,7 +3,6 @@ TESTS = libcharon_tests exchange_tests
 check_PROGRAMS = $(TESTS)
 
 libcharon_tests_SOURCES = \
-  suites/test_proposal.c \
   suites/test_ike_cfg.c \
   suites/test_mem_pool.c \
   suites/test_message_chapoly.c \
index f770f46..d17ea04 100644 (file)
@@ -24,7 +24,6 @@
  * @ingroup libcharon-tests
  */
 
-TEST_SUITE(proposal_suite_create)
 TEST_SUITE(ike_cfg_suite_create)
 TEST_SUITE(mem_pool_suite_create)
 TEST_SUITE_DEPEND(message_chapoly_suite_create, AEAD, ENCR_CHACHA20_POLY1305, 32)
diff --git a/src/libcharon/tests/suites/test_proposal.c b/src/libcharon/tests/suites/test_proposal.c
deleted file mode 100644 (file)
index f159179..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2016 Tobias Brunner
- * HSR Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <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 "test_suite.h"
-
-#include <config/proposal.h>
-
-static struct {
-       protocol_id_t proto;
-       char *proposal;
-       char *expected;
-} create_data[] = {
-       { PROTO_IKE, "", NULL },
-       { PROTO_IKE, "sha256", NULL },
-       { PROTO_IKE, "sha256-modp3072", NULL },
-       { PROTO_IKE, "null-sha256-modp3072", "IKE:NULL/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128", NULL },
-       { PROTO_IKE, "aes128-sha256", NULL },
-       { PROTO_IKE, "aes128-sha256-modpnone", NULL },
-       { PROTO_IKE, "aes128-sha256-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128-sha256-prfsha384-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_384/MODP_3072" },
-       { PROTO_IKE, "aes128gcm16-modp3072", NULL },
-       { PROTO_IKE, "aes128gcm16-prfsha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128gcm16-sha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128gcm16-aes128-modp3072", NULL },
-       { PROTO_IKE, "aes128gcm16-aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "", NULL },
-       { PROTO_ESP, "sha256", NULL },
-       { PROTO_ESP, "aes128-sha256", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-esn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-esn-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-prfsha256-modp3072", "ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_3072/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128gcm16-aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "aes128gmac", "ESP:NULL_AES_GMAC_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "", NULL },
-       { PROTO_AH,  "aes128", NULL },
-       { PROTO_AH,  "aes128-sha256", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "sha256-sha1", "AH:HMAC_SHA2_256_128/HMAC_SHA1_96/NO_EXT_SEQ" },
-       { PROTO_AH,  "aes128gmac-sha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "aes128gmac-sha256-prfsha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "aes128gmac-aes256gmac-aes128-sha256", "AH:AES_128_GMAC/AES_256_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "sha256-esn", "AH:HMAC_SHA2_256_128/EXT_SEQ" },
-       { PROTO_AH,  "sha256-noesn", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "sha256-esn-noesn", "AH:HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
-};
-
-START_TEST(test_create_from_string)
-{
-       proposal_t *proposal;
-       char str[BUF_LEN];
-
-       proposal = proposal_create_from_string(create_data[_i].proto,
-                                                                                  create_data[_i].proposal);
-       if (!create_data[_i].expected)
-       {
-               ck_assert(!proposal);
-               return;
-       }
-       snprintf(str, sizeof(str), "%P", proposal);
-       ck_assert_str_eq(create_data[_i].expected, str);
-       proposal->destroy(proposal);
-}
-END_TEST
-
-static struct {
-       protocol_id_t proto;
-       char *self;
-       char *other;
-       char *expected;
-} select_data[] = {
-       { PROTO_ESP, "aes128", "aes128", "aes128" },
-       { PROTO_ESP, "aes128", "aes256", NULL },
-       { PROTO_ESP, "aes128-aes256", "aes256-aes128", "aes128" },
-       { PROTO_ESP, "aes256-aes128", "aes128-aes256", "aes256" },
-       { PROTO_ESP, "aes128-aes256-sha1-sha256", "aes256-aes128-sha256-sha1", "aes128-sha1" },
-       { PROTO_ESP, "aes256-aes128-sha256-sha1", "aes128-aes256-sha1-sha256", "aes256-sha256" },
-       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256", NULL },
-       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256-modpnone", NULL },
-       { PROTO_ESP, "aes128-sha256-modpnone", "aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256", "aes128-sha256" },
-       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
-       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072" },
-       { PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone" },
-       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
-       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072" },
-       { PROTO_IKE, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
-};
-
-START_TEST(test_select)
-{
-       proposal_t *self, *other, *selected, *expected;
-
-       self = proposal_create_from_string(select_data[_i].proto,
-                                                                          select_data[_i].self);
-       other = proposal_create_from_string(select_data[_i].proto,
-                                                                               select_data[_i].other);
-       selected = self->select(self, other, TRUE, FALSE);
-       if (select_data[_i].expected)
-       {
-               expected = proposal_create_from_string(select_data[_i].proto,
-                                                                                          select_data[_i].expected);
-               ck_assert(selected);
-               ck_assert_msg(expected->equals(expected, selected), "proposal %P does "
-                                         "not match expected %P", selected, expected);
-               expected->destroy(expected);
-       }
-       else
-       {
-               ck_assert(!selected);
-       }
-       DESTROY_IF(selected);
-       other->destroy(other);
-       self->destroy(self);
-}
-END_TEST
-
-START_TEST(test_select_spi)
-{
-       proposal_t *self, *other, *selected;
-
-       self = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
-       other = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
-       other->set_spi(other, 0x12345678);
-
-       selected = self->select(self, other, TRUE, FALSE);
-       ck_assert(selected);
-       ck_assert_int_eq(selected->get_spi(selected), other->get_spi(other));
-       selected->destroy(selected);
-
-       selected = self->select(self, other, FALSE, FALSE);
-       ck_assert(selected);
-       ck_assert_int_eq(selected->get_spi(selected), self->get_spi(self));
-       selected->destroy(selected);
-
-       other->destroy(other);
-       self->destroy(self);
-}
-END_TEST
-
-Suite *proposal_suite_create()
-{
-       Suite *s;
-       TCase *tc;
-
-       s = suite_create("proposal");
-
-       tc = tcase_create("create_from_string");
-       tcase_add_loop_test(tc, test_create_from_string, 0, countof(create_data));
-       suite_add_tcase(s, tc);
-
-       tc = tcase_create("select");
-       tcase_add_loop_test(tc, test_select, 0, countof(select_data));
-       tcase_add_test(tc, test_select_spi);
-       suite_add_tcase(s, tc);
-
-       return s;
-}
index 0247add..fb7c62a 100644 (file)
@@ -8,7 +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/hashers/hash_algorithm_set.c crypto/proposal/proposal.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 \
index a9759ae..66539a8 100644 (file)
@@ -6,7 +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/hashers/hash_algorithm_set.c crypto/proposal/proposal.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 \
@@ -69,7 +69,7 @@ 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/hashers/hash_algorithm_set.h crypto/mac.h \
+crypto/hashers/hash_algorithm_set.h crypto/mac.h crypto/proposal/proposal.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/crypto/proposal/proposal.c b/src/libstrongswan/crypto/proposal/proposal.c
new file mode 100644 (file)
index 0000000..221375f
--- /dev/null
@@ -0,0 +1,1102 @@
+/*
+ * Copyright (C) 2008-2016 Tobias Brunner
+ * Copyright (C) 2006-2010 Martin Willi
+ * Copyright (C) 2013-2015 Andreas Steffen
+ * 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 <string.h>
+
+#include "proposal.h"
+
+#include <collections/array.h>
+#include <utils/identification.h>
+
+#include <crypto/transform.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+
+ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
+       "PROTO_NONE",
+       "IKE",
+       "AH",
+       "ESP",
+       "IPCOMP",
+);
+
+typedef struct private_proposal_t private_proposal_t;
+
+/**
+ * Private data of an proposal_t object
+ */
+struct private_proposal_t {
+
+       /**
+        * Public part
+        */
+       proposal_t public;
+
+       /**
+        * protocol (ESP or AH)
+        */
+       protocol_id_t protocol;
+
+       /**
+        * Priority ordered list of transforms, as entry_t
+        */
+       array_t *transforms;
+
+       /**
+        * senders SPI
+        */
+       uint64_t spi;
+
+       /**
+        * Proposal number
+        */
+       u_int number;
+};
+
+/**
+ * Struct used to store different kinds of algorithms.
+ */
+typedef struct {
+       /** Type of the transform */
+       transform_type_t type;
+       /** algorithm identifier */
+       uint16_t alg;
+       /** key size in bits, or zero if not needed */
+       uint16_t key_size;
+} entry_t;
+
+METHOD(proposal_t, add_algorithm, void,
+       private_proposal_t *this, transform_type_t type,
+       uint16_t alg, uint16_t key_size)
+{
+       entry_t entry = {
+               .type = type,
+               .alg = alg,
+               .key_size = key_size,
+       };
+
+       array_insert(this->transforms, ARRAY_TAIL, &entry);
+}
+
+CALLBACK(alg_filter, bool,
+       uintptr_t type, enumerator_t *orig, va_list args)
+{
+       entry_t *entry;
+       uint16_t *alg, *key_size;
+
+       VA_ARGS_VGET(args, alg, key_size);
+
+       while (orig->enumerate(orig, &entry))
+       {
+               if (entry->type != type)
+               {
+                       continue;
+               }
+               if (alg)
+               {
+                       *alg = entry->alg;
+               }
+               if (key_size)
+               {
+                       *key_size = entry->key_size;
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(proposal_t, create_enumerator, enumerator_t*,
+       private_proposal_t *this, transform_type_t type)
+{
+       return enumerator_create_filter(
+                                               array_create_enumerator(this->transforms),
+                                               alg_filter, (void*)(uintptr_t)type, NULL);
+}
+
+METHOD(proposal_t, get_algorithm, bool,
+       private_proposal_t *this, transform_type_t type,
+       uint16_t *alg, uint16_t *key_size)
+{
+       enumerator_t *enumerator;
+       bool found = FALSE;
+
+       enumerator = create_enumerator(this, type);
+       if (enumerator->enumerate(enumerator, alg, key_size))
+       {
+               found = TRUE;
+       }
+       enumerator->destroy(enumerator);
+
+       return found;
+}
+
+METHOD(proposal_t, has_dh_group, bool,
+       private_proposal_t *this, diffie_hellman_group_t group)
+{
+       bool found = FALSE, any = FALSE;
+       enumerator_t *enumerator;
+       uint16_t current;
+
+       enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
+       while (enumerator->enumerate(enumerator, &current, NULL))
+       {
+               any = TRUE;
+               if (current == group)
+               {
+                       found = TRUE;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (!any && group == MODP_NONE)
+       {
+               found = TRUE;
+       }
+       return found;
+}
+
+METHOD(proposal_t, strip_dh, void,
+       private_proposal_t *this, diffie_hellman_group_t keep)
+{
+       enumerator_t *enumerator;
+       entry_t *entry;
+
+       enumerator = array_create_enumerator(this->transforms);
+       while (enumerator->enumerate(enumerator, &entry))
+       {
+               if (entry->type == DIFFIE_HELLMAN_GROUP &&
+                       entry->alg != keep)
+               {
+                       array_remove_at(this->transforms, enumerator);
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * Select a matching proposal from this and other, insert into selected.
+ */
+static bool select_algo(private_proposal_t *this, proposal_t *other,
+                                               proposal_t *selected, transform_type_t type, bool priv)
+{
+       enumerator_t *e1, *e2;
+       uint16_t alg1, alg2, ks1, ks2;
+       bool found = FALSE, optional = FALSE;
+
+       if (type == INTEGRITY_ALGORITHM &&
+               selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
+               encryption_algorithm_is_aead(alg1))
+       {
+               /* no integrity algorithm required, we have an AEAD */
+               return TRUE;
+       }
+       if (type == DIFFIE_HELLMAN_GROUP)
+       {
+               optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
+       }
+
+       e1 = create_enumerator(this, type);
+       e2 = other->create_enumerator(other, type);
+       if (!e1->enumerate(e1, &alg1, NULL))
+       {
+               if (!e2->enumerate(e2, &alg2, NULL))
+               {
+                       found = TRUE;
+               }
+               else if (optional)
+               {
+                       do
+                       {       /* if NONE is proposed, we accept the proposal */
+                               found = !alg2;
+                       }
+                       while (!found && e2->enumerate(e2, &alg2, NULL));
+               }
+       }
+       else if (!e2->enumerate(e2, NULL, NULL))
+       {
+               if (optional)
+               {
+                       do
+                       {       /* if NONE is proposed, we accept the proposal */
+                               found = !alg1;
+                       }
+                       while (!found && e1->enumerate(e1, &alg1, NULL));
+               }
+       }
+
+       e1->destroy(e1);
+       e1 = create_enumerator(this, type);
+       /* compare algs, order of algs in "first" is preferred */
+       while (!found && e1->enumerate(e1, &alg1, &ks1))
+       {
+               e2->destroy(e2);
+               e2 = other->create_enumerator(other, type);
+               while (e2->enumerate(e2, &alg2, &ks2))
+               {
+                       if (alg1 == alg2 && ks1 == ks2)
+                       {
+                               if (!priv && alg1 >= 1024)
+                               {
+                                       /* accept private use algorithms only if requested */
+                                       DBG1(DBG_CFG, "an algorithm from private space would match, "
+                                                "but peer implementation is unknown, skipped");
+                                       continue;
+                               }
+                               selected->add_algorithm(selected, type, alg1, ks1);
+                               found = TRUE;
+                               break;
+                       }
+               }
+       }
+       /* no match in all comparisons */
+       e1->destroy(e1);
+       e2->destroy(e2);
+
+       if (!found)
+       {
+               DBG2(DBG_CFG, "  no acceptable %N found", transform_type_names, type);
+       }
+       return found;
+}
+
+METHOD(proposal_t, select_proposal, proposal_t*,
+       private_proposal_t *this, proposal_t *other, bool other_remote,
+       bool private)
+{
+       proposal_t *selected;
+
+       DBG2(DBG_CFG, "selecting proposal:");
+
+       if (this->protocol != other->get_protocol(other))
+       {
+               DBG2(DBG_CFG, "  protocol mismatch, skipping");
+               return NULL;
+       }
+
+       if (other_remote)
+       {
+               selected = proposal_create(this->protocol, other->get_number(other));
+               selected->set_spi(selected, other->get_spi(other));
+       }
+       else
+       {
+               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))
+       {
+               selected->destroy(selected);
+               return NULL;
+       }
+
+       DBG2(DBG_CFG, "  proposal matches");
+       return selected;
+}
+
+METHOD(proposal_t, get_protocol, protocol_id_t,
+       private_proposal_t *this)
+{
+       return this->protocol;
+}
+
+METHOD(proposal_t, set_spi, void,
+       private_proposal_t *this, uint64_t spi)
+{
+       this->spi = spi;
+}
+
+METHOD(proposal_t, get_spi, uint64_t,
+       private_proposal_t *this)
+{
+       return this->spi;
+}
+
+/**
+ * Check if two proposals have the same algorithms for a given transform type
+ */
+static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
+                                                        transform_type_t type)
+{
+       enumerator_t *e1, *e2;
+       uint16_t alg1, alg2, ks1, ks2;
+       bool equals = TRUE;
+
+       e1 = create_enumerator(this, type);
+       e2 = other->create_enumerator(other, type);
+       while (e1->enumerate(e1, &alg1, &ks1))
+       {
+               if (!e2->enumerate(e2, &alg2, &ks2))
+               {
+                       /* this has more algs */
+                       equals = FALSE;
+                       break;
+               }
+               if (alg1 != alg2 || ks1 != ks2)
+               {
+                       equals = FALSE;
+                       break;
+               }
+       }
+       if (e2->enumerate(e2, &alg2, &ks2))
+       {
+               /* other has more algs */
+               equals = FALSE;
+       }
+       e1->destroy(e1);
+       e2->destroy(e2);
+
+       return equals;
+}
+
+METHOD(proposal_t, get_number, u_int,
+       private_proposal_t *this)
+{
+       return this->number;
+}
+
+METHOD(proposal_t, equals, bool,
+       private_proposal_t *this, proposal_t *other)
+{
+       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));
+}
+
+METHOD(proposal_t, clone_, proposal_t*,
+       private_proposal_t *this)
+{
+       private_proposal_t *clone;
+       enumerator_t *enumerator;
+       entry_t *entry;
+
+       clone = (private_proposal_t*)proposal_create(this->protocol, 0);
+
+       enumerator = array_create_enumerator(this->transforms);
+       while (enumerator->enumerate(enumerator, &entry))
+       {
+               array_insert(clone->transforms, ARRAY_TAIL, entry);
+       }
+       enumerator->destroy(enumerator);
+
+       clone->spi = this->spi;
+       clone->number = this->number;
+
+       return &clone->public;
+}
+
+/**
+ * Map integrity algorithms to the PRF functions using the same algorithm.
+ */
+static const struct {
+       integrity_algorithm_t integ;
+       pseudo_random_function_t prf;
+} integ_prf_map[] = {
+       {AUTH_HMAC_SHA1_96,                                     PRF_HMAC_SHA1                                   },
+       {AUTH_HMAC_SHA1_160,                            PRF_HMAC_SHA1                                   },
+       {AUTH_HMAC_SHA2_256_128,                        PRF_HMAC_SHA2_256                               },
+       {AUTH_HMAC_SHA2_384_192,                        PRF_HMAC_SHA2_384                               },
+       {AUTH_HMAC_SHA2_512_256,                        PRF_HMAC_SHA2_512                               },
+       {AUTH_HMAC_MD5_96,                                      PRF_HMAC_MD5                                    },
+       {AUTH_HMAC_MD5_128,                                     PRF_HMAC_MD5                                    },
+       {AUTH_AES_XCBC_96,                                      PRF_AES128_XCBC                                 },
+       {AUTH_CAMELLIA_XCBC_96,                         PRF_CAMELLIA128_XCBC                    },
+       {AUTH_AES_CMAC_96,                                      PRF_AES128_CMAC                                 },
+};
+
+/**
+ * Remove all entries of the given transform type
+ */
+static void remove_transform(private_proposal_t *this, transform_type_t type)
+{
+       enumerator_t *e;
+       entry_t *entry;
+
+       e = array_create_enumerator(this->transforms);
+       while (e->enumerate(e, &entry))
+       {
+               if (entry->type == type)
+               {
+                       array_remove_at(this->transforms, e);
+               }
+       }
+       e->destroy(e);
+}
+
+/**
+ * Checks the proposal read from a string.
+ */
+static bool check_proposal(private_proposal_t *this)
+{
+       enumerator_t *e;
+       entry_t *entry;
+       uint16_t alg, ks;
+       bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
+       int i;
+
+       if (this->protocol == PROTO_IKE)
+       {
+               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
+               {       /* No explicit PRF found. We assume the same algorithm as used
+                        * for integrity checking. */
+                       e = create_enumerator(this, INTEGRITY_ALGORITHM);
+                       while (e->enumerate(e, &alg, &ks))
+                       {
+                               for (i = 0; i < countof(integ_prf_map); i++)
+                               {
+                                       if (alg == integ_prf_map[i].integ)
+                                       {
+                                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
+                                                                         integ_prf_map[i].prf, 0);
+                                               break;
+                                       }
+                               }
+                       }
+                       e->destroy(e);
+               }
+               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
+               {
+                       DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
+                       return FALSE;
+               }
+               /* remove MODP_NONE from IKE proposal */
+               e = array_create_enumerator(this->transforms);
+               while (e->enumerate(e, &entry))
+               {
+                       if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
+                       {
+                               array_remove_at(this->transforms, e);
+                       }
+               }
+               e->destroy(e);
+               if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
+               {
+                       DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
+                       return FALSE;
+               }
+       }
+       else
+       {       /* remove PRFs from ESP/AH proposals */
+               remove_transform(this, PSEUDO_RANDOM_FUNCTION);
+       }
+
+       if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
+       {
+               e = create_enumerator(this, ENCRYPTION_ALGORITHM);
+               while (e->enumerate(e, &alg, &ks))
+               {
+                       any_enc = TRUE;
+                       if (encryption_algorithm_is_aead(alg))
+                       {
+                               any_aead = TRUE;
+                               continue;
+                       }
+                       all_aead = FALSE;
+               }
+               e->destroy(e);
+
+               if (!any_enc)
+               {
+                       DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
+                                protocol_id_names, this->protocol);
+                       return FALSE;
+               }
+               else if (any_aead && !all_aead)
+               {
+                       DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
+                                "algorithms can't be contained in the same %N proposal",
+                                protocol_id_names, this->protocol);
+                       return FALSE;
+               }
+               else if (all_aead)
+               {       /* if all encryption algorithms in the proposal are AEADs,
+                        * we MUST NOT propose any integrity algorithms */
+                       remove_transform(this, INTEGRITY_ALGORITHM);
+               }
+       }
+       else
+       {       /* AES-GMAC is parsed as encryption algorithm, so we map that to the
+                * proper integrity algorithm */
+               e = array_create_enumerator(this->transforms);
+               while (e->enumerate(e, &entry))
+               {
+                       if (entry->type == ENCRYPTION_ALGORITHM)
+                       {
+                               if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
+                               {
+                                       entry->type = INTEGRITY_ALGORITHM;
+                                       ks = entry->key_size;
+                                       entry->key_size = 0;
+                                       switch (ks)
+                                       {
+                                               case 128:
+                                                       entry->alg = AUTH_AES_128_GMAC;
+                                                       continue;
+                                               case 192:
+                                                       entry->alg = AUTH_AES_192_GMAC;
+                                                       continue;
+                                               case 256:
+                                                       entry->alg = AUTH_AES_256_GMAC;
+                                                       continue;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                               /* remove all other encryption algorithms */
+                               array_remove_at(this->transforms, e);
+                       }
+               }
+               e->destroy(e);
+
+               if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
+               {
+                       DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
+                                "proposals");
+                       return FALSE;
+               }
+       }
+
+       if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
+       {
+               if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
+               {       /* ESN not specified, assume not supported */
+                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+               }
+       }
+
+       array_compress(this->transforms);
+       return TRUE;
+}
+
+/**
+ * add a algorithm identified by a string to the proposal.
+ */
+static bool add_string_algo(private_proposal_t *this, const char *alg)
+{
+       const proposal_token_t *token;
+
+       token = lib->proposal->get_token(lib->proposal, alg);
+       if (token == NULL)
+       {
+               DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
+               return FALSE;
+       }
+
+       add_algorithm(this, token->type, token->algorithm, token->keysize);
+
+       return TRUE;
+}
+
+/**
+ * print all algorithms of a kind to buffer
+ */
+static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
+                                        u_int kind, void *names, bool *first)
+{
+       enumerator_t *enumerator;
+       size_t written = 0;
+       uint16_t alg, size;
+
+       enumerator = create_enumerator(this, kind);
+       while (enumerator->enumerate(enumerator, &alg, &size))
+       {
+               if (*first)
+               {
+                       written += print_in_hook(data, "%N", names, alg);
+                       *first = FALSE;
+               }
+               else
+               {
+                       written += print_in_hook(data, "/%N", names, alg);
+               }
+               if (size)
+               {
+                       written += print_in_hook(data, "_%u", size);
+               }
+       }
+       enumerator->destroy(enumerator);
+       return written;
+}
+
+/**
+ * Described in header.
+ */
+int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+                                                const void *const *args)
+{
+       private_proposal_t *this = *((private_proposal_t**)(args[0]));
+       linked_list_t *list = *((linked_list_t**)(args[0]));
+       enumerator_t *enumerator;
+       size_t written = 0;
+       bool first = TRUE;
+
+       if (this == NULL)
+       {
+               return print_in_hook(data, "(null)");
+       }
+
+       if (spec->hash)
+       {
+               enumerator = list->create_enumerator(list);
+               while (enumerator->enumerate(enumerator, &this))
+               {       /* call recursivly */
+                       if (first)
+                       {
+                               written += print_in_hook(data, "%P", this);
+                               first = FALSE;
+                       }
+                       else
+                       {
+                               written += print_in_hook(data, ", %P", this);
+                       }
+               }
+               enumerator->destroy(enumerator);
+               return written;
+       }
+
+       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);
+       return written;
+}
+
+METHOD(proposal_t, destroy, void,
+       private_proposal_t *this)
+{
+       array_destroy(this->transforms);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create(protocol_id_t protocol, u_int number)
+{
+       private_proposal_t *this;
+
+       INIT(this,
+               .public = {
+                       .add_algorithm = _add_algorithm,
+                       .create_enumerator = _create_enumerator,
+                       .get_algorithm = _get_algorithm,
+                       .has_dh_group = _has_dh_group,
+                       .strip_dh = _strip_dh,
+                       .select = _select_proposal,
+                       .get_protocol = _get_protocol,
+                       .set_spi = _set_spi,
+                       .get_spi = _get_spi,
+                       .get_number = _get_number,
+                       .equals = _equals,
+                       .clone = _clone_,
+                       .destroy = _destroy,
+               },
+               .protocol = protocol,
+               .number = number,
+               .transforms = array_create(sizeof(entry_t), 0),
+       );
+
+       return &this->public;
+}
+
+/**
+ * Add supported IKE algorithms to proposal
+ */
+static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
+{
+       enumerator_t *enumerator;
+       encryption_algorithm_t encryption;
+       integrity_algorithm_t integrity;
+       pseudo_random_function_t prf;
+       diffie_hellman_group_t group;
+       const char *plugin_name;
+
+       if (aead)
+       {
+               /* Round 1 adds algorithms with at least 128 bit security strength */
+               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_AES_GCM_ICV16:
+                               case ENCR_AES_CCM_ICV16:
+                               case ENCR_CAMELLIA_CCM_ICV16:
+                                       /* we assume that we support all AES/Camellia sizes */
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               case ENCR_CHACHA20_POLY1305:
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               /* Round 2 adds algorithms with less than 128 bit security strength */
+               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_AES_GCM_ICV12:
+                               case ENCR_AES_GCM_ICV8:
+                               case ENCR_AES_CCM_ICV12:
+                               case ENCR_AES_CCM_ICV8:
+                               case ENCR_CAMELLIA_CCM_ICV12:
+                               case ENCR_CAMELLIA_CCM_ICV8:
+                                       /* we assume that we support all AES/Camellia sizes */
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (!array_count(this->transforms))
+               {
+                       return FALSE;
+               }
+       }
+       else
+       {
+               /* Round 1 adds algorithms with at least 128 bit security strength */
+               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_AES_CBC:
+                               case ENCR_AES_CTR:
+                               case ENCR_CAMELLIA_CBC:
+                               case ENCR_CAMELLIA_CTR:
+                                       /* we assume that we support all AES/Camellia sizes */
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               /* Round 2 adds algorithms with less than 128 bit security strength */
+               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_3DES:
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
+                                       break;
+                               case ENCR_DES:
+                                       /* no, thanks */
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (!array_count(this->transforms))
+               {
+                       return FALSE;
+               }
+
+               /* Round 1 adds algorithms with at least 128 bit security strength */
+               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
+               {
+                       switch (integrity)
+                       {
+                               case AUTH_HMAC_SHA2_256_128:
+                               case AUTH_HMAC_SHA2_384_192:
+                               case AUTH_HMAC_SHA2_512_256:
+                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               /* Round 2 adds algorithms with less than 128 bit security strength */
+               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
+               {
+                       switch (integrity)
+                       {
+                               case AUTH_AES_XCBC_96:
+                               case AUTH_AES_CMAC_96:
+                               case AUTH_HMAC_SHA1_96:
+                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
+                                       break;
+                               case AUTH_HMAC_MD5_96:
+                                       /* no, thanks */
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+
+       /* Round 1 adds algorithms with at least 128 bit security strength */
+       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
+       {
+               switch (prf)
+               {
+                       case PRF_HMAC_SHA2_256:
+                       case PRF_HMAC_SHA2_384:
+                       case PRF_HMAC_SHA2_512:
+                       case PRF_AES128_XCBC:
+                       case PRF_AES128_CMAC:
+                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 2 adds algorithms with less than 128 bit security strength */
+       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
+       {
+               switch (prf)
+               {
+                       case PRF_HMAC_SHA1:
+                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
+                               break;
+                       case PRF_HMAC_MD5:
+                               /* no, thanks */
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
+       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &group, &plugin_name))
+       {
+               switch (group)
+               {
+                       case ECP_256_BIT:
+                       case ECP_384_BIT:
+                       case ECP_521_BIT:
+                       case ECP_256_BP:
+                       case ECP_384_BP:
+                       case ECP_512_BP:
+                       case CURVE_25519:
+                       case CURVE_448:
+                       case NTRU_128_BIT:
+                       case NTRU_192_BIT:
+                       case NTRU_256_BIT:
+                       case NH_128_BIT:
+                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 2 adds other algorithms with at least 128 bit security strength */
+       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &group, &plugin_name))
+       {
+               switch (group)
+               {
+                       case MODP_3072_BIT:
+                       case MODP_4096_BIT:
+                       case MODP_8192_BIT:
+                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 3 adds algorithms with less than 128 bit security strength */
+       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &group, &plugin_name))
+       {
+               switch (group)
+               {
+                       case MODP_NULL:
+                               /* only for testing purposes */
+                               break;
+                       case MODP_768_BIT:
+                       case MODP_1024_BIT:
+                       case MODP_1536_BIT:
+                               /* weak */
+                               break;
+                       case MODP_1024_160:
+                       case MODP_2048_224:
+                       case MODP_2048_256:
+                               /* RFC 5114 primes are of questionable source */
+                               break;
+                       case ECP_224_BIT:
+                       case ECP_224_BP:
+                       case ECP_192_BIT:
+                       case NTRU_112_BIT:
+                               /* rarely used */
+                               break;
+                       case MODP_2048_BIT:
+                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       return TRUE;
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create_default(protocol_id_t protocol)
+{
+       private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
+
+       switch (protocol)
+       {
+               case PROTO_IKE:
+                       if (!proposal_add_supported_ike(this, FALSE))
+                       {
+                               destroy(this);
+                               return NULL;
+                       }
+                       break;
+               case PROTO_ESP:
+                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          128);
+                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          192);
+                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          256);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
+                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+                       break;
+               case PROTO_AH:
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
+                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+                       break;
+               default:
+                       break;
+       }
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create_default_aead(protocol_id_t protocol)
+{
+       private_proposal_t *this;
+
+       switch (protocol)
+       {
+               case PROTO_IKE:
+                       this = (private_proposal_t*)proposal_create(protocol, 0);
+                       if (!proposal_add_supported_ike(this, TRUE))
+                       {
+                               destroy(this);
+                               return NULL;
+                       }
+                       return &this->public;
+               case PROTO_ESP:
+                       /* we currently don't include any AEAD proposal for ESP, as we
+                        * don't know if our kernel backend actually supports it. */
+                       return NULL;
+               case PROTO_AH:
+               default:
+                       return NULL;
+       }
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
+{
+       private_proposal_t *this;
+       enumerator_t *enumerator;
+       bool failed = TRUE;
+       char *alg;
+
+       this = (private_proposal_t*)proposal_create(protocol, 0);
+
+       /* get all tokens, separated by '-' */
+       enumerator = enumerator_create_token(algs, "-", " ");
+       while (enumerator->enumerate(enumerator, &alg))
+       {
+               if (!add_string_algo(this, alg))
+               {
+                       failed = TRUE;
+                       break;
+               }
+               failed = FALSE;
+       }
+       enumerator->destroy(enumerator);
+
+       if (failed || !check_proposal(this))
+       {
+               destroy(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
diff --git a/src/libstrongswan/crypto/proposal/proposal.h b/src/libstrongswan/crypto/proposal/proposal.h
new file mode 100644 (file)
index 0000000..d9a2af7
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2009-2016 Tobias Brunner
+ * Copyright (C) 2006 Martin Willi
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <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 proposal proposal
+ * @{ @ingroup crypto
+ */
+
+#ifndef PROPOSAL_H_
+#define PROPOSAL_H_
+
+typedef enum protocol_id_t protocol_id_t;
+typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
+typedef struct proposal_t proposal_t;
+
+#include <library.h>
+#include <utils/identification.h>
+#include <collections/linked_list.h>
+#include <networking/host.h>
+#include <crypto/transform.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+#include <crypto/diffie_hellman.h>
+#include <selectors/traffic_selector.h>
+
+/**
+ * Protocol ID of a proposal.
+ */
+enum protocol_id_t {
+       PROTO_NONE = 0,
+       PROTO_IKE = 1,
+       PROTO_AH = 2,
+       PROTO_ESP = 3,
+       PROTO_IPCOMP = 4, /* IKEv1 only */
+};
+
+/**
+ * enum names for protocol_id_t
+ */
+extern enum_name_t *protocol_id_names;
+
+/**
+ * Stores a set of algorithms used for an SA.
+ *
+ * A proposal stores algorithms for a specific
+ * protocol. It can store algorithms for one protocol.
+ * Proposals with multiple protocols are not supported,
+ * as it's not specified in RFC4301 anymore.
+ */
+struct proposal_t {
+
+       /**
+        * Add an algorithm to the proposal.
+        *
+        * The algorithms are stored by priority, first added
+        * is the most preferred.
+        * Key size is only needed for encryption algorithms
+        * with variable key size (such as AES). Must be set
+        * to zero if key size is not specified.
+        * The alg parameter accepts encryption_algorithm_t,
+        * integrity_algorithm_t, dh_group_number_t and
+        * extended_sequence_numbers_t.
+        *
+        * @param type                  kind of algorithm
+        * @param alg                   identifier for algorithm
+        * @param key_size              key size to use
+        */
+       void (*add_algorithm) (proposal_t *this, transform_type_t type,
+                                                  uint16_t alg, uint16_t key_size);
+
+       /**
+        * Get an enumerator over algorithms for a specific algo type.
+        *
+        * @param type                  kind of algorithm
+        * @return                              enumerator over uint16_t alg, uint16_t key_size
+        */
+       enumerator_t *(*create_enumerator) (proposal_t *this, transform_type_t type);
+
+       /**
+        * Get the algorithm for a type to use.
+        *
+        * If there are multiple algorithms, only the first is returned.
+        *
+        * @param type                  kind of algorithm
+        * @param alg                   pointer which receives algorithm
+        * @param key_size              pointer which receives the key size
+        * @return                              TRUE if algorithm of this kind available
+        */
+       bool (*get_algorithm) (proposal_t *this, transform_type_t type,
+                                                  uint16_t *alg, uint16_t *key_size);
+
+       /**
+        * Check if the proposal has a specific DH group.
+        *
+        * @param group                 group to check for
+        * @return                              TRUE if algorithm included
+        */
+       bool (*has_dh_group) (proposal_t *this, diffie_hellman_group_t group);
+
+       /**
+        * Strip DH groups from proposal to use it without PFS.
+        *
+        * @param keep                  group to keep (MODP_NONE to remove all)
+        */
+       void (*strip_dh)(proposal_t *this, diffie_hellman_group_t keep);
+
+       /**
+        * Compare two proposal, and select a matching subset.
+        *
+        * If the proposals are for the same protocols (AH/ESP), they are
+        * compared. If they have at least one algorithm of each type
+        * in common, a resulting proposal of this kind is created.
+        *
+        * @param other                 proposal to compare against
+        * @param other_remote  whether other is the remote proposal from which to
+        *                                              copy SPI and proposal number to the result,
+        *                                              otherwise copy from this proposal
+        * @param private               accepts algorithms allocated in a private range
+        * @return                              selected proposal, NULL if proposals don't match
+        */
+       proposal_t *(*select)(proposal_t *this, proposal_t *other,
+                                                 bool other_remote, bool private);
+
+       /**
+        * Get the protocol ID of the proposal.
+        *
+        * @return                              protocol of the proposal
+        */
+       protocol_id_t (*get_protocol) (proposal_t *this);
+
+       /**
+        * Get the SPI of the proposal.
+        *
+        * @return                              spi for proto
+        */
+       uint64_t (*get_spi) (proposal_t *this);
+
+       /**
+        * Set the SPI of the proposal.
+        *
+        * @param spi                   spi to set for proto
+        */
+       void (*set_spi) (proposal_t *this, uint64_t spi);
+
+       /**
+        * Get the proposal number, as encoded in SA payload
+        *
+        * @return                              proposal number
+        */
+       u_int (*get_number)(proposal_t *this);
+
+       /**
+        * Check for the eqality of two proposals.
+        *
+        * @param other                 other proposal to check for equality
+        * @return                              TRUE if other equal to this
+        */
+       bool (*equals)(proposal_t *this, proposal_t *other);
+
+       /**
+        * Clone a proposal.
+        *
+        * @return                              clone of proposal
+        */
+       proposal_t *(*clone) (proposal_t *this);
+
+       /**
+        * Destroys the proposal object.
+        */
+       void (*destroy) (proposal_t *this);
+};
+
+/**
+ * Create a child proposal for AH, ESP or IKE.
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @param number                       proposal number, as encoded in SA payload
+ * @return                                     proposal_t object
+ */
+proposal_t *proposal_create(protocol_id_t protocol, u_int number);
+
+/**
+ * Create a default proposal if nothing further specified.
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @return                                     proposal_t object
+ */
+proposal_t *proposal_create_default(protocol_id_t protocol);
+
+/**
+ * Create a default proposal for supported AEAD algorithms
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @return                                     proposal_t object, NULL if none supported
+ */
+proposal_t *proposal_create_default_aead(protocol_id_t protocol);
+
+/**
+ * Create a proposal from a string identifying the algorithms.
+ *
+ * The string is in the same form as a in the ipsec.conf file.
+ * E.g.:       aes128-sha2_256-modp2048
+ *               3des-md5
+ * An additional '!' at the end of the string forces this proposal,
+ * without it the peer may choose another algorithm we support.
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @param algs                         algorithms as string
+ * @return                                     proposal_t object
+ */
+proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs);
+
+/**
+ * printf hook function for proposal_t.
+ *
+ * Arguments are:
+ *     proposal_t *proposal
+ * With the #-specifier, arguments are:
+ *     linked_list_t *list containing proposal_t*
+ */
+int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+                                                const void *const *args);
+
+#endif /** PROPOSAL_H_ @}*/
index 856abdc..b062221 100644 (file)
@@ -37,7 +37,7 @@
 
 /**
  * @defgroup proposal_keywords proposal_keywords
- * @{ @ingroup crypto
+ * @{ @ingroup proposal
  */
 
 #ifndef PROPOSAL_KEYWORDS_H_
index 7944b93..dbdf5cf 100644 (file)
@@ -26,6 +26,7 @@
 #include <collections/hashtable.h>
 #include <utils/backtrace.h>
 #include <selectors/traffic_selector.h>
+#include <crypto/proposal/proposal.h>
 
 #define CHECKSUM_LIBRARY IPSEC_LIB_DIR"/libchecksum.so"
 
@@ -369,6 +370,8 @@ bool library_init(char *settings, const char *namespace)
                                         PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
        pfh->add_handler(pfh, 'R', traffic_selector_printf_hook,
                                         PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
+       pfh->add_handler(pfh, 'P', proposal_printf_hook,
+                                        PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
 
        this->objects = hashtable_create((hashtable_hash_t)hash,
                                                                         (hashtable_equals_t)equals, 4);
index 07f5eb5..5737e7a 100644 (file)
@@ -47,6 +47,7 @@ libstrongswan_tests_SOURCES = tests.h tests.c \
   suites/test_auth_cfg.c \
   suites/test_hasher.c \
   suites/test_crypter.c \
+  suites/test_proposal.c \
   suites/test_crypto_factory.c \
   suites/test_iv_gen.c \
   suites/test_pen.c \
diff --git a/src/libstrongswan/tests/suites/test_proposal.c b/src/libstrongswan/tests/suites/test_proposal.c
new file mode 100644 (file)
index 0000000..9176626
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <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 "test_suite.h"
+
+#include <crypto/proposal/proposal.h>
+
+static struct {
+       protocol_id_t proto;
+       char *proposal;
+       char *expected;
+} create_data[] = {
+       { PROTO_IKE, "", NULL },
+       { PROTO_IKE, "sha256", NULL },
+       { PROTO_IKE, "sha256-modp3072", NULL },
+       { PROTO_IKE, "null-sha256-modp3072", "IKE:NULL/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128", NULL },
+       { PROTO_IKE, "aes128-sha256", NULL },
+       { PROTO_IKE, "aes128-sha256-modpnone", NULL },
+       { PROTO_IKE, "aes128-sha256-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128-sha256-prfsha384-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_384/MODP_3072" },
+       { PROTO_IKE, "aes128gcm16-modp3072", NULL },
+       { PROTO_IKE, "aes128gcm16-prfsha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128gcm16-sha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128gcm16-aes128-modp3072", NULL },
+       { PROTO_IKE, "aes128gcm16-aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "", NULL },
+       { PROTO_ESP, "sha256", NULL },
+       { PROTO_ESP, "aes128-sha256", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-esn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-esn-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-prfsha256-modp3072", "ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_3072/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128gcm16-aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "aes128gmac", "ESP:NULL_AES_GMAC_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "", NULL },
+       { PROTO_AH,  "aes128", NULL },
+       { PROTO_AH,  "aes128-sha256", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "sha256-sha1", "AH:HMAC_SHA2_256_128/HMAC_SHA1_96/NO_EXT_SEQ" },
+       { PROTO_AH,  "aes128gmac-sha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "aes128gmac-sha256-prfsha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "aes128gmac-aes256gmac-aes128-sha256", "AH:AES_128_GMAC/AES_256_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "sha256-esn", "AH:HMAC_SHA2_256_128/EXT_SEQ" },
+       { PROTO_AH,  "sha256-noesn", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "sha256-esn-noesn", "AH:HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
+};
+
+START_TEST(test_create_from_string)
+{
+       proposal_t *proposal;
+       char str[BUF_LEN];
+
+       proposal = proposal_create_from_string(create_data[_i].proto,
+                                                                                  create_data[_i].proposal);
+       if (!create_data[_i].expected)
+       {
+               ck_assert(!proposal);
+               return;
+       }
+       snprintf(str, sizeof(str), "%P", proposal);
+       ck_assert_str_eq(create_data[_i].expected, str);
+       proposal->destroy(proposal);
+}
+END_TEST
+
+static struct {
+       protocol_id_t proto;
+       char *self;
+       char *other;
+       char *expected;
+} select_data[] = {
+       { PROTO_ESP, "aes128", "aes128", "aes128" },
+       { PROTO_ESP, "aes128", "aes256", NULL },
+       { PROTO_ESP, "aes128-aes256", "aes256-aes128", "aes128" },
+       { PROTO_ESP, "aes256-aes128", "aes128-aes256", "aes256" },
+       { PROTO_ESP, "aes128-aes256-sha1-sha256", "aes256-aes128-sha256-sha1", "aes128-sha1" },
+       { PROTO_ESP, "aes256-aes128-sha256-sha1", "aes128-aes256-sha1-sha256", "aes256-sha256" },
+       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256", NULL },
+       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256-modpnone", NULL },
+       { PROTO_ESP, "aes128-sha256-modpnone", "aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256", "aes128-sha256" },
+       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
+       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072" },
+       { PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone" },
+       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
+       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072" },
+       { PROTO_IKE, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
+};
+
+START_TEST(test_select)
+{
+       proposal_t *self, *other, *selected, *expected;
+
+       self = proposal_create_from_string(select_data[_i].proto,
+                                                                          select_data[_i].self);
+       other = proposal_create_from_string(select_data[_i].proto,
+                                                                               select_data[_i].other);
+       selected = self->select(self, other, TRUE, FALSE);
+       if (select_data[_i].expected)
+       {
+               expected = proposal_create_from_string(select_data[_i].proto,
+                                                                                          select_data[_i].expected);
+               ck_assert(selected);
+               ck_assert_msg(expected->equals(expected, selected), "proposal %P does "
+                                         "not match expected %P", selected, expected);
+               expected->destroy(expected);
+       }
+       else
+       {
+               ck_assert(!selected);
+       }
+       DESTROY_IF(selected);
+       other->destroy(other);
+       self->destroy(self);
+}
+END_TEST
+
+START_TEST(test_select_spi)
+{
+       proposal_t *self, *other, *selected;
+
+       self = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
+       other = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
+       other->set_spi(other, 0x12345678);
+
+       selected = self->select(self, other, TRUE, FALSE);
+       ck_assert(selected);
+       ck_assert_int_eq(selected->get_spi(selected), other->get_spi(other));
+       selected->destroy(selected);
+
+       selected = self->select(self, other, FALSE, FALSE);
+       ck_assert(selected);
+       ck_assert_int_eq(selected->get_spi(selected), self->get_spi(self));
+       selected->destroy(selected);
+
+       other->destroy(other);
+       self->destroy(self);
+}
+END_TEST
+
+Suite *proposal_suite_create()
+{
+       Suite *s;
+       TCase *tc;
+
+       s = suite_create("proposal");
+
+       tc = tcase_create("create_from_string");
+       tcase_add_loop_test(tc, test_create_from_string, 0, countof(create_data));
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("select");
+       tcase_add_loop_test(tc, test_select, 0, countof(select_data));
+       tcase_add_test(tc, test_select_spi);
+       suite_add_tcase(s, tc);
+
+       return s;
+}
index 525bdeb..5fab227 100644 (file)
@@ -40,6 +40,7 @@ TEST_SUITE(printf_suite_create)
 TEST_SUITE(auth_cfg_suite_create)
 TEST_SUITE(hasher_suite_create)
 TEST_SUITE(crypter_suite_create)
+TEST_SUITE(proposal_suite_create)
 TEST_SUITE(crypto_factory_suite_create)
 TEST_SUITE_DEPEND(iv_gen_suite_create, RNG, RNG_STRONG)
 TEST_SUITE(pen_suite_create)