diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon-tkm/src/charon-tkm.c | 4 | ||||
-rw-r--r-- | src/charon-tkm/src/tkm/tkm_spi_generator.c | 98 | ||||
-rw-r--r-- | src/charon-tkm/src/tkm/tkm_spi_generator.h | 36 | ||||
-rw-r--r-- | src/libcharon/daemon.c | 40 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa_manager.c | 44 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa_manager.h | 21 | ||||
-rw-r--r-- | src/libstrongswan/settings/settings.c | 25 | ||||
-rw-r--r-- | src/libstrongswan/settings/settings.h | 9 | ||||
-rw-r--r-- | src/libstrongswan/tests/suites/test_settings.c | 24 |
9 files changed, 279 insertions, 22 deletions
diff --git a/src/charon-tkm/src/charon-tkm.c b/src/charon-tkm/src/charon-tkm.c index 6c3a78bd8..52d82f3ad 100644 --- a/src/charon-tkm/src/charon-tkm.c +++ b/src/charon-tkm/src/charon-tkm.c @@ -43,6 +43,7 @@ #include "tkm_public_key.h" #include "tkm_cred.h" #include "tkm_encoder.h" +#include "tkm_spi_generator.h" /** * TKM bus listener for IKE authorize events. @@ -298,6 +299,9 @@ int main(int argc, char *argv[]) PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA256), PLUGIN_CALLBACK(kernel_ipsec_register, tkm_kernel_ipsec_create), PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"), + PLUGIN_CALLBACK(tkm_spi_generator_register, NULL), + PLUGIN_PROVIDE(CUSTOM, "tkm-spi-generator"), + PLUGIN_DEPENDS(CUSTOM, "libcharon-sa-managers"), }; lib->plugins->add_static_features(lib->plugins, "tkm-backend", features, countof(features), TRUE, NULL, NULL); diff --git a/src/charon-tkm/src/tkm/tkm_spi_generator.c b/src/charon-tkm/src/tkm/tkm_spi_generator.c new file mode 100644 index 000000000..eff0ca91e --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_spi_generator.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 Reto Buerki + * Copyright (C) 2015 Adrian-Ken Rueegsegger + * 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 <inttypes.h> +#include <library.h> +#include <daemon.h> + +#include "tkm_spi_generator.h" + +/** + * Get SPI callback arguments + */ +typedef struct { + rng_t *rng; + u_int64_t spi_mask; + u_int64_t spi_label; +} get_spi_args_t; + +static get_spi_args_t *spi_args; + +/** + * Callback called to generate an IKE SPI. + * + * @param this Callback args containing rng_t and spi mask & label + * @return labeled SPI + */ +CALLBACK(tkm_get_spi, u_int64_t, + const get_spi_args_t const *this) +{ + u_int64_t spi; + + if (!this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi)) + { + return 0; + } + + return (spi & ~this->spi_mask) | this->spi_label; +} + +bool tkm_spi_generator_register(plugin_t *plugin, + plugin_feature_t *feature, + bool reg, void *cb_data) +{ + u_int64_t spi_mask, spi_label; + char *spi_val; + rng_t *rng; + + if (reg) + { + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + return FALSE; + } + + spi_val = lib->settings->get_str(lib->settings, "%s.spi_mask", NULL, + lib->ns); + spi_mask = settings_value_as_uint64(spi_val, 0); + + spi_val = lib->settings->get_str(lib->settings, "%s.spi_label", NULL, + lib->ns); + spi_label = settings_value_as_uint64(spi_val, 0); + + INIT(spi_args, + .rng = rng, + .spi_mask = spi_mask, + .spi_label = spi_label, + ); + + charon->ike_sa_manager->set_spi_cb(charon->ike_sa_manager, + tkm_get_spi, spi_args); + DBG1(DBG_IKE, "using SPI label 0x%.16"PRIx64" and mask 0x%.16"PRIx64, + spi_label, spi_mask); + } + else + { + if (spi_args) + { + DESTROY_IF(spi_args->rng); + free(spi_args); + } + } + + return TRUE; +} diff --git a/src/charon-tkm/src/tkm/tkm_spi_generator.h b/src/charon-tkm/src/tkm/tkm_spi_generator.h new file mode 100644 index 000000000..5f9ff03c6 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_spi_generator.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 Reto Buerki + * Copyright (C) 2015 Adrian-Ken Rueegsegger + * 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 tkm-spi-generator spi generator + * @{ @ingroup tkm + */ + +#ifndef TKM_SPI_GENERATOR_H_ +#define TKM_SPI_GENERATOR_H_ + +#include <plugins/plugin.h> + +/** + * Register the TKM SPI generator callback. + * + * @return TRUE on success + */ +bool tkm_spi_generator_register(plugin_t *plugin, + plugin_feature_t *feature, + bool reg, void *cb_data); + +#endif /** TKM_SPI_GENERATOR_H_ @}*/ diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index f3fe3f8cd..dce2a7144 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2012 Tobias Brunner + * Copyright (C) 2006-2015 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -488,8 +488,6 @@ static void destroy(private_daemon_t *this) DESTROY_IF(this->kernel_handler); DESTROY_IF(this->public.traps); DESTROY_IF(this->public.shunts); - DESTROY_IF(this->public.child_sa_manager); - DESTROY_IF(this->public.ike_sa_manager); DESTROY_IF(this->public.controller); DESTROY_IF(this->public.eap); DESTROY_IF(this->public.xauth); @@ -562,7 +560,6 @@ METHOD(daemon_t, start, void, run_scripts(this, "start"); } - /** * Initialize/deinitialize sender and receiver */ @@ -586,12 +583,36 @@ static bool sender_receiver_cb(void *plugin, plugin_feature_t *feature, return TRUE; } +/** + * Initialize/deinitialize IKE_SA/CHILD_SA managers + */ +static bool sa_managers_cb(void *plugin, plugin_feature_t *feature, + bool reg, private_daemon_t *this) +{ + if (reg) + { + this->public.ike_sa_manager = ike_sa_manager_create(); + if (!this->public.ike_sa_manager) + { + return FALSE; + } + this->public.child_sa_manager = child_sa_manager_create(); + } + else + { + DESTROY_IF(this->public.ike_sa_manager); + DESTROY_IF(this->public.child_sa_manager); + } + return TRUE; +} + METHOD(daemon_t, initialize, bool, private_daemon_t *this, char *plugins) { plugin_feature_t features[] = { PLUGIN_PROVIDE(CUSTOM, "libcharon"), PLUGIN_DEPENDS(NONCE_GEN), + PLUGIN_DEPENDS(CUSTOM, "libcharon-sa-managers"), PLUGIN_DEPENDS(CUSTOM, "libcharon-receiver"), PLUGIN_DEPENDS(CUSTOM, "kernel-ipsec"), PLUGIN_DEPENDS(CUSTOM, "kernel-net"), @@ -600,6 +621,10 @@ METHOD(daemon_t, initialize, bool, PLUGIN_DEPENDS(HASHER, HASH_SHA1), PLUGIN_DEPENDS(RNG, RNG_STRONG), PLUGIN_DEPENDS(CUSTOM, "socket"), + PLUGIN_CALLBACK((plugin_feature_callback_t)sa_managers_cb, this), + PLUGIN_PROVIDE(CUSTOM, "libcharon-sa-managers"), + PLUGIN_DEPENDS(HASHER, HASH_SHA1), + PLUGIN_DEPENDS(RNG, RNG_WEAK), }; lib->plugins->add_static_features(lib->plugins, lib->ns, features, countof(features), TRUE, NULL, NULL); @@ -610,13 +635,6 @@ METHOD(daemon_t, initialize, bool, return FALSE; } - this->public.ike_sa_manager = ike_sa_manager_create(); - if (this->public.ike_sa_manager == NULL) - { - return FALSE; - } - this->public.child_sa_manager = child_sa_manager_create(); - /* Queue start_action job */ lib->processor->queue_job(lib->processor, (job_t*)start_action_job_create()); diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 389cbfe3b..4625df5b8 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -394,9 +394,17 @@ struct private_ike_sa_manager_t { rng_t *rng; /** - * Lock to access the RNG instance + * Registered callback for IKE SPIs */ - rwlock_t *rng_lock; + struct { + spi_cb_t cb; + void *data; + } spi_cb; + + /** + * Lock to access the RNG instance and the callback + */ + rwlock_t *spi_lock; /** * reuse existing IKE_SAs in checkout_by_config @@ -971,13 +979,17 @@ static u_int64_t get_spi(private_ike_sa_manager_t *this) { u_int64_t spi; - this->rng_lock->read_lock(this->rng_lock); - if (!this->rng || - !this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi)) + this->spi_lock->read_lock(this->spi_lock); + if (this->spi_cb.cb) + { + spi = this->spi_cb.cb(this->spi_cb.data); + } + else if (!this->rng || + !this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi)) { spi = 0; } - this->rng_lock->unlock(this->rng_lock); + this->spi_lock->unlock(this->spi_lock); return spi; } @@ -2040,6 +2052,15 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int, return count; } +METHOD(ike_sa_manager_t, set_spi_cb, void, + private_ike_sa_manager_t *this, spi_cb_t callback, void *data) +{ + this->spi_lock->write_lock(this->spi_lock); + this->spi_cb.cb = callback; + this->spi_cb.data = data; + this->spi_lock->unlock(this->spi_lock); +} + METHOD(ike_sa_manager_t, flush, void, private_ike_sa_manager_t *this) { @@ -2122,10 +2143,12 @@ METHOD(ike_sa_manager_t, flush, void, charon->bus->set_sa(charon->bus, NULL); unlock_all_segments(this); - this->rng_lock->write_lock(this->rng_lock); + this->spi_lock->write_lock(this->spi_lock); this->rng->destroy(this->rng); this->rng = NULL; - this->rng_lock->unlock(this->rng_lock); + this->spi_cb.cb = NULL; + this->spi_cb.data = NULL; + this->spi_lock->unlock(this->spi_lock); } METHOD(ike_sa_manager_t, destroy, void, @@ -2150,7 +2173,7 @@ METHOD(ike_sa_manager_t, destroy, void, free(this->connected_peers_segments); free(this->init_hashes_segments); - this->rng_lock->destroy(this->rng_lock); + this->spi_lock->destroy(this->spi_lock); free(this); } @@ -2197,6 +2220,7 @@ ike_sa_manager_t *ike_sa_manager_create() .get_count = _get_count, .get_half_open_count = _get_half_open_count, .flush = _flush, + .set_spi_cb = _set_spi_cb, .destroy = _destroy, }, ); @@ -2208,7 +2232,7 @@ ike_sa_manager_t *ike_sa_manager_create() free(this); return NULL; } - this->rng_lock = rwlock_create(RWLOCK_TYPE_DEFAULT); + this->spi_lock = rwlock_create(RWLOCK_TYPE_DEFAULT); this->ikesa_limit = lib->settings->get_int(lib->settings, "%s.ikesa_limit", 0, lib->ns); diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index 3ea928ea5..f1b7c2579 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008-2015 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -31,6 +31,16 @@ typedef struct ike_sa_manager_t ike_sa_manager_t; #include <config/peer_cfg.h> /** + * Callback called to generate an IKE SPI. + * + * This may be called from multiple threads concurrently. + * + * @param data data supplied during registration of the callback + * @return allocated SPI, 0 on failure + */ +typedef u_int64_t (*spi_cb_t)(void *data); + +/** * Manages and synchronizes access to all IKE_SAs. * * To synchronize access to thread-unsave IKE_SAs, they are checked out for @@ -227,6 +237,15 @@ struct ike_sa_manager_t { bool responder_only); /** + * Set the callback to generate IKE SPIs + * + * @param callback callback to register + * @param data data provided to callback + */ + void (*set_spi_cb)(ike_sa_manager_t *this, spi_cb_t callback, + void *data); + + /** * Delete all existing IKE_SAs and destroy them immediately. * * Threads will be driven out, so all SAs can be deleted cleanly. diff --git a/src/libstrongswan/settings/settings.c b/src/libstrongswan/settings/settings.c index 305ebe620..56cc2f19b 100644 --- a/src/libstrongswan/settings/settings.c +++ b/src/libstrongswan/settings/settings.c @@ -540,6 +540,31 @@ METHOD(settings_t, get_int, int, /** * Described in header */ +inline u_int64_t settings_value_as_uint64(char *value, u_int64_t def) +{ + u_int64_t intval; + char *end; + int base = 10; + + if (value) + { + errno = 0; + if (value[0] == '0' && value[1] == 'x') + { /* manually detect 0x prefix as we want to avoid octal encoding */ + base = 16; + } + intval = strtoull(value, &end, base); + if (errno == 0 && *end == 0 && end != value) + { + return intval; + } + } + return def; +} + +/** + * Described in header + */ inline double settings_value_as_double(char *value, double def) { double dval; diff --git a/src/libstrongswan/settings/settings.h b/src/libstrongswan/settings/settings.h index 4ef80d0f6..a133a3681 100644 --- a/src/libstrongswan/settings/settings.h +++ b/src/libstrongswan/settings/settings.h @@ -51,6 +51,15 @@ bool settings_value_as_bool(char *value, bool def); int settings_value_as_int(char *value, int def); /** + * Convert a string value returned by a key/value enumerator to an u_int64_t. + * + * @see settings_t.create_key_value_enumerator() + * @param value the string value + * @param def the default value, if value is NULL or invalid + */ +u_int64_t settings_value_as_uint64(char *value, u_int64_t def); + +/** * Convert a string value returned by a key/value enumerator to a double. * * @see settings_t.create_key_value_enumerator() diff --git a/src/libstrongswan/tests/suites/test_settings.c b/src/libstrongswan/tests/suites/test_settings.c index bead9d795..5ddd0bb9a 100644 --- a/src/libstrongswan/tests/suites/test_settings.c +++ b/src/libstrongswan/tests/suites/test_settings.c @@ -317,6 +317,26 @@ START_TEST(test_set_int) } END_TEST +START_TEST(test_value_as_unit64) +{ + test_int_eq(1, settings_value_as_uint64(NULL, 1)); + test_int_eq(1, settings_value_as_uint64("", 1)); + test_int_eq(1, settings_value_as_uint64("2a", 1)); + test_int_eq(1, settings_value_as_uint64("a2", 1)); + test_int_eq(1, settings_value_as_uint64("2.0", 1)); + + test_int_eq(10, settings_value_as_uint64("10", 0)); + test_int_eq(10, settings_value_as_uint64("010", 0)); + test_int_eq(16, settings_value_as_uint64("0x010", 0)); + test_int_eq(0x2a, settings_value_as_uint64("0x2a", 0)); + + test_int_eq(0xffffffffffffffffLL, settings_value_as_uint64("0xffffffffffffffff", 0)); + test_int_eq(0xffffffff00000000LL, settings_value_as_uint64("0xffffffff00000000", 0)); + test_int_eq(0xffffffff00000000LL, settings_value_as_uint64("18446744069414584320", 0)); + test_int_eq(0xffffffff00000001LL, settings_value_as_uint64("18446744069414584321", 0)); +} +END_TEST + START_SETUP(setup_double_config) { create_settings(chunk_from_str( @@ -1158,6 +1178,10 @@ Suite *settings_suite_create() tcase_add_test(tc, test_set_int); suite_add_tcase(s, tc); + tc = tcase_create("settings_value_as_uint64"); + tcase_add_test(tc, test_value_as_unit64); + suite_add_tcase(s, tc); + tc = tcase_create("get/set_double"); tcase_add_checked_fixture(tc, setup_double_config, teardown_config); tcase_add_test(tc, test_get_double); |