From: Tobias Brunner Date: Fri, 28 Oct 2011 18:59:03 +0000 (+0200) Subject: pkcs11: Merged the ECDH into the DH implementation. X-Git-Tag: 4.6.0~49 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=10b82be61fb09f6f854d0254d28bb2c8437c8ebc;p=thirdparty%2Fstrongswan.git pkcs11: Merged the ECDH into the DH implementation. --- diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h index 9ae7723639..aca793b713 100644 --- a/src/libstrongswan/crypto/diffie_hellman.h +++ b/src/libstrongswan/crypto/diffie_hellman.h @@ -57,7 +57,7 @@ enum diffie_hellman_group_t { ECP_224_BIT = 26, /** insecure NULL diffie hellman group for testing, in PRIVATE USE */ MODP_NULL = 1024, - /** MODP group with custon generator, prime */ + /** MODP group with custom generator/prime */ MODP_CUSTOM = 1025, }; diff --git a/src/libstrongswan/plugins/pkcs11/Makefile.am b/src/libstrongswan/plugins/pkcs11/Makefile.am index bdf00e5687..d032b879a7 100644 --- a/src/libstrongswan/plugins/pkcs11/Makefile.am +++ b/src/libstrongswan/plugins/pkcs11/Makefile.am @@ -18,7 +18,6 @@ libstrongswan_pkcs11_la_SOURCES = \ pkcs11_hasher.h pkcs11_hasher.c \ pkcs11_rng.h pkcs11_rng.c \ pkcs11_dh.h pkcs11_dh.c \ - pkcs11_ec_dh.h pkcs11_ec_dh.c \ pkcs11_manager.h pkcs11_manager.c libstrongswan_pkcs11_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c b/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c index e902b0ba8f..e7cc222348 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include "pkcs11_manager.h" @@ -62,10 +64,24 @@ struct private_pkcs11_dh_t { */ chunk_t secret; + /** + * Mechanism to use to generate a key pair + */ + CK_MECHANISM_TYPE mech_key; + + /** + * Mechanism to use to derive a shared secret + */ + CK_MECHANISM_TYPE mech_derive; + }; -METHOD(diffie_hellman_t, set_other_public_value, void, - private_pkcs11_dh_t *this, chunk_t value) +/** + * Derive a DH/ECDH shared secret. + * + * If this succeeds the shared secret is stored in this->secret. + */ +static void derive_secret(private_pkcs11_dh_t *this, chunk_t other) { CK_OBJECT_CLASS klass = CKO_SECRET_KEY; CK_KEY_TYPE type = CKK_GENERIC_SECRET; @@ -74,9 +90,9 @@ METHOD(diffie_hellman_t, set_other_public_value, void, { CKA_KEY_TYPE, &type, sizeof(type) }, }; CK_MECHANISM mech = { - CKM_DH_PKCS_DERIVE, - value.ptr, - value.len, + this->mech_derive, + other.ptr, + other.len, }; CK_OBJECT_HANDLE secret; CK_RV rv; @@ -96,6 +112,42 @@ METHOD(diffie_hellman_t, set_other_public_value, void, } } +METHOD(diffie_hellman_t, set_other_public_value, void, + private_pkcs11_dh_t *this, chunk_t value) +{ + switch (this->group) + { + case ECP_192_BIT: + case ECP_224_BIT: + case ECP_256_BIT: + case ECP_384_BIT: + case ECP_521_BIT: + { /* we expect the public value to just be the concatenated x and y + * coordinates, so we tag the value as an uncompressed ECPoint */ + chunk_t tag = chunk_from_chars(0x04); + chunk_t pubkey = chunk_cata("cc", tag, value); + CK_ECDH1_DERIVE_PARAMS params = { + CKD_NULL, + 0, + NULL, + pubkey.len, + pubkey.ptr, + }; + + if (!lib->settings->get_bool(lib->settings, + "libstrongswan.ecp_x_coordinate_only", TRUE)) + { /* we only get the x coordinate back */ + return; + } + value = chunk_from_thing(params); + break; + } + default: + break; + } + derive_secret(this, value); +} + METHOD(diffie_hellman_t, get_my_public_value, void, private_pkcs11_dh_t *this, chunk_t *value) { @@ -129,38 +181,32 @@ METHOD(diffie_hellman_t, destroy, void, } /** - * Generate DH key pair + * Generate a DH/ECDH key pair. + * + * If this succeeds, this->pri_key has a handle to the private key and + * this->pub_key stores the public key. */ -static bool generate_key_pair(private_pkcs11_dh_t *this, size_t exp_len, - chunk_t g, chunk_t p) +static bool generate_key_pair(private_pkcs11_dh_t *this, CK_ATTRIBUTE_PTR pub, + int pub_len, CK_ATTRIBUTE_PTR pri, int pri_len, + CK_ATTRIBUTE_TYPE attr) { - CK_ULONG bits = exp_len * 8; - CK_ATTRIBUTE pub_attr[] = { - { CKA_PRIME, p.ptr, p.len }, - { CKA_BASE, g.ptr, g.len }, - }; - CK_ATTRIBUTE pri_attr[] = { - { CKA_VALUE_BITS, &bits, sizeof(bits) }, - }; CK_MECHANISM mech = { - CKM_DH_PKCS_KEY_PAIR_GEN, + this->mech_key, NULL, 0, }; CK_OBJECT_HANDLE pub_key; CK_RV rv; - rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub_attr, - countof(pub_attr), pri_attr, countof(pri_attr), - &pub_key, &this->pri_key); + rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub, pub_len, + pri, pri_len, &pub_key, &this->pri_key); if (rv != CKR_OK) { DBG1(DBG_CFG, "C_GenerateKeyPair() error: %N", ck_rv_names, rv); return FALSE; } - if (!this->lib->get_ck_attribute(this->lib, this->session, pub_key, - CKA_VALUE, &this->pub_key)) + attr, &this->pub_key)) { chunk_free(&this->pub_key); return FALSE; @@ -169,9 +215,52 @@ static bool generate_key_pair(private_pkcs11_dh_t *this, size_t exp_len, } /** - * Find a token we can use for DH algorithm + * Generate DH key pair. + */ +static bool generate_key_pair_modp(private_pkcs11_dh_t *this, size_t exp_len, + chunk_t g, chunk_t p) +{ + CK_ATTRIBUTE pub_attr[] = { + { CKA_PRIME, p.ptr, p.len }, + { CKA_BASE, g.ptr, g.len }, + }; + CK_ULONG bits = exp_len * 8; + CK_ATTRIBUTE pri_attr[] = { + { CKA_VALUE_BITS, &bits, sizeof(bits) }, + }; + return generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr, + countof(pri_attr), CKA_VALUE); +} + +/** + * Generate ECDH key pair. */ -static pkcs11_library_t *find_token(CK_SESSION_HANDLE *session) +static bool generate_key_pair_ecp(private_pkcs11_dh_t *this, + chunk_t ecparams) +{ + CK_ATTRIBUTE pub_attr[] = { + { CKA_EC_PARAMS, ecparams.ptr, ecparams.len }, + }; + if (!generate_key_pair(this, pub_attr, countof(pub_attr), NULL, 0, + CKA_EC_POINT)) + { + return FALSE; + } + if (this->pub_key.len <= 0 || this->pub_key.ptr[0] != 0x04) + { /* we currently only support the point in uncompressed form which + * looks like this: 0x04 || x || y */ + chunk_clear(&this->pub_key); + return FALSE; + } + this->pub_key = chunk_skip(this->pub_key, 1); + return TRUE; +} + +/** + * Find a token we can use for DH/ECDH algorithm + */ +static pkcs11_library_t *find_token(private_pkcs11_dh_t *this, + CK_SESSION_HANDLE *session) { enumerator_t *tokens, *mechs; pkcs11_manager_t *manager; @@ -189,9 +278,9 @@ static pkcs11_library_t *find_token(CK_SESSION_HANDLE *session) { mechs = current->create_mechanism_enumerator(current, slot); while (mechs->enumerate(mechs, &type, NULL)) - { - /* we assume CKM_DH_PKCS_DERIVE is supported too */ - if (type == CKM_DH_PKCS_KEY_PAIR_GEN) + { /* we assume we can generate key pairs if the derive mechanism + * is supported */ + if (type == this->mech_derive) { if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, session) == CKR_OK) @@ -211,11 +300,12 @@ static pkcs11_library_t *find_token(CK_SESSION_HANDLE *session) return found; } -/* +/** * Generic internal constructor */ -pkcs11_dh_t *create_generic(diffie_hellman_group_t group, size_t exp_len, - chunk_t g, chunk_t p) +static private_pkcs11_dh_t *create_generic(diffie_hellman_group_t group, + CK_MECHANISM_TYPE key, + CK_MECHANISM_TYPE derive) { private_pkcs11_dh_t *this; @@ -230,43 +320,114 @@ pkcs11_dh_t *create_generic(diffie_hellman_group_t group, size_t exp_len, }, }, .group = group, + .mech_key = key, + .mech_derive = derive, ); - this->lib = find_token(&this->session); + this->lib = find_token(this, &this->session); if (!this->lib) { free(this); return NULL; } + return this; +} - if (!generate_key_pair(this, exp_len, g, p)) +static pkcs11_dh_t *create_ecp(diffie_hellman_group_t group, chunk_t ecparam) +{ + private_pkcs11_dh_t *this = create_generic(group, CKM_EC_KEY_PAIR_GEN, + CKM_ECDH1_DERIVE); + + if (this) { + if (generate_key_pair_ecp(this, ecparam)) + { + return &this->public; + } free(this); - return NULL; } - return &this->public; + return NULL; } - -/* - * Described in header. +/** + * Constructor for MODP DH */ -pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group, - chunk_t g, chunk_t p) +static pkcs11_dh_t *create_modp(diffie_hellman_group_t group, size_t exp_len, + chunk_t g, chunk_t p) { - diffie_hellman_params_t *params; + private_pkcs11_dh_t *this = create_generic(group, CKM_DH_PKCS_KEY_PAIR_GEN, + CKM_DH_PKCS_DERIVE); + + if (this) + { + if (generate_key_pair_modp(this, exp_len, g, p)) + { + return &this->public; + } + free(this); + } + return NULL; +} - if (group == MODP_CUSTOM) +/** + * Lookup the EC params for the given group. + */ +static chunk_t ecparams_lookup(diffie_hellman_group_t group) +{ + switch (group) { - return create_generic(group, p.len, g, p); + case ECP_192_BIT: + return asn1_build_known_oid(OID_PRIME192V1); + case ECP_224_BIT: + return asn1_build_known_oid(OID_SECT224R1); + case ECP_256_BIT: + return asn1_build_known_oid(OID_PRIME256V1); + case ECP_384_BIT: + return asn1_build_known_oid(OID_SECT384R1); + case ECP_521_BIT: + return asn1_build_known_oid(OID_SECT521R1); + default: + break; } + return chunk_empty; +} - params = diffie_hellman_get_params(group); - if (!params) +/** + * Described in header. + */ +pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group, + chunk_t g, chunk_t p) +{ + switch (group) { - return NULL; + case MODP_CUSTOM: + { + return create_modp(group, p.len, g, p); + } + case ECP_192_BIT: + case ECP_224_BIT: + case ECP_256_BIT: + case ECP_384_BIT: + case ECP_521_BIT: + { + chunk_t params = ecparams_lookup(group); + if (params.ptr) + { + return create_ecp(group, params); + } + break; + } + default: + { + diffie_hellman_params_t *params = diffie_hellman_get_params(group); + if (params) + { + return create_modp(group, params->exp_len, params->generator, + params->prime); + } + break; + } } - return create_generic(group, params->exp_len, - params->generator, params->prime); + return NULL; } diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_ec_dh.c b/src/libstrongswan/plugins/pkcs11/pkcs11_ec_dh.c deleted file mode 100644 index 807d3f5fa1..0000000000 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_ec_dh.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2011 Tobias Brunner - * 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 . - * - * 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 "pkcs11_ec_dh.h" - -#include -#include -#include -#include -#include - -#include "pkcs11_manager.h" - -typedef struct private_pkcs11_ec_dh_t private_pkcs11_ec_dh_t; - -/** - * Private data of an pkcs11_ec_dh_t object. - */ -struct private_pkcs11_ec_dh_t { - - /** - * Public pkcs11_ec_dh_t interface - */ - pkcs11_ec_dh_t public; - - /** - * PKCS#11 library - */ - pkcs11_library_t *lib; - - /** - * Session handle for this objct - */ - CK_SESSION_HANDLE session; - - /** - * Diffie Hellman group number. - */ - u_int16_t group; - - /** - * EC params (DER-encoded ANSI x9.62 Parameters value) - */ - chunk_t ecparams; - - /** - * Handle for own private value - */ - CK_OBJECT_HANDLE pri_key; - - /** - * Own public value - */ - chunk_t pub_key; - - /** - * Shared secret - */ - chunk_t secret; - -}; - -METHOD(diffie_hellman_t, set_other_public_value, void, - private_pkcs11_ec_dh_t *this, chunk_t value) -{ - chunk_t pubkey = chunk_alloca(value.len + 1); - CK_OBJECT_CLASS klass = CKO_SECRET_KEY; - CK_KEY_TYPE type = CKK_GENERIC_SECRET; - CK_ATTRIBUTE attr[] = { - { CKA_CLASS, &klass, sizeof(klass) }, - { CKA_KEY_TYPE, &type, sizeof(type) }, - }; - CK_ECDH1_DERIVE_PARAMS params = { - CKD_NULL, - 0, - NULL, - pubkey.len, - pubkey.ptr, - }; - CK_MECHANISM mech = { - CKM_ECDH1_DERIVE, - ¶ms, - sizeof(params), - }; - CK_OBJECT_HANDLE secret; - CK_RV rv; - - if (!lib->settings->get_bool(lib->settings, - "libstrongswan.ecp_x_coordinate_only", TRUE)) - { /* we only get the x coordinate back */ - return; - } - - /* we expect the public value to just be the concatenated x and y - * coordinates, so we have to specify that it is an uncompressed ECPoint */ - pubkey.ptr[0] = 0x04; - memcpy(pubkey.ptr + 1, value.ptr, value.len); - - rv = this->lib->f->C_DeriveKey(this->session, &mech, this->pri_key, - attr, countof(attr), &secret); - if (rv != CKR_OK) - { - DBG1(DBG_CFG, "C_DeriveKey() error: %N", ck_rv_names, rv); - return; - } - if (!this->lib->get_ck_attribute(this->lib, this->session, secret, - CKA_VALUE, &this->secret)) - { - chunk_free(&this->secret); - return; - } -} - -METHOD(diffie_hellman_t, get_my_public_value, void, - private_pkcs11_ec_dh_t *this, chunk_t *value) -{ - *value = chunk_clone(this->pub_key); -} - -METHOD(diffie_hellman_t, get_shared_secret, status_t, - private_pkcs11_ec_dh_t *this, chunk_t *secret) -{ - if (!this->secret.ptr) - { - return FAILED; - } - *secret = chunk_clone(this->secret); - return SUCCESS; -} - -METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, - private_pkcs11_ec_dh_t *this) -{ - return this->group; -} - -METHOD(diffie_hellman_t, destroy, void, - private_pkcs11_ec_dh_t *this) -{ - this->lib->f->C_CloseSession(this->session); - chunk_clear(&this->pub_key); - chunk_clear(&this->secret); - free(this); -} - -/** - * Generate ECDH key pair - */ -static bool generate_key_pair(private_pkcs11_ec_dh_t *this) -{ - CK_ATTRIBUTE pub_attr[] = { - { CKA_EC_PARAMS, this->ecparams.ptr, this->ecparams.len }, - }; - CK_MECHANISM mech = { - CKM_EC_KEY_PAIR_GEN, - NULL, - 0, - }; - CK_OBJECT_HANDLE pub_key; - CK_RV rv; - - rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub_attr, - countof(pub_attr), NULL, 0, &pub_key, - &this->pri_key); - if (rv != CKR_OK) - { - DBG1(DBG_CFG, "C_GenerateKeyPair() error: %N", ck_rv_names, rv); - return FALSE; - } - - if (!this->lib->get_ck_attribute(this->lib, this->session, pub_key, - CKA_EC_POINT, &this->pub_key)) - { - chunk_free(&this->pub_key); - return FALSE; - } - if (this->pub_key.len <= 0 || this->pub_key.ptr[0] != 0x04) - { /* we currently only support the point in uncompressed form which - * looks like this: 0x04 || x || y */ - chunk_clear(&this->pub_key); - return FALSE; - } - this->pub_key = chunk_skip(this->pub_key, 1); - return TRUE; -} - -/** - * Find a token we can use for DH algorithm - */ -static pkcs11_library_t *find_token(CK_SESSION_HANDLE *session) -{ - enumerator_t *tokens, *mechs; - pkcs11_manager_t *manager; - pkcs11_library_t *current, *found = NULL; - CK_MECHANISM_TYPE type; - CK_SLOT_ID slot; - - manager = lib->get(lib, "pkcs11-manager"); - if (!manager) - { - return NULL; - } - tokens = manager->create_token_enumerator(manager); - while (tokens->enumerate(tokens, ¤t, &slot)) - { - mechs = current->create_mechanism_enumerator(current, slot); - while (mechs->enumerate(mechs, &type, NULL)) - { - /* we assume CKM_EC_KEY_PAIR_GEN is supported too */ - if (type == CKM_ECDH1_DERIVE) - { - if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION, - NULL, NULL, session) == CKR_OK) - { - found = current; - break; - } - } - } - mechs->destroy(mechs); - if (found) - { - break; - } - } - tokens->destroy(tokens); - return found; -} - -/** - * Lookup the EC params matching the given group - */ -static chunk_t lookup_ecparams(diffie_hellman_group_t group) -{ - switch (group) - { - case ECP_192_BIT: - return asn1_build_known_oid(OID_PRIME192V1); - case ECP_224_BIT: - return asn1_build_known_oid(OID_SECT224R1); - case ECP_256_BIT: - return asn1_build_known_oid(OID_PRIME256V1); - case ECP_384_BIT: - return asn1_build_known_oid(OID_SECT384R1); - case ECP_521_BIT: - return asn1_build_known_oid(OID_SECT521R1); - default: - break; - } - return chunk_empty; -} - -/* - * Described in header. - */ -pkcs11_ec_dh_t *pkcs11_ec_dh_create(diffie_hellman_group_t group) -{ - private_pkcs11_ec_dh_t *this; - - INIT(this, - .public = { - .dh = { - .get_shared_secret = _get_shared_secret, - .set_other_public_value = _set_other_public_value, - .get_my_public_value = _get_my_public_value, - .get_dh_group = _get_dh_group, - .destroy = _destroy, - }, - }, - .group = group, - ); - - this->ecparams = lookup_ecparams(group); - if (!this->ecparams.ptr) - { - free(this); - return NULL; - } - - this->lib = find_token(&this->session); - if (!this->lib) - { - free(this); - return NULL; - } - - if (!generate_key_pair(this)) - { - free(this); - return NULL; - } - return &this->public; -} - diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_ec_dh.h b/src/libstrongswan/plugins/pkcs11/pkcs11_ec_dh.h deleted file mode 100644 index 5332184b10..0000000000 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_ec_dh.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2011 Tobias Brunner - * 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 . - * - * 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 pkcs11_ec_dh pkcs11_ec_dh - * @{ @ingroup pkcs11_p - */ - -#ifndef PKCS11_EC_DH_H_ -#define PKCS11_EC_DH_H_ - -typedef struct pkcs11_ec_dh_t pkcs11_ec_dh_t; - -#include - -/** - * Implementation of the EC Diffie-Hellman algorithm via PKCS#11. - */ -struct pkcs11_ec_dh_t { - - /** - * Implements diffie_hellman_t interface. - */ - diffie_hellman_t dh; -}; - -/** - * Creates a new pkcs11_ec_dh_t object. - * - * @param group EC Diffie Hellman group number to use - * @return pkcs11_ec_dh_t object, NULL if not supported - */ -pkcs11_ec_dh_t *pkcs11_ec_dh_create(diffie_hellman_group_t group); - -#endif /** PKCS11_EC_DH_H_ @}*/ - diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c b/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c index 79b3477832..52f0242fb8 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c @@ -30,7 +30,6 @@ #include "pkcs11_hasher.h" #include "pkcs11_rng.h" #include "pkcs11_dh.h" -#include "pkcs11_ec_dh.h" typedef struct private_pkcs11_plugin_t private_pkcs11_plugin_t; @@ -165,7 +164,7 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PUBKEY, KEY_RSA), }; static plugin_feature_t f_ecdh[] = { - PLUGIN_REGISTER(DH, pkcs11_ec_dh_create), + PLUGIN_REGISTER(DH, pkcs11_dh_create), PLUGIN_PROVIDE(DH, ECP_192_BIT), PLUGIN_PROVIDE(DH, ECP_224_BIT), PLUGIN_PROVIDE(DH, ECP_256_BIT),