diff options
Diffstat (limited to 'src/libhydra')
-rw-r--r-- | src/libhydra/kernel/kernel_interface.c | 125 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_interface.h | 48 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c | 24 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c | 35 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 24 |
5 files changed, 239 insertions, 17 deletions
diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c index 650cb1e9e..0ee5e1a55 100644 --- a/src/libhydra/kernel/kernel_interface.c +++ b/src/libhydra/kernel/kernel_interface.c @@ -15,6 +15,28 @@ * for more details. */ +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #include "kernel_interface.h" #include <debug.h> @@ -23,6 +45,34 @@ typedef struct private_kernel_interface_t private_kernel_interface_t; +typedef struct kernel_algorithm_t kernel_algorithm_t; + +/** + * Mapping of IKE algorithms to kernel-specific algorithm identifiers + */ +struct kernel_algorithm_t { + + /** + * Transform type of the algorithm + */ + transform_type_t type; + + /** + * Identifier specified in IKE + */ + u_int16_t ike; + + /** + * Identifier as defined in pfkeyv2.h + */ + u_int16_t kernel; + + /** + * Name of the algorithm in linux crypto API + */ + char *name; +}; + /** * Private data of a kernel_interface_t object. */ @@ -62,6 +112,16 @@ struct private_kernel_interface_t { * list of registered listeners */ linked_list_t *listeners; + + /** + * mutex for algorithm mappings + */ + mutex_t *mutex_algs; + + /** + * List of algorithm mappings (kernel_algorithm_t*) + */ + linked_list_t *algorithms; }; METHOD(kernel_interface_t, get_spi, status_t, @@ -510,13 +570,72 @@ METHOD(kernel_interface_t, roam, void, this->mutex->unlock(this->mutex); } +METHOD(kernel_interface_t, register_algorithm, void, + private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type, + u_int16_t kernel_id, char *kernel_name) +{ + kernel_algorithm_t *algorithm; + + INIT(algorithm, + .type = type, + .ike = alg_id, + .kernel = kernel_id, + .name = strdup(kernel_name), + ); + + this->mutex_algs->lock(this->mutex_algs); + this->algorithms->insert_first(this->algorithms, algorithm); + this->mutex_algs->unlock(this->mutex_algs); +} + +METHOD(kernel_interface_t, lookup_algorithm, bool, + private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type, + u_int16_t *kernel_id, char **kernel_name) +{ + kernel_algorithm_t *algorithm; + enumerator_t *enumerator; + bool found = FALSE; + + this->mutex_algs->lock(this->mutex_algs); + enumerator = this->algorithms->create_enumerator(this->algorithms); + while (enumerator->enumerate(enumerator, &algorithm)) + { + if (algorithm->type == type && algorithm->ike == alg_id) + { + if (kernel_id) + { + *kernel_id = algorithm->kernel; + } + if (kernel_name) + { + *kernel_name = algorithm->name; + } + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->mutex_algs->unlock(this->mutex_algs); + return found; +} + METHOD(kernel_interface_t, destroy, void, private_kernel_interface_t *this) { + kernel_algorithm_t *algorithm; + + while (this->algorithms->remove_first(this->algorithms, + (void**)&algorithm) == SUCCESS) + { + free(algorithm->name); + free(algorithm); + } + this->algorithms->destroy(this->algorithms); + this->mutex_algs->destroy(this->mutex_algs); DESTROY_IF(this->ipsec); DESTROY_IF(this->net); - this->mutex->destroy(this->mutex); this->listeners->destroy(this->listeners); + this->mutex->destroy(this->mutex); free(this); } @@ -559,6 +678,8 @@ kernel_interface_t *kernel_interface_create() .add_listener = _add_listener, .remove_listener = _remove_listener, + .register_algorithm = _register_algorithm, + .lookup_algorithm = _lookup_algorithm, .acquire = _acquire, .expire = _expire, .mapping = _mapping, @@ -568,6 +689,8 @@ kernel_interface_t *kernel_interface_create() }, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .listeners = linked_list_create(), + .mutex_algs = mutex_create(MUTEX_TYPE_DEFAULT), + .algorithms = linked_list_create(), ); return &this->public; diff --git a/src/libhydra/kernel/kernel_interface.h b/src/libhydra/kernel/kernel_interface.h index 37b72f8bb..a17e8c6bb 100644 --- a/src/libhydra/kernel/kernel_interface.h +++ b/src/libhydra/kernel/kernel_interface.h @@ -16,6 +16,28 @@ * for more details. */ +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + /** * @defgroup kernel_interface kernel_interface * @{ @ingroup hkernel @@ -493,6 +515,32 @@ struct kernel_interface_t { void (*roam)(kernel_interface_t *this, bool address); /** + * Register a new algorithm with the kernel interface. + * + * @param alg_id the IKE id of the algorithm + * @param type the transform type of the algorithm + * @param kernel_id the kernel id of the algorithm + * @param kernel_name the kernel name of the algorithm + */ + void (*register_algorithm)(kernel_interface_t *this, u_int16_t alg_id, + transform_type_t type, u_int16_t kernel_id, + char *kernel_name); + + /** + * Return the kernel-specific id and/or name for an algorithms depending on + * the arguments specified. + * + * @param alg_id the IKE id of the algorithm + * @param type the transform type of the algorithm + * @param kernel_id the kernel id of the algorithm (optional) + * @param kernel_name the kernel name of the algorithm (optional) + * @return TRUE if algorithm was found + */ + bool (*lookup_algorithm)(kernel_interface_t *this, u_int16_t alg_id, + transform_type_t type, u_int16_t *kernel_id, + char **kernel_name); + + /** * Destroys a kernel_interface_manager_t object. */ void (*destroy) (kernel_interface_t *this); diff --git a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c index 5f077b234..fa7f6107c 100644 --- a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c +++ b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c @@ -820,8 +820,22 @@ static kernel_algorithm_t compression_algs[] = { /** * Look up a kernel algorithm ID and its key size */ -static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) +static int lookup_algorithm(transform_type_t type, int ikev2) { + kernel_algorithm_t *list; + int alg = 0; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + list = encryption_algs; + break; + case INTEGRITY_ALGORITHM: + list = integrity_algs; + break; + default: + return 0; + } while (list->ikev2 != END_OF_LIST) { if (ikev2 == list->ikev2) @@ -830,7 +844,9 @@ static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) } list++; } - return 0; + hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2, + type, &alg, NULL); + return alg; } /** @@ -1713,8 +1729,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->sadb_sa_spi = spi; sa->sadb_sa_state = SADB_SASTATE_MATURE; sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; - sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg); - sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, enc_alg); + sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); + sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); PFKEY_EXT_ADD(msg, sa); add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC); diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index ef0a08c42..ac9d9fe77 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -243,8 +243,25 @@ static kernel_algorithm_t compression_algs[] = { /** * Look up a kernel algorithm name and its key size */ -static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2) +static char* lookup_algorithm(transform_type_t type, int ikev2) { + kernel_algorithm_t *list; + char *name = NULL; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + list = encryption_algs; + break; + case INTEGRITY_ALGORITHM: + list = integrity_algs; + break; + case COMPRESSION_ALGORITHM: + list = compression_algs; + break; + default: + return NULL; + } while (list->ikev2 != END_OF_LIST) { if (list->ikev2 == ikev2) @@ -253,7 +270,9 @@ static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2) } list++; } - return NULL; + hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2, + type, NULL, &name); + return name; } typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t; @@ -1222,12 +1241,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { struct xfrm_algo_aead *algo; - alg_name = lookup_algorithm(encryption_algs, enc_alg); + alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - encryption_algorithm_names, enc_alg); - goto failed; + encryption_algorithm_names, enc_alg); + goto failed; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", encryption_algorithm_names, enc_alg, enc_key.len * 8); @@ -1254,7 +1273,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { struct xfrm_algo *algo; - alg_name = lookup_algorithm(encryption_algs, enc_alg); + alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -1285,7 +1304,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { u_int trunc_len = 0; - alg_name = lookup_algorithm(integrity_algs, int_alg); + alg_name = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -1355,7 +1374,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, if (ipcomp != IPCOMP_NONE) { rthdr->rta_type = XFRMA_ALG_COMP; - alg_name = lookup_algorithm(compression_algs, ipcomp); + alg_name = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 13422670a..a562dddaa 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -807,8 +807,22 @@ static kernel_algorithm_t compression_algs[] = { /** * Look up a kernel algorithm ID and its key size */ -static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) +static int lookup_algorithm(transform_type_t type, int ikev2) { + kernel_algorithm_t *list; + int alg = 0; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + list = encryption_algs; + break; + case INTEGRITY_ALGORITHM: + list = integrity_algs; + break; + default: + return 0; + } while (list->ikev2 != END_OF_LIST) { if (ikev2 == list->ikev2) @@ -817,7 +831,9 @@ static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) } list++; } - return 0; + hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2, + type, &alg, NULL); + return alg; } /** @@ -1510,8 +1526,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->sadb_sa_len = PFKEY_LEN(len); sa->sadb_sa_spi = spi; sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; - sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg); - sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, enc_alg); + sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); + sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); PFKEY_EXT_ADD(msg, sa); sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg); |