From 1c1213f4b660b947821d4eaa26f7f3d8d09fd677 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 23 Jul 2021 16:44:07 +0200 Subject: [PATCH 01/15] openssl: Move shared secret calculation to get_shared_secret() This is a change from the multi-KE branch. --- .../plugins/openssl/openssl_diffie_hellman.c | 44 ++++++++----------- .../openssl/openssl_ec_diffie_hellman.c | 43 ++++++++---------- .../plugins/openssl/openssl_util.c | 1 + .../openssl/openssl_x_diffie_hellman.c | 36 ++++++--------- 4 files changed, 51 insertions(+), 73 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c index bee56a425..876742f35 100644 --- a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c +++ b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c @@ -63,11 +63,6 @@ struct private_openssl_diffie_hellman_t { * Shared secret */ chunk_t shared_secret; - - /** - * True if shared secret is computed - */ - bool computed; }; METHOD(diffie_hellman_t, get_my_public_value, bool, @@ -85,15 +80,24 @@ METHOD(diffie_hellman_t, get_my_public_value, bool, METHOD(diffie_hellman_t, get_shared_secret, bool, private_openssl_diffie_hellman_t *this, chunk_t *secret) { - if (!this->computed) + int len; + + if (!this->shared_secret.len) { - return FALSE; + this->shared_secret = chunk_alloc(DH_size(this->dh)); + memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len); + len = DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh); + if (len < 0) + { + DBG1(DBG_LIB, "DH shared secret computation failed"); + chunk_clear(&this->shared_secret); + return FALSE; + } + this->shared_secret.len = len; } - /* shared secret should requires a len according the DH group */ - *secret = chunk_alloc(DH_size(this->dh)); - memset(secret->ptr, 0, secret->len); - memcpy(secret->ptr + secret->len - this->shared_secret.len, - this->shared_secret.ptr, this->shared_secret.len); + /* shared secret requires a length according to the DH group */ + *secret = chunk_copy_pad(chunk_alloc(DH_size(this->dh)), + this->shared_secret, 0); return TRUE; } @@ -101,25 +105,16 @@ METHOD(diffie_hellman_t, get_shared_secret, bool, METHOD(diffie_hellman_t, set_other_public_value, bool, private_openssl_diffie_hellman_t *this, chunk_t value) { - int len; - if (!diffie_hellman_verify_value(this->group, value)) { return FALSE; } - BN_bin2bn(value.ptr, value.len, this->pub_key); - chunk_clear(&this->shared_secret); - this->shared_secret.ptr = malloc(DH_size(this->dh)); - memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len); - len = DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh); - if (len < 0) + if (!BN_bin2bn(value.ptr, value.len, this->pub_key)) { - DBG1(DBG_LIB, "DH shared secret computation failed"); return FALSE; } - this->shared_secret.len = len; - this->computed = TRUE; + chunk_clear(&this->shared_secret); return TRUE; } @@ -136,7 +131,6 @@ METHOD(diffie_hellman_t, set_private_value, bool, return FALSE; } chunk_clear(&this->shared_secret); - this->computed = FALSE; return DH_generate_key(this->dh); } return FALSE; @@ -220,9 +214,7 @@ openssl_diffie_hellman_t *openssl_diffie_hellman_create( } this->group = group; - this->computed = FALSE; this->pub_key = BN_new(); - this->shared_secret = chunk_empty; if (group == MODP_CUSTOM) { diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c index d591b0517..ff00ecb80 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c @@ -51,6 +51,11 @@ struct private_openssl_ec_diffie_hellman_t { */ EVP_PKEY *key; + /** + * Public key provided by peer + */ + EVP_PKEY *pub; + /** * EC group */ @@ -186,50 +191,35 @@ error: METHOD(diffie_hellman_t, set_other_public_value, bool, private_openssl_ec_diffie_hellman_t *this, chunk_t value) { - EVP_PKEY *pub = NULL; - - chunk_clear(&this->shared_secret); - this->computed = FALSE; - if (!diffie_hellman_verify_value(this->group, value)) { return FALSE; } - pub = EVP_PKEY_new(); - if (!pub) + if (!this->pub) { - goto error; + this->pub = EVP_PKEY_new(); } #if OPENSSL_VERSION_NUMBER < 0x1010000fL - if (!chunk2ecp(this->ec_group, value, pub)) + if (!chunk2ecp(this->ec_group, value, this->pub)) { DBG1(DBG_LIB, "ECDH public value is malformed"); - goto error; + return FALSE; } #else /* OpenSSL expects the pubkey in the format specified in section 2.3.4 of * SECG SEC 1, i.e. prefixed with 0x04 to indicate an uncompressed point */ value = chunk_cata("cc", chunk_from_chars(0x04), value); - if (EVP_PKEY_copy_parameters(pub, this->key) <= 0 || - EVP_PKEY_set1_tls_encodedpoint(pub, value.ptr, value.len) <= 0) + if (EVP_PKEY_copy_parameters(this->pub, this->key) <= 0 || + EVP_PKEY_set1_tls_encodedpoint(this->pub, value.ptr, value.len) <= 0) { DBG1(DBG_LIB, "ECDH public value is malformed"); - goto error; + return FALSE; } #endif - - if (!openssl_compute_shared_key(this->key, pub, &this->shared_secret)) - { - DBG1(DBG_LIB, "ECDH shared secret computation failed"); - goto error; - } - this->computed = TRUE; - -error: - EVP_PKEY_free(pub); - return this->computed; + chunk_clear(&this->shared_secret); + return TRUE; } METHOD(diffie_hellman_t, get_my_public_value, bool, @@ -304,8 +294,10 @@ error: METHOD(diffie_hellman_t, get_shared_secret, bool, private_openssl_ec_diffie_hellman_t *this, chunk_t *secret) { - if (!this->computed) + if (!this->shared_secret.len && + !openssl_compute_shared_key(this->key, this->pub, &this->shared_secret)) { + DBG1(DBG_LIB, "ECDH shared secret computation failed"); return FALSE; } *secret = chunk_clone(this->shared_secret); @@ -323,6 +315,7 @@ METHOD(diffie_hellman_t, destroy, void, { EC_GROUP_free(this->ec_group); EVP_PKEY_free(this->key); + EVP_PKEY_free(this->pub); chunk_clear(&this->shared_secret); free(this); } diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c index 55fe80ae8..225f16ad8 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.c +++ b/src/libstrongswan/plugins/openssl/openssl_util.c @@ -62,6 +62,7 @@ bool openssl_compute_shared_key(EVP_PKEY *priv, EVP_PKEY *pub, chunk_t *shared) if (EVP_PKEY_derive(ctx, shared->ptr, &shared->len) <= 0) { + chunk_clear(shared); goto error; } diff --git a/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c index 3d41eb95a..ad36b3dd4 100644 --- a/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c +++ b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c @@ -45,15 +45,15 @@ struct private_diffie_hellman_t { */ EVP_PKEY *key; + /** + * Public key provided by peer + */ + EVP_PKEY *pub; + /** * Shared secret */ chunk_t shared_secret; - - /** - * True if shared secret is computed - */ - bool computed; }; /** @@ -75,33 +75,21 @@ static int map_key_type(diffie_hellman_group_t group) METHOD(diffie_hellman_t, set_other_public_value, bool, private_diffie_hellman_t *this, chunk_t value) { - EVP_PKEY *pub; - if (!diffie_hellman_verify_value(this->group, value)) { return FALSE; } - pub = EVP_PKEY_new_raw_public_key(map_key_type(this->group), NULL, - value.ptr, value.len); - if (!pub) + EVP_PKEY_free(this->pub); + this->pub = EVP_PKEY_new_raw_public_key(map_key_type(this->group), NULL, + value.ptr, value.len); + if (!this->pub) { DBG1(DBG_LIB, "%N public value is malformed", diffie_hellman_group_names, this->group); return FALSE; } - chunk_clear(&this->shared_secret); - - if (!openssl_compute_shared_key(this->key, pub, &this->shared_secret)) - { - DBG1(DBG_LIB, "%N shared secret computation failed", - diffie_hellman_group_names, this->group); - EVP_PKEY_free(pub); - return FALSE; - } - this->computed = TRUE; - EVP_PKEY_free(pub); return TRUE; } @@ -141,8 +129,11 @@ METHOD(diffie_hellman_t, set_private_value, bool, METHOD(diffie_hellman_t, get_shared_secret, bool, private_diffie_hellman_t *this, chunk_t *secret) { - if (!this->computed) + if (!this->shared_secret.len && + !openssl_compute_shared_key(this->key, this->pub, &this->shared_secret)) { + DBG1(DBG_LIB, "%N shared secret computation failed", + diffie_hellman_group_names, this->group); return FALSE; } *secret = chunk_clone(this->shared_secret); @@ -159,6 +150,7 @@ METHOD(diffie_hellman_t, destroy, void, private_diffie_hellman_t *this) { EVP_PKEY_free(this->key); + EVP_PKEY_free(this->pub); chunk_clear(&this->shared_secret); free(this); } From 519bc22091b6bb56abed86f86013a527250fe9ee Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Feb 2022 17:39:39 +0100 Subject: [PATCH 02/15] leak-detective: Whitelist OpenSSL 3.0 functions --- src/libstrongswan/utils/leak_detective.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 0476353ad..5e3be5acc 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -597,6 +597,29 @@ static char *whitelist[] = { "RAND_DRBG_get0_master", "RAND_DRBG_get0_private", "RAND_DRBG_get0_public", + /* OpenSSL 3.0 caches even more static stuff */ + "ERR_set_debug", + "ERR_set_error", + "EVP_DigestSignInit", + "EVP_DigestVerifyInit", + "EVP_PKEY_encrypt_init", + "EVP_PKEY_decrypt_init", + "EVP_PKEY_derive_init", + "EVP_PKEY_sign_init", + "EVP_ASYM_CIPHER_fetch", + "EVP_CIPHER_fetch", + "EVP_KDF_fetch", + "EVP_KEYEXCH_fetch", + "EVP_KEYMGMT_fetch", + "EVP_MAC_fetch", + "EVP_MD_fetch", + "EVP_SIGNATURE_fetch", + "OSSL_DECODER_do_all_provided", + "OSSL_ENCODER_do_all_provided", + "OSSL_PROVIDER_try_load", + "OSSL_PROVIDER_load", + "RAND_get0_private", + "RAND_get0_public", /* We get this via libcurl and OpenSSL 1.1.1 */ "CRYPTO_get_ex_new_index", /* OpenSSL libssl */ From 13efce489e594e5a781ad9ad9b92235c92270745 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 24 Feb 2022 14:50:25 +0100 Subject: [PATCH 03/15] openssl: PRF_KEYED_SHA1 might not be supported The old API has been deprecated with OpenSSL 3 and direct access to the state isn't possible via EVP API. In the future we might just remove this implementation but we'd probably have to implement EAP-AKA' first, which uses HMAC-SHA-256 with IKEv2's prf+ construct to derive keys instead of this weird construct (plus what fips-prf builds around it) that's used by EAP-AKA. --- .../plugins/openssl/openssl_plugin.c | 3 ++- .../plugins/openssl/openssl_sha1_prf.c | 18 ++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index c21292b09..b881c8105 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -615,7 +615,8 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(XOF, XOF_SHAKE_128), PLUGIN_PROVIDE(XOF, XOF_SHAKE_256), #endif -#ifndef OPENSSL_NO_SHA1 +#if !defined(OPENSSL_NO_SHA1) && \ + (OPENSSL_VERSION_NUMBER < 0x30000000L || !defined(OPENSSL_NO_DEPRECATED)) /* keyed sha1 hasher (aka prf) */ PLUGIN_REGISTER(PRF, openssl_sha1_prf_create), PLUGIN_PROVIDE(PRF, PRF_KEYED_SHA1), diff --git a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c index 8371bc17f..fe68f0c17 100644 --- a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c +++ b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c @@ -13,9 +13,15 @@ * for more details. */ +/* direct access to the state and the SHA1_* API have been deprecated with + * OpenSSL 3, so at some point this won't work anymore */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include #include -#ifndef OPENSSL_NO_SHA1 +#if !defined(OPENSSL_NO_SHA1) && \ + (OPENSSL_VERSION_NUMBER < 0x30000000L || !defined(OPENSSL_NO_DEPRECATED)) #include "openssl_sha1_prf.h" @@ -43,14 +49,10 @@ struct private_openssl_sha1_prf_t { METHOD(prf_t, get_bytes, bool, private_openssl_sha1_prf_t *this, chunk_t seed, uint8_t *bytes) { -#if OPENSSL_VERSION_NUMBER >= 0x10000000L if (!SHA1_Update(&this->ctx, seed.ptr, seed.len)) { return FALSE; } -#else /* OPENSSL_VERSION_NUMBER < 1.0 */ - SHA1_Update(&this->ctx, seed.ptr, seed.len); -#endif if (bytes) { @@ -92,14 +94,10 @@ METHOD(prf_t, get_key_size, size_t, METHOD(prf_t, set_key, bool, private_openssl_sha1_prf_t *this, chunk_t key) { -#if OPENSSL_VERSION_NUMBER >= 0x10000000L if (!SHA1_Init(&this->ctx)) { return FALSE; } -#else /* OPENSSL_VERSION_NUMBER < 1.0 */ - SHA1_Init(&this->ctx); -#endif if (key.len % 4) { @@ -162,4 +160,4 @@ openssl_sha1_prf_t *openssl_sha1_prf_create(pseudo_random_function_t algo) return &this->public; } -#endif /* OPENSSL_NO_SHA1 */ +#endif /* !OPENSSL_NO_SHA1 && SHA_LONG */ From f5710c9ccb617c356b2cb4c938f4ffd3146f944a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 24 Feb 2022 17:29:09 +0100 Subject: [PATCH 04/15] openssl: Fixes for ECDH with OpenSSL 3.0 Uses new and non-deprecated APIs to create/generate key pairs. --- .../openssl/openssl_ec_diffie_hellman.c | 231 ++++++++++++------ 1 file changed, 161 insertions(+), 70 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c index ff00ecb80..35969654e 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c @@ -23,6 +23,15 @@ #if OPENSSL_VERSION_NUMBER < 0x1010000fL #include +#elif OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#include +#endif + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +#define EVP_PKEY_set1_encoded_public_key EVP_PKEY_set1_tls_encodedpoint +#define EVP_PKEY_get1_encoded_public_key EVP_PKEY_get1_tls_encodedpoint #endif #include "openssl_ec_diffie_hellman.h" @@ -212,7 +221,7 @@ METHOD(diffie_hellman_t, set_other_public_value, bool, * SECG SEC 1, i.e. prefixed with 0x04 to indicate an uncompressed point */ value = chunk_cata("cc", chunk_from_chars(0x04), value); if (EVP_PKEY_copy_parameters(this->pub, this->key) <= 0 || - EVP_PKEY_set1_tls_encodedpoint(this->pub, value.ptr, value.len) <= 0) + EVP_PKEY_set1_encoded_public_key(this->pub, value.ptr, value.len) <= 0) { DBG1(DBG_LIB, "ECDH public value is malformed"); return FALSE; @@ -232,7 +241,7 @@ METHOD(diffie_hellman_t, get_my_public_value, bool, /* OpenSSL returns the pubkey in the format specified in section 2.3.4 of * SECG SEC 1, i.e. prefixed with 0x04 to indicate an uncompressed point */ - pub.len = EVP_PKEY_get1_tls_encodedpoint(this->key, &pub.ptr); + pub.len = EVP_PKEY_get1_encoded_public_key(this->key, &pub.ptr); if (pub.len != 0) { *value = chunk_clone(chunk_skip(pub, 1)); @@ -243,54 +252,6 @@ METHOD(diffie_hellman_t, get_my_public_value, bool, #endif } -METHOD(diffie_hellman_t, set_private_value, bool, - private_openssl_ec_diffie_hellman_t *this, chunk_t value) -{ - EC_KEY *key = NULL; - EC_POINT *pub = NULL; - BIGNUM *priv = NULL; - bool ret = FALSE; - - priv = BN_bin2bn(value.ptr, value.len, NULL); - if (!priv) - { - goto error; - } - pub = EC_POINT_new(this->ec_group); - if (!pub) - { - goto error; - } - if (EC_POINT_mul(this->ec_group, pub, priv, NULL, NULL, NULL) != 1) - { - goto error; - } - key = EC_KEY_new(); - if (!key || !EC_KEY_set_group(key, this->ec_group)) - { - goto error; - } - if (EC_KEY_set_private_key(key, priv) != 1) - { - goto error; - } - if (EC_KEY_set_public_key(key, pub) != 1) - { - goto error; - } - if (EVP_PKEY_set1_EC_KEY(this->key, key) != 1) - { - goto error; - } - ret = TRUE; - -error: - EC_POINT_free(pub); - BN_free(priv); - EC_KEY_free(key); - return ret; -} - METHOD(diffie_hellman_t, get_shared_secret, bool, private_openssl_ec_diffie_hellman_t *this, chunk_t *secret) { @@ -310,16 +271,6 @@ METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, return this->group; } -METHOD(diffie_hellman_t, destroy, void, - private_openssl_ec_diffie_hellman_t *this) -{ - EC_GROUP_free(this->ec_group); - EVP_PKEY_free(this->key); - EVP_PKEY_free(this->pub); - chunk_clear(&this->shared_secret); - free(this); -} - /* * Described in header */ @@ -353,21 +304,151 @@ int openssl_ecdh_group_to_nid(diffie_hellman_group_t group) } } +/** + * Parse the given private key as BIGNUM and calculate the corresponding public + * key as EC_POINT. + */ +static bool get_keypair(EC_GROUP *group, chunk_t value, BIGNUM **priv, + EC_POINT **pub) +{ + *priv = BN_bin2bn(value.ptr, value.len, NULL); + *pub = EC_POINT_new(group); + return *priv && *pub && + EC_POINT_mul(group, *pub, *priv, NULL, NULL, NULL) == 1; +} + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +/** + * Convert the given EC_POINT to a chunk. + */ +static bool ecp2chunk(EC_GROUP *group, EC_POINT *point, chunk_t *chunk) +{ + BN_CTX *ctx = BN_CTX_new(); + + if (ctx) + { + chunk->len = EC_POINT_point2buf(group, point, + POINT_CONVERSION_UNCOMPRESSED, + &chunk->ptr, ctx); + } + BN_CTX_free(ctx); + return chunk->len; +} + +METHOD(diffie_hellman_t, set_private_value, bool, + private_openssl_ec_diffie_hellman_t *this, chunk_t value) +{ + BIGNUM *priv = NULL; + EC_POINT *pub = NULL; + chunk_t pub_chunk = chunk_empty; + const char *name; + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx; + EVP_PKEY *key = NULL; + bool ret = FALSE; + + if (!get_keypair(this->ec_group, value, &priv, &pub) || + !ecp2chunk(this->ec_group, pub, &pub_chunk)) + { + EC_POINT_free(pub); + BN_free(priv); + return FALSE; + } + EC_POINT_free(pub); + + name = OSSL_EC_curve_nid2name(openssl_ecdh_group_to_nid(this->group)); + bld = OSSL_PARAM_BLD_new(); + if (name && bld && + OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + (char*)name, 0) && + OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, + pub_chunk.ptr, pub_chunk.len) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv)) + { + params = OSSL_PARAM_BLD_to_param(bld); + } + OSSL_PARAM_BLD_free(bld); + chunk_free(&pub_chunk); + BN_free(priv); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (params && ctx && + EVP_PKEY_fromdata_init(ctx) > 0 && + EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_KEYPAIR, params) > 0) + { + EVP_PKEY_free(this->key); + this->key = key; + ret = TRUE; + } + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + return ret; +} + +#else /* OPENSSL_VERSION_NUMBER */ + +METHOD(diffie_hellman_t, set_private_value, bool, + private_openssl_ec_diffie_hellman_t *this, chunk_t value) +{ + EC_KEY *key = NULL; + EC_POINT *pub = NULL; + BIGNUM *priv = NULL; + bool ret = FALSE; + + if (!get_keypair(this->ec_group, value, &priv, &pub)) + { + goto error; + } + key = EC_KEY_new(); + if (!key || !EC_KEY_set_group(key, this->ec_group)) + { + goto error; + } + if (EC_KEY_set_private_key(key, priv) != 1) + { + goto error; + } + if (EC_KEY_set_public_key(key, pub) != 1) + { + goto error; + } + if (EVP_PKEY_set1_EC_KEY(this->key, key) != 1) + { + goto error; + } + ret = TRUE; + +error: + EC_POINT_free(pub); + BN_free(priv); + EC_KEY_free(key); + return ret; +} + +#endif /* OPENSSL_VERSION_NUMBER */ + +METHOD(diffie_hellman_t, destroy, void, + private_openssl_ec_diffie_hellman_t *this) +{ + EC_GROUP_free(this->ec_group); + EVP_PKEY_free(this->key); + EVP_PKEY_free(this->pub); + chunk_clear(&this->shared_secret); + free(this); +} + /* * Described in header */ openssl_ec_diffie_hellman_t *openssl_ec_diffie_hellman_create(diffie_hellman_group_t group) { private_openssl_ec_diffie_hellman_t *this; - EC_KEY *key = NULL; int curve; curve = openssl_ecdh_group_to_nid(group); - if (curve) - { - key = EC_KEY_new_by_curve_name(curve); - } - if (!key) + if (!curve) { return NULL; } @@ -384,17 +465,25 @@ openssl_ec_diffie_hellman_t *openssl_ec_diffie_hellman_create(diffie_hellman_gro }, }, .group = group, - .ec_group = EC_GROUP_dup(EC_KEY_get0_group(key)), ); - /* generate an EC private (public) key */ - if (!EC_KEY_generate_key(key)) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + this->ec_group = EC_GROUP_new_by_curve_name(curve); + this->key = EVP_EC_gen(OSSL_EC_curve_nid2name(curve)); + if (!this->key) + { + destroy(this); + return NULL; + } +#else + EC_KEY *key = EC_KEY_new_by_curve_name(curve); + if (!key || !EC_KEY_generate_key(key)) { EC_KEY_free(key); destroy(this); return NULL; } - + this->ec_group = EC_GROUP_dup(EC_KEY_get0_group(key)); this->key = EVP_PKEY_new(); if (!this->key || !EVP_PKEY_assign_EC_KEY(this->key, key)) { @@ -402,6 +491,8 @@ openssl_ec_diffie_hellman_t *openssl_ec_diffie_hellman_create(diffie_hellman_gro destroy(this); return NULL; } +#endif + return &this->public; } From 36cf74f5d92cc0d1da0bfeebb32a759bc149e9ae Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Feb 2022 17:05:24 +0100 Subject: [PATCH 05/15] openssl: Fixes for DH with OpenSSL 3.0 While we could assign the DH object to a EVP_PKEY object, this won't work with BoringSSL as it doesn't seem to support EVP_PKEY_derive() for DH. --- .../plugins/openssl/openssl_diffie_hellman.c | 285 ++++++++++++++---- .../plugins/openssl/openssl_util.c | 13 + 2 files changed, 236 insertions(+), 62 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c index 876742f35..01b0fa0ea 100644 --- a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c +++ b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c @@ -18,9 +18,15 @@ #ifndef OPENSSL_NO_DH +#include #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#endif + #include "openssl_diffie_hellman.h" #include "openssl_util.h" @@ -49,6 +55,17 @@ struct private_openssl_diffie_hellman_t { */ diffie_hellman_group_t group; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + /** + * Diffie Hellman key + */ + EVP_PKEY *key; + + /** + * Other public value + */ + EVP_PKEY *pub; +#else /** * Diffie Hellman object */ @@ -58,6 +75,7 @@ struct private_openssl_diffie_hellman_t { * Other public value */ BIGNUM *pub_key; +#endif /** * Shared secret @@ -65,9 +83,27 @@ struct private_openssl_diffie_hellman_t { chunk_t shared_secret; }; +METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, + private_openssl_diffie_hellman_t *this) +{ + return this->group; +} + METHOD(diffie_hellman_t, get_my_public_value, bool, private_openssl_diffie_hellman_t *this, chunk_t *value) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + chunk_t pub; + + pub.len = EVP_PKEY_get1_encoded_public_key(this->key, &pub.ptr); + if (pub.len != 0) + { + *value = chunk_clone(pub); + OPENSSL_free(pub.ptr); + return value->len != 0; + } + return FALSE; +#else const BIGNUM *pubkey; *value = chunk_alloc(DH_size(this->dh)); @@ -75,11 +111,22 @@ METHOD(diffie_hellman_t, get_my_public_value, bool, DH_get0_key(this->dh, &pubkey, NULL); BN_bn2bin(pubkey, value->ptr + value->len - BN_num_bytes(pubkey)); return TRUE; +#endif } METHOD(diffie_hellman_t, get_shared_secret, bool, private_openssl_diffie_hellman_t *this, chunk_t *secret) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!this->shared_secret.len && + !openssl_compute_shared_key(this->key, this->pub, &this->shared_secret)) + { + DBG1(DBG_LIB, "DH shared secret computation failed"); + return FALSE; + } + *secret = chunk_clone(this->shared_secret); + return TRUE; +#else int len; if (!this->shared_secret.len) @@ -99,6 +146,7 @@ METHOD(diffie_hellman_t, get_shared_secret, bool, *secret = chunk_copy_pad(chunk_alloc(DH_size(this->dh)), this->shared_secret, 0); return TRUE; +#endif } @@ -110,14 +158,101 @@ METHOD(diffie_hellman_t, set_other_public_value, bool, return FALSE; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!this->pub) + { + this->pub = EVP_PKEY_new(); + } + if (EVP_PKEY_copy_parameters(this->pub, this->key) <= 0 || + EVP_PKEY_set1_encoded_public_key(this->pub, value.ptr, value.len) <= 0) + { + DBG1(DBG_LIB, "DH public value is malformed"); + return FALSE; + } +#else if (!BN_bin2bn(value.ptr, value.len, this->pub_key)) { return FALSE; } +#endif chunk_clear(&this->shared_secret); return TRUE; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +/** + * Calculate the public key for the given private key and DH parameters. + * Setting only the private key and generating the public key interanlly is + * not supported anymore with OpenSSL 3.0.0. + */ +static BIGNUM *calculate_public_key(BIGNUM *priv, const BIGNUM *g, + const BIGNUM *p) +{ + BN_CTX *ctx = BN_CTX_new(); + BIGNUM *pub = BN_new(); + + BN_set_flags(priv, BN_FLG_CONSTTIME); + /* pub = g^priv mod p */ + if (!ctx || ! pub || !BN_mod_exp(pub, g, priv, p, ctx)) + { + BN_free(pub); + pub = NULL; + } + BN_CTX_free(ctx); + return pub; +} + +METHOD(diffie_hellman_t, set_private_value, bool, + private_openssl_diffie_hellman_t *this, chunk_t value) +{ + BIGNUM *priv, *g = NULL, *p = NULL, *pub = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY *key = NULL; + EVP_PKEY_CTX *ctx = NULL; + bool ret = FALSE; + + priv = BN_bin2bn(value.ptr, value.len, NULL); + if (EVP_PKEY_get_bn_param(this->key, OSSL_PKEY_PARAM_FFC_G, &g) <= 0 || + EVP_PKEY_get_bn_param(this->key, OSSL_PKEY_PARAM_FFC_P, &p) <= 0) + { + goto error; + } + pub = calculate_public_key(priv, g, p); + bld = OSSL_PARAM_BLD_new(); + if (pub && bld && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, pub)) + { + params = OSSL_PARAM_BLD_to_param(bld); + } + ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (!params || !ctx || + EVP_PKEY_fromdata_init(ctx) <= 0 || + EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_KEYPAIR, params) <= 0) + { + goto error; + } + EVP_PKEY_free(this->key); + this->key = key; + ret = TRUE; + +error: + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + BN_free(pub); + BN_free(p); + BN_free(g); + BN_free(priv); + return ret; +} + +#else /* OPENSSL_VERSION_NUMBER */ + METHOD(diffie_hellman_t, set_private_value, bool, private_openssl_diffie_hellman_t *this, chunk_t value) { @@ -136,50 +271,18 @@ METHOD(diffie_hellman_t, set_private_value, bool, return FALSE; } -METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, - private_openssl_diffie_hellman_t *this) -{ - return this->group; -} - -/** - * Lookup the modulus in modulo table - */ -static status_t set_modulus(private_openssl_diffie_hellman_t *this) -{ - BIGNUM *p, *g; - - diffie_hellman_params_t *params = diffie_hellman_get_params(this->group); - if (!params) - { - return NOT_FOUND; - } - p = BN_bin2bn(params->prime.ptr, params->prime.len, NULL); - g = BN_bin2bn(params->generator.ptr, params->generator.len, NULL); - if (!DH_set0_pqg(this->dh, p, NULL, g)) - { - return FAILED; - } - if (params->exp_len != params->prime.len) - { -#if defined(OPENSSL_IS_BORINGSSL) && \ - (!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 11) - this->dh->priv_length = params->exp_len * 8; -#else - if (!DH_set_length(this->dh, params->exp_len * 8)) - { - return FAILED; - } -#endif - } - return SUCCESS; -} +#endif /* OPENSSL_VERSION_NUMBER */ METHOD(diffie_hellman_t, destroy, void, private_openssl_diffie_hellman_t *this) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(this->key); + EVP_PKEY_free(this->pub); +#else BN_clear_free(this->pub_key); DH_free(this->dh); +#endif chunk_clear(&this->shared_secret); free(this); } @@ -191,7 +294,8 @@ openssl_diffie_hellman_t *openssl_diffie_hellman_create( diffie_hellman_group_t group, ...) { private_openssl_diffie_hellman_t *this; - const BIGNUM *privkey; + BIGNUM *g, *p; + int priv_len = 0; INIT(this, .public = { @@ -204,48 +308,105 @@ openssl_diffie_hellman_t *openssl_diffie_hellman_create( .destroy = _destroy, }, }, + .group = group, ); - this->dh = DH_new(); - if (!this->dh) - { - free(this); - return NULL; - } - - this->group = group; - this->pub_key = BN_new(); - if (group == MODP_CUSTOM) { - chunk_t g, p; + chunk_t g_chunk, p_chunk; - VA_ARGS_GET(group, g, p); - if (!DH_set0_pqg(this->dh, BN_bin2bn(p.ptr, p.len, NULL), NULL, - BN_bin2bn(g.ptr, g.len, NULL))) - { - destroy(this); - return NULL; - } + VA_ARGS_GET(group, g_chunk, p_chunk); + g = BN_bin2bn(g_chunk.ptr, g_chunk.len, NULL); + p = BN_bin2bn(p_chunk.ptr, p_chunk.len, NULL); } else { - /* find a modulus according to group */ - if (set_modulus(this) != SUCCESS) + diffie_hellman_params_t *params = diffie_hellman_get_params(group); + if (!params) { destroy(this); return NULL; } + g = BN_bin2bn(params->generator.ptr, params->generator.len, NULL); + p = BN_bin2bn(params->prime.ptr, params->prime.len, NULL); + if (params->exp_len != params->prime.len) + { + priv_len = params->exp_len * 8; + } } - /* generate my public and private values */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx; + + /* if we abandoned MODP_CUSTOM, we could set OSSL_PKEY_PARAM_GROUP_NAME, + * which wouldn't require the first ctx/key for the parameters */ + bld = OSSL_PARAM_BLD_new(); + if (bld && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) && + (!priv_len || + OSSL_PARAM_BLD_push_int(bld, OSSL_PKEY_PARAM_DH_PRIV_LEN, priv_len))) + { + params = OSSL_PARAM_BLD_to_param(bld); + } + OSSL_PARAM_BLD_free(bld); + BN_free(g); + BN_free(p); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (!params || !ctx || + EVP_PKEY_fromdata_init(ctx) <= 0 || + EVP_PKEY_fromdata(ctx, &this->key, EVP_PKEY_KEY_PARAMETERS, params) <= 0) + { + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + destroy(this); + return NULL; + } + OSSL_PARAM_free(params); + EVP_PKEY_CTX_free(ctx); + + ctx = EVP_PKEY_CTX_new(this->key, NULL); + if (!ctx || + EVP_PKEY_keygen_init(ctx) <= 0 || + EVP_PKEY_generate(ctx, &this->key) <= 0) + { + EVP_PKEY_CTX_free(ctx); + destroy(this); + return NULL; + } + EVP_PKEY_CTX_free(ctx); +#else /* OPENSSL_VERSION_NUMBER */ + this->dh = DH_new(); + this->pub_key = BN_new(); + if (!DH_set0_pqg(this->dh, p, NULL, g)) + { + BN_free(g); + BN_free(p); + destroy(this); + return NULL; + } + if (priv_len) + { +#if defined(OPENSSL_IS_BORINGSSL) && \ + (!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 11) + this->dh->priv_length = priv_len; +#else + if (!DH_set_length(this->dh, priv_len)) + { + destroy(this); + return NULL; + } +#endif + } if (!DH_generate_key(this->dh)) { destroy(this); return NULL; } - DH_get0_key(this->dh, NULL, &privkey); - DBG2(DBG_LIB, "size of DH secret exponent: %d bits", BN_num_bits(privkey)); +#endif /* OPENSSL_VERSION_NUMBER */ return &this->public; } diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c index 225f16ad8..f01ac797e 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.c +++ b/src/libstrongswan/plugins/openssl/openssl_util.c @@ -22,6 +22,11 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +/* for EVP_PKEY_CTX_set_dh_pad */ +#include +#endif + /* these were added with 1.1.0 when ASN1_OBJECT was made opaque */ #if OPENSSL_VERSION_NUMBER < 0x10100000L #define OBJ_get0_data(o) ((o)->data) @@ -48,6 +53,14 @@ bool openssl_compute_shared_key(EVP_PKEY *priv, EVP_PKEY *pub, chunk_t *shared) goto error; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (EVP_PKEY_base_id(priv) == EVP_PKEY_DH && + EVP_PKEY_CTX_set_dh_pad(ctx, 1) <= 0) + { + goto error; + } +#endif + if (EVP_PKEY_derive_set_peer(ctx, pub) <= 0) { goto error; From 21b586c61c95756add73aaeaaa292571565bdb4c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 28 Feb 2022 14:28:18 +0100 Subject: [PATCH 06/15] openssl: Fixes for RSA with OpenSSL 3.0 --- .../plugins/openssl/openssl_plugin.c | 2 - .../plugins/openssl/openssl_rsa_private_key.c | 471 ++++++++---------- .../plugins/openssl/openssl_rsa_public_key.c | 361 +++++++------- src/libstrongswan/tests/suites/test_rsa.c | 63 ++- 4 files changed, 445 insertions(+), 452 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index b881c8105..7ea53b858 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -723,10 +723,8 @@ METHOD(plugin_t, get_features, int, /* signature/encryption schemes */ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_NULL), PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL), -#if OPENSSL_VERSION_NUMBER >= 0x10000000L PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS), PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS), -#endif #ifndef OPENSSL_NO_SHA1 PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1), PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1), diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index 15a4ead3d..f8334cba9 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -31,6 +31,11 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#endif + /** * Public exponent to use for key generation. */ @@ -41,6 +46,7 @@ OPENSSL_KEY_FALLBACK(RSA, key, n, e, d) OPENSSL_KEY_FALLBACK(RSA, factors, p, q) OPENSSL_KEY_FALLBACK(RSA, crt_params, dmp1, dmq1, iqmp) #define BN_secure_new() BN_new() +#define BN_CTX_secure_new() BN_CTX_new() #endif typedef struct private_openssl_rsa_private_key_t private_openssl_rsa_private_key_t; @@ -55,9 +61,9 @@ struct private_openssl_rsa_private_key_t { openssl_rsa_private_key_t public; /** - * RSA object from OpenSSL + * RSA key object */ - RSA *rsa; + EVP_PKEY *key; /** * TRUE if the key is from an OpenSSL ENGINE and might not be readable @@ -71,9 +77,7 @@ struct private_openssl_rsa_private_key_t { }; /* implemented in rsa public key */ -bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp); - -#if OPENSSL_VERSION_NUMBER >= 0x10000000L +bool openssl_rsa_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp); /** * Build RSA signature @@ -84,20 +88,14 @@ static bool build_signature(private_openssl_rsa_private_key_t *this, { EVP_PKEY_CTX *pctx = NULL; EVP_MD_CTX *mctx = NULL; - EVP_PKEY *key; bool success = FALSE; mctx = EVP_MD_CTX_create(); - key = EVP_PKEY_new(); - if (!mctx || !key) + if (!mctx) { - goto error; + return FALSE; } - if (!EVP_PKEY_set1_RSA(key, this->rsa)) - { - goto error; - } - if (EVP_DigestSignInit(mctx, &pctx, md, NULL, key) <= 0) + if (EVP_DigestSignInit(mctx, &pctx, md, NULL, this->key) <= 0) { goto error; } @@ -118,17 +116,31 @@ static bool build_signature(private_openssl_rsa_private_key_t *this, success = (EVP_DigestSignFinal(mctx, sig->ptr, &sig->len) == 1); error: - if (key) - { - EVP_PKEY_free(key); - } - if (mctx) - { - EVP_MD_CTX_destroy(mctx); - } + EVP_MD_CTX_destroy(mctx); return success; } +/** + * Build an EMSA PKCS1 signature without hashing + */ +static bool build_plain_signature(private_openssl_rsa_private_key_t *this, + chunk_t data, chunk_t *sig) +{ + EVP_PKEY_CTX *ctx; + + ctx = EVP_PKEY_CTX_new(this->key, NULL); + if (!ctx || + EVP_PKEY_sign_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 || + EVP_PKEY_sign(ctx, sig->ptr, &sig->len, data.ptr, data.len) <= 0) + { + EVP_PKEY_CTX_free(ctx); + return FALSE; + } + EVP_PKEY_CTX_free(ctx); + return TRUE; +} + /** * Build an EMSA PKCS1 signature described in PKCS#1 */ @@ -137,12 +149,11 @@ static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this, { const EVP_MD *md; - *sig = chunk_alloc(RSA_size(this->rsa)); + *sig = chunk_alloc(EVP_PKEY_size(this->key)); if (type == NID_undef) { - if (RSA_private_encrypt(data.len, data.ptr, sig->ptr, this->rsa, - RSA_PKCS1_PADDING) == sig->len) + if (build_plain_signature(this, data, sig)) { return TRUE; } @@ -173,7 +184,7 @@ static bool build_emsa_pss_signature(private_openssl_rsa_private_key_t *this, return FALSE; } - *sig = chunk_alloc(RSA_size(this->rsa)); + *sig = chunk_alloc(EVP_PKEY_size(this->key)); md = openssl_get_md(params->hash); if (md && build_signature(this, md, params, data, sig)) @@ -184,80 +195,6 @@ static bool build_emsa_pss_signature(private_openssl_rsa_private_key_t *this, return FALSE; } -#else /* OPENSSL_VERSION_NUMBER < 1.0 */ - -/** - * Build an EMSA PKCS1 signature described in PKCS#1 - */ -static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this, - int type, chunk_t data, chunk_t *sig) -{ - bool success = FALSE; - - *sig = chunk_alloc(RSA_size(this->rsa)); - - if (type == NID_undef) - { - if (RSA_private_encrypt(data.len, data.ptr, sig->ptr, this->rsa, - RSA_PKCS1_PADDING) == sig->len) - { - success = TRUE; - } - } - else - { - EVP_MD_CTX *ctx = NULL; - EVP_PKEY *key = NULL; - const EVP_MD *hasher; - u_int len; - - hasher = EVP_get_digestbynid(type); - if (!hasher) - { - goto error; - } - - ctx = EVP_MD_CTX_create(); - key = EVP_PKEY_new(); - if (!ctx || !key) - { - goto error; - } - if (!EVP_PKEY_set1_RSA(key, this->rsa)) - { - goto error; - } - if (!EVP_SignInit_ex(ctx, hasher, NULL)) - { - goto error; - } - if (!EVP_SignUpdate(ctx, data.ptr, data.len)) - { - goto error; - } - if (EVP_SignFinal(ctx, sig->ptr, &len, key)) - { - success = TRUE; - } - -error: - if (key) - { - EVP_PKEY_free(key); - } - if (ctx) - { - EVP_MD_CTX_destroy(ctx); - } - } - if (!success) - { - free(sig->ptr); - } - return success; -} -#endif /* OPENSSL_VERSION_NUMBER < 1.0 */ - METHOD(private_key_t, get_type, key_type_t, private_openssl_rsa_private_key_t *this) { @@ -294,10 +231,8 @@ METHOD(private_key_t, sign, bool, return build_emsa_pkcs1_signature(this, NID_sha1, data, signature); case SIGN_RSA_EMSA_PKCS1_MD5: return build_emsa_pkcs1_signature(this, NID_md5, data, signature); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L case SIGN_RSA_EMSA_PSS: return build_emsa_pss_signature(this, params, data, signature); -#endif default: DBG1(DBG_LIB, "signature scheme %N not supported in RSA", signature_scheme_names, scheme); @@ -310,7 +245,6 @@ METHOD(private_key_t, decrypt, bool, void *params, chunk_t crypto, chunk_t *plain) { EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *evp_key = NULL; chunk_t label = chunk_empty; hash_algorithm_t hash_alg = HASH_UNKNOWN; size_t len; @@ -349,23 +283,11 @@ METHOD(private_key_t, decrypt, bool, return FALSE; } - evp_key = EVP_PKEY_new(); - if (!evp_key) - { - DBG1(DBG_LIB, "could not create EVP key"); - goto error; - } - if (EVP_PKEY_set1_RSA(evp_key, this->rsa) <= 0) - { - DBG1(DBG_LIB, "could not set EVP key to RSA key"); - goto error; - } - - ctx = EVP_PKEY_CTX_new(evp_key, NULL); + ctx = EVP_PKEY_CTX_new(this->key, NULL); if (!ctx) { DBG1(DBG_LIB, "could not create EVP context"); - goto error; + return FALSE; } if (EVP_PKEY_decrypt_init(ctx) <= 0) @@ -410,7 +332,7 @@ METHOD(private_key_t, decrypt, bool, } /* determine maximum plaintext size */ - len = RSA_size(this->rsa); + len = EVP_PKEY_size(this->key); decrypted = malloc(len); /* decrypt data */ @@ -424,33 +346,23 @@ METHOD(private_key_t, decrypt, bool, success = TRUE; error: - if (ctx) - { - EVP_PKEY_CTX_free(ctx); - } - if (evp_key) - { - EVP_PKEY_free(evp_key); - } + EVP_PKEY_CTX_free(ctx); return success; } METHOD(private_key_t, get_keysize, int, private_openssl_rsa_private_key_t *this) { - return RSA_size(this->rsa) * 8; + return EVP_PKEY_bits(this->key); } METHOD(private_key_t, get_public_key, public_key_t*, private_openssl_rsa_private_key_t *this) { - chunk_t enc; public_key_t *key; - u_char *p; + chunk_t enc; - enc = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL)); - p = enc.ptr; - i2d_RSAPublicKey(this->rsa, &p); + enc = openssl_i2chunk(PublicKey, this->key); key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER, enc, BUILD_END); free(enc.ptr); @@ -461,15 +373,13 @@ METHOD(private_key_t, get_fingerprint, bool, private_openssl_rsa_private_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint) { - return openssl_rsa_fingerprint(this->rsa, type, fingerprint); + return openssl_rsa_fingerprint(this->key, type, fingerprint); } METHOD(private_key_t, get_encoding, bool, private_openssl_rsa_private_key_t *this, cred_encoding_type_t type, chunk_t *encoding) { - u_char *p; - if (this->engine) { return FALSE; @@ -481,9 +391,7 @@ METHOD(private_key_t, get_encoding, bool, { bool success = TRUE; - *encoding = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL)); - p = encoding->ptr; - i2d_RSAPrivateKey(this->rsa, &p); + *encoding = openssl_i2chunk(PrivateKey, this->key); if (type == PRIVKEY_PEM) { @@ -513,10 +421,10 @@ METHOD(private_key_t, destroy, void, { if (ref_put(&this->ref)) { - if (this->rsa) + if (this->key) { - lib->encoding->clear_cache(lib->encoding, this->rsa); - RSA_free(this->rsa); + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); } free(this); } @@ -525,7 +433,7 @@ METHOD(private_key_t, destroy, void, /** * Internal generic constructor */ -static private_openssl_rsa_private_key_t *create_empty() +static private_openssl_rsa_private_key_t *create_internal(EVP_PKEY *key) { private_openssl_rsa_private_key_t *this; @@ -547,6 +455,7 @@ static private_openssl_rsa_private_key_t *create_empty() }, }, .ref = 1, + .key = key, ); return this; @@ -559,9 +468,9 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_gen(key_type_t type, va_list args) { private_openssl_rsa_private_key_t *this; + EVP_PKEY *key = NULL; u_int key_size = 0; - RSA *rsa = NULL; - BIGNUM *e = NULL; + BIGNUM *e; while (TRUE) { @@ -583,29 +492,54 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_gen(key_type_t type, } e = BN_new(); if (!e || !BN_set_word(e, PUBLIC_EXPONENT)) - { - goto error; - } - rsa = RSA_new(); - if (!rsa || !RSA_generate_key_ex(rsa, key_size, e, NULL)) - { - goto error; - } - this = create_empty(); - this->rsa = rsa; - BN_free(e); - return &this->public; - -error: - if (e) { BN_free(e); + return NULL; } - if (rsa) + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + /* EVP_RSA_gen() does not allow specifying the public exponent, the default + * value is the same, but let's still use this more flexible approach */ + EVP_PKEY_CTX *ctx; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (!ctx || + EVP_PKEY_keygen_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, key_size) <= 0 || + EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) <= 0 || + EVP_PKEY_keygen(ctx, &key) <= 0) + { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + EVP_PKEY_CTX_free(ctx); +#else /* OPENSSL_VERSION_NUMBER */ + RSA *rsa = RSA_new(); + + if (RSA_generate_key_ex(rsa, key_size, e, NULL)) + { + key = EVP_PKEY_new(); + if (!EVP_PKEY_assign_RSA(key, rsa)) + { + RSA_free(rsa); + EVP_PKEY_free(key); + key = NULL; + } + } + else { RSA_free(rsa); } - return NULL; +#endif /* OPENSSL_VERSION_NUMBER */ + + if (!key) + { + BN_free(e); + return NULL; + } + this = create_internal(key); + BN_free(e); + return &this->public; } /* @@ -614,16 +548,13 @@ error: private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine) { private_openssl_rsa_private_key_t *this; - RSA *rsa; - rsa = EVP_PKEY_get1_RSA(key); - EVP_PKEY_free(key); - if (!rsa) + if (EVP_PKEY_base_id(key) != EVP_PKEY_RSA) { + EVP_PKEY_free(key); return NULL; } - this = create_empty(); - this->rsa = rsa; + this = create_internal(key); this->engine = engine; return &this->public.key; } @@ -632,19 +563,13 @@ private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine) * Recover the primes from n, e and d using the algorithm described in * Appendix C of NIST SP 800-56B. */ -static bool calculate_pq(BIGNUM *n, BIGNUM *e, BIGNUM *d, - BIGNUM **p, BIGNUM **q) +static bool calculate_pq(BN_CTX *ctx, BIGNUM *n, BIGNUM *e, BIGNUM *d, + BIGNUM *p, BIGNUM *q) { - BN_CTX *ctx; BIGNUM *k, *r, *g, *y, *n1, *x; int i, t, j; bool success = FALSE; - ctx = BN_CTX_new(); - if (!ctx) - { - return FALSE; - } BN_CTX_start(ctx); k = BN_CTX_get(ctx); r = BN_CTX_get(ctx); @@ -685,7 +610,7 @@ static bool calculate_pq(BIGNUM *n, BIGNUM *e, BIGNUM *d, } for (i = 0; i < 100; i++) { /* generate random integer g in [0, n-1] */ - if (!BN_pseudo_rand_range(g, n)) + if (!BN_rand_range(g, n)) { goto error; } @@ -730,25 +655,19 @@ done: { goto error; } - *p = BN_secure_new(); - if (!BN_gcd(*p, y, n, ctx)) + if (!BN_gcd(p, y, n, ctx)) { - BN_clear_free(*p); goto error; } /* q = n/p */ - *q = BN_secure_new(); - if (!BN_div(*q, NULL, n, *p, ctx)) + if (!BN_div(q, NULL, n, p, ctx)) { - BN_clear_free(*p); - BN_clear_free(*q); goto error; } success = TRUE; error: BN_CTX_end(ctx); - BN_CTX_free(ctx); return success; } @@ -756,65 +675,31 @@ error: * Calculates dp = d (mod p-1) or dq = d (mod q-1) for the Chinese remainder * algorithm. */ -static BIGNUM *dmodpq1(BIGNUM *d, BIGNUM *pq) +static bool dmodpq1(BN_CTX *ctx, BIGNUM *d, BIGNUM *pq, BIGNUM *res) { - BN_CTX *ctx; - BIGNUM *res = NULL, *pq1; + BIGNUM *pq1; - ctx = BN_CTX_new(); - if (!ctx) - { - return NULL; - } BN_CTX_start(ctx); pq1 = BN_CTX_get(ctx); - /* p|q - 1 */ - if (!BN_sub(pq1, pq, BN_value_one())) + /* p|q - 1 + * d (mod p|q -1) */ + if (!BN_sub(pq1, pq, BN_value_one()) || + !BN_mod(res, d, pq1, ctx)) { - goto error; + BN_CTX_end(ctx); + return FALSE; } - /* d (mod p|q -1) */ - res = BN_secure_new(); - if (!BN_mod(res, d, pq1, ctx)) - { - BN_clear_free(res); - res = NULL; - goto error; - } - -error: BN_CTX_end(ctx); - BN_CTX_free(ctx); - return res; + return TRUE; } /** * Calculates qinv = q^-1 (mod p) for the Chinese remainder algorithm. */ -static BIGNUM *qinv(BIGNUM *q, BIGNUM *p) +static bool qinv(BN_CTX *ctx, BIGNUM *q, BIGNUM *p, BIGNUM *res) { - BN_CTX *ctx; - BIGNUM *res = NULL; - - ctx = BN_CTX_new(); - if (!ctx) - { - return NULL; - } - BN_CTX_start(ctx); /* q^-1 (mod p) */ - res = BN_secure_new(); - if (!BN_mod_inverse(res, q, p, ctx)) - { - BN_clear_free(res); - res = NULL; - goto error; - } - -error: - BN_CTX_end(ctx); - BN_CTX_free(ctx); - return res; + return BN_mod_inverse(res, q, p, ctx); } /* @@ -824,6 +709,7 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type, va_list args) { private_openssl_rsa_private_key_t *this; + EVP_PKEY *key = NULL; chunk_t blob, n, e, d, p, q, exp1, exp2, coeff; blob = n = e = d = p = q = exp1 = exp2 = coeff = chunk_empty; @@ -866,79 +752,126 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type, break; } - this = create_empty(); if (blob.ptr) { - this->rsa = d2i_RSAPrivateKey(NULL, (const u_char**)&blob.ptr, blob.len); - if (this->rsa && RSA_check_key(this->rsa) == 1) - { - return &this->public; - } + key = d2i_PrivateKey(EVP_PKEY_RSA, NULL, (const u_char**)&blob.ptr, + blob.len); } else if (n.ptr && e.ptr && d.ptr) { - BIGNUM *bn_n, *bn_e, *bn_d, *bn_p, *bn_q; - BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; + BN_CTX *ctx; + BIGNUM *bn_n, *bn_e, *bn_d, *bn_p, *bn_q, *dmp1, *dmq1, *iqmp; - this->rsa = RSA_new(); - - bn_n = BN_bin2bn((const u_char*)n.ptr, n.len, NULL); - bn_e = BN_bin2bn((const u_char*)e.ptr, e.len, NULL); - bn_d = BN_bin2bn((const u_char*)d.ptr, d.len, NULL); - if (!RSA_set0_key(this->rsa, bn_n, bn_e, bn_d)) + ctx = BN_CTX_secure_new(); + if (!ctx) { goto error; - } + BN_CTX_start(ctx); + bn_n = BN_CTX_get(ctx); + bn_e = BN_CTX_get(ctx); + bn_d = BN_CTX_get(ctx); + bn_p = BN_CTX_get(ctx); + bn_q = BN_CTX_get(ctx); + dmp1 = BN_CTX_get(ctx); + dmq1 = BN_CTX_get(ctx); + iqmp = BN_CTX_get(ctx); + + bn_n = BN_bin2bn((const u_char*)n.ptr, n.len, bn_n); + bn_e = BN_bin2bn((const u_char*)e.ptr, e.len, bn_e); + bn_d = BN_bin2bn((const u_char*)d.ptr, d.len, bn_d); if (p.ptr && q.ptr) { - bn_p = BN_bin2bn((const u_char*)p.ptr, p.len, NULL); - bn_q = BN_bin2bn((const u_char*)q.ptr, q.len, NULL); + bn_p = BN_bin2bn((const u_char*)p.ptr, p.len, bn_p); + bn_q = BN_bin2bn((const u_char*)q.ptr, q.len, bn_q); } - else - { - if (!calculate_pq(bn_n, bn_e, bn_d, &bn_p, &bn_q)) - { - goto error; - } - } - if (!RSA_set0_factors(this->rsa, bn_p, bn_q)) + else if (!calculate_pq(ctx, bn_n, bn_e, bn_d, bn_p, bn_q)) { goto error; } if (exp1.ptr) { - dmp1 = BN_bin2bn((const u_char*)exp1.ptr, exp1.len, NULL); + dmp1 = BN_bin2bn((const u_char*)exp1.ptr, exp1.len, dmp1); } - else + else if (!dmodpq1(ctx, bn_d, bn_p, dmp1)) { - dmp1 = dmodpq1(bn_d, bn_p); + goto error; } if (exp2.ptr) { - dmq1 = BN_bin2bn((const u_char*)exp2.ptr, exp2.len, NULL); + dmq1 = BN_bin2bn((const u_char*)exp2.ptr, exp2.len, dmq1); } - else + else if (!dmodpq1(ctx, bn_d, bn_q, dmq1)) { - dmq1 = dmodpq1(bn_d, bn_q); + goto error; } if (coeff.ptr) { - iqmp = BN_bin2bn((const u_char*)coeff.ptr, coeff.len, NULL); + iqmp = BN_bin2bn((const u_char*)coeff.ptr, coeff.len, iqmp); } - else + else if (!qinv(ctx, bn_q, bn_p, iqmp)) { - iqmp = qinv(bn_q, bn_p); + goto error; } - if (RSA_set0_crt_params(this->rsa, dmp1, dmq1, iqmp) && - RSA_check_key(this->rsa) == 1) + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx; + + bld = OSSL_PARAM_BLD_new(); + if (bld && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_n) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_e) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, bn_d) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, bn_p) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, bn_q) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp)) { - return &this->public; + params = OSSL_PARAM_BLD_to_param(bld); } - } + OSSL_PARAM_BLD_free(bld); + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (!params || !pctx || + EVP_PKEY_fromdata_init(pctx) <= 0 || + EVP_PKEY_fromdata(pctx, &key, EVP_PKEY_KEYPAIR, params) <= 0) + { + key = NULL; + } + EVP_PKEY_CTX_free(pctx); + OSSL_PARAM_free(params); +#else /* OPENSSL_VERSION_NUMBER */ + RSA *rsa = RSA_new(); + if (!RSA_set0_key(rsa, BN_dup(bn_n), BN_dup(bn_e), BN_dup(bn_d)) || + !RSA_set0_factors(rsa, BN_dup(bn_p), BN_dup(bn_q)) || + !RSA_set0_crt_params(rsa, BN_dup(dmp1), BN_dup(dmq1), BN_dup(iqmp)) || + RSA_check_key(rsa) <= 0) + { + RSA_free(rsa); + goto error; + } + key = EVP_PKEY_new(); + if (!EVP_PKEY_assign_RSA(key, rsa)) + { + RSA_free(rsa); + EVP_PKEY_free(key); + key = NULL; + } +#endif /* OPENSSL_VERSION_NUMBER */ + error: - destroy(this); - return NULL; + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (!key) + { + return NULL; + } + this = create_internal(key); + return &this->public; } #endif /* OPENSSL_NO_RSA */ diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index d5c9eed1e..43ebe0362 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -31,6 +31,11 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#endif + #if OPENSSL_VERSION_NUMBER < 0x10100000L OPENSSL_KEY_FALLBACK(RSA, key, n, e, d) #endif @@ -47,9 +52,9 @@ struct private_openssl_rsa_public_key_t { openssl_rsa_public_key_t public; /** - * RSA object from OpenSSL + * RSA key object */ - RSA *rsa; + EVP_PKEY *key; /** * reference counter @@ -57,9 +62,6 @@ struct private_openssl_rsa_public_key_t { refcount_t ref; }; - -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - /** * Verify RSA signature */ @@ -69,8 +71,7 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this, { EVP_PKEY_CTX *pctx = NULL; EVP_MD_CTX *mctx = NULL; - EVP_PKEY *key; - int rsa_size = RSA_size(this->rsa); + int rsa_size = EVP_PKEY_size(this->key); bool valid = FALSE; /* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */ @@ -80,16 +81,11 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this, } mctx = EVP_MD_CTX_create(); - key = EVP_PKEY_new(); - if (!mctx || !key) + if (!mctx) { - goto error; + return FALSE; } - if (!EVP_PKEY_set1_RSA(key, this->rsa)) - { - goto error; - } - if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, key) <= 0) + if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, this->key) <= 0) { goto error; } @@ -110,14 +106,7 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this, valid = (EVP_DigestVerifyFinal(mctx, signature.ptr, signature.len) == 1); error: - if (key) - { - EVP_PKEY_free(key); - } - if (mctx) - { - EVP_MD_CTX_destroy(mctx); - } + EVP_MD_CTX_destroy(mctx); return valid; } @@ -128,7 +117,7 @@ static bool verify_plain_signature(private_openssl_rsa_public_key_t *this, chunk_t data, chunk_t signature) { char *buf; - int len, rsa_size = RSA_size(this->rsa); + size_t rsa_size = EVP_PKEY_size(this->key); bool valid = FALSE; /* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */ @@ -136,14 +125,39 @@ static bool verify_plain_signature(private_openssl_rsa_public_key_t *this, { signature = chunk_skip(signature, signature.len - rsa_size); } +#if defined(OPENSSL_IS_BORINGSSL) && \ + (!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 10) + RSA *rsa = EVP_PKEY_get1_RSA(this->key); + int len; + buf = malloc(rsa_size); - len = RSA_public_decrypt(signature.len, signature.ptr, buf, this->rsa, + len = RSA_public_decrypt(signature.len, signature.ptr, buf, rsa, RSA_PKCS1_PADDING); if (len != -1) { valid = chunk_equals_const(data, chunk_create(buf, len)); } + RSA_free(rsa); +#else + EVP_PKEY_CTX *ctx; + size_t len = rsa_size; + + ctx = EVP_PKEY_CTX_new(this->key, NULL); + if (!ctx || + EVP_PKEY_verify_recover_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) + { + EVP_PKEY_CTX_free(ctx); + return FALSE; + } + buf = malloc(rsa_size); + if (EVP_PKEY_verify_recover(ctx, buf, &len, signature.ptr, signature.len) > 0) + { + valid = chunk_equals_const(data, chunk_create(buf, len)); + } free(buf); + EVP_PKEY_CTX_free(ctx); +#endif return valid; } @@ -180,85 +194,6 @@ static bool verify_emsa_pss_signature(private_openssl_rsa_public_key_t *this, return md && verify_signature(this, md, params, data, signature); } -#else /* OPENSSL_VERSION_NUMBER < 1.0 */ - -/** - * Verification of an EMSA PKCS1 signature described in PKCS#1 - */ -static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this, - int type, chunk_t data, chunk_t signature) -{ - bool valid = FALSE; - int rsa_size = RSA_size(this->rsa); - - /* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */ - if (signature.len > rsa_size) - { - signature = chunk_skip(signature, signature.len - rsa_size); - } - - if (type == NID_undef) - { - char *buf; - int len; - - buf = malloc(rsa_size); - len = RSA_public_decrypt(signature.len, signature.ptr, buf, this->rsa, - RSA_PKCS1_PADDING); - if (len != -1) - { - valid = chunk_equals_const(data, chunk_create(buf, len)); - } - free(buf); - } - else - { - EVP_MD_CTX *ctx; - EVP_PKEY *key; - const EVP_MD *hasher; - - hasher = EVP_get_digestbynid(type); - if (!hasher) - { - return FALSE; - } - - ctx = EVP_MD_CTX_create(); - key = EVP_PKEY_new(); - - if (!ctx || !key) - { - goto error; - } - if (!EVP_PKEY_set1_RSA(key, this->rsa)) - { - goto error; - } - if (!EVP_VerifyInit_ex(ctx, hasher, NULL)) - { - goto error; - } - if (!EVP_VerifyUpdate(ctx, data.ptr, data.len)) - { - goto error; - } - valid = (EVP_VerifyFinal(ctx, signature.ptr, signature.len, key) == 1); - -error: - if (key) - { - EVP_PKEY_free(key); - } - if (ctx) - { - EVP_MD_CTX_destroy(ctx); - } - } - return valid; -} - -#endif /* OPENSSL_VERSION_NUMBER < 1.0 */ - METHOD(public_key_t, get_type, key_type_t, private_openssl_rsa_public_key_t *this) { @@ -295,10 +230,8 @@ METHOD(public_key_t, verify, bool, return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature); case SIGN_RSA_EMSA_PKCS1_MD5: return verify_emsa_pkcs1_signature(this, NID_md5, data, signature); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L case SIGN_RSA_EMSA_PSS: return verify_emsa_pss_signature(this, params, data, signature); -#endif default: DBG1(DBG_LIB, "signature scheme %N not supported in RSA", signature_scheme_names, scheme); @@ -311,7 +244,6 @@ METHOD(public_key_t, encrypt, bool, void *params, chunk_t plain, chunk_t *crypto) { EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *evp_key = NULL; chunk_t label = chunk_empty; hash_algorithm_t hash_alg = HASH_UNKNOWN; size_t len; @@ -350,23 +282,11 @@ METHOD(public_key_t, encrypt, bool, return FALSE; } - evp_key = EVP_PKEY_new(); - if (!evp_key) - { - DBG1(DBG_LIB, "could not create EVP key"); - goto error; - } - if (EVP_PKEY_set1_RSA(evp_key, this->rsa) <= 0) - { - DBG1(DBG_LIB, "could not set EVP key to RSA key"); - goto error; - } - - ctx = EVP_PKEY_CTX_new(evp_key, NULL); + ctx = EVP_PKEY_CTX_new(this->key, NULL); if (!ctx) { DBG1(DBG_LIB, "could not create EVP context"); - goto error; + return FALSE; } if (EVP_PKEY_encrypt_init(ctx) <= 0) @@ -411,7 +331,7 @@ METHOD(public_key_t, encrypt, bool, } /* determine maximum ciphertext size */ - len = RSA_size(this->rsa); + len = EVP_PKEY_size(this->key); encrypted = malloc(len); /* decrypt data */ @@ -425,59 +345,91 @@ METHOD(public_key_t, encrypt, bool, success = TRUE; error: - if (ctx) - { - EVP_PKEY_CTX_free(ctx); - } - if (evp_key) - { - EVP_PKEY_free(evp_key); - } + EVP_PKEY_CTX_free(ctx); return success; } METHOD(public_key_t, get_keysize, int, private_openssl_rsa_public_key_t *this) { - return RSA_size(this->rsa) * 8; + return EVP_PKEY_bits(this->key); +} + +/** + * Get n and e of the given RSA key (allocated). + */ +static bool get_n_and_e(EVP_PKEY *key, chunk_t *n, chunk_t *e) +{ + const BIGNUM *cbn_n, *cbn_e; + BIGNUM *bn_n = NULL, *bn_e = NULL; + bool success = FALSE; + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_N, &bn_n) <= 0 || + EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_E, &bn_e) <= 0) + { + goto error; + } + cbn_n = bn_n; + cbn_e = bn_e; +#elif OPENSSL_VERSION_NUMBER >= 0x1010000fL + RSA *rsa = EVP_PKEY_get0_RSA(key); + RSA_get0_key(rsa, &cbn_n, &cbn_e, NULL); +#else + RSA *rsa = EVP_PKEY_get1_RSA(key); + RSA_get0_key(rsa, &cbn_n, &cbn_e, NULL); + RSA_free(rsa); +#endif + + *n = *e = chunk_empty; + if (!openssl_bn2chunk(cbn_n, n) || + !openssl_bn2chunk(cbn_e, e)) + { + chunk_free(n); + chunk_free(e); + goto error; + } + success = TRUE; + +error: + BN_free(bn_n); + BN_free(bn_e); + return success; } /** * Calculate fingerprint from a RSA key, also used in rsa private key. */ -bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp) +bool openssl_rsa_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp) { hasher_t *hasher; - chunk_t key; + chunk_t enc; u_char *p; - if (lib->encoding->get_cache(lib->encoding, type, rsa, fp)) + if (lib->encoding->get_cache(lib->encoding, type, key, fp)) { return TRUE; } switch (type) { case KEYID_PUBKEY_SHA1: - key = chunk_alloc(i2d_RSAPublicKey(rsa, NULL)); - p = key.ptr; - i2d_RSAPublicKey(rsa, &p); + enc = chunk_alloc(i2d_PublicKey(key, NULL)); + p = enc.ptr; + i2d_PublicKey(key, &p); break; case KEYID_PUBKEY_INFO_SHA1: - key = chunk_alloc(i2d_RSA_PUBKEY(rsa, NULL)); - p = key.ptr; - i2d_RSA_PUBKEY(rsa, &p); + enc = chunk_alloc(i2d_PUBKEY(key, NULL)); + p = enc.ptr; + i2d_PUBKEY(key, &p); break; default: { - const BIGNUM *bn_n, *bn_e; chunk_t n = chunk_empty, e = chunk_empty; bool success = FALSE; - RSA_get0_key(rsa, &bn_n, &bn_e, NULL); - if (openssl_bn2chunk(bn_n, &n) && - openssl_bn2chunk(bn_e, &e)) + if (get_n_and_e(key, &n, &e)) { - success = lib->encoding->encode(lib->encoding, type, rsa, fp, + success = lib->encoding->encode(lib->encoding, type, key, fp, CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END); } @@ -487,16 +439,16 @@ bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp) } } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher || !hasher->allocate_hash(hasher, key, fp)) + if (!hasher || !hasher->allocate_hash(hasher, enc, fp)) { DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); DESTROY_IF(hasher); - free(key.ptr); + free(enc.ptr); return FALSE; } - free(key.ptr); + free(enc.ptr); hasher->destroy(hasher); - lib->encoding->cache(lib->encoding, type, rsa, *fp); + lib->encoding->cache(lib->encoding, type, key, *fp); return TRUE; } @@ -504,7 +456,7 @@ METHOD(public_key_t, get_fingerprint, bool, private_openssl_rsa_public_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint) { - return openssl_rsa_fingerprint(this->rsa, type, fingerprint); + return openssl_rsa_fingerprint(this->key, type, fingerprint); } METHOD(public_key_t, get_encoding, bool, @@ -512,16 +464,13 @@ METHOD(public_key_t, get_encoding, bool, chunk_t *encoding) { bool success = FALSE; - u_char *p; switch (type) { case PUBKEY_SPKI_ASN1_DER: case PUBKEY_PEM: { - *encoding = chunk_alloc(i2d_RSA_PUBKEY(this->rsa, NULL)); - p = encoding->ptr; - i2d_RSA_PUBKEY(this->rsa, &p); + *encoding = openssl_i2chunk(PUBKEY, this->key); success = TRUE; if (type == PUBKEY_PEM) @@ -537,19 +486,14 @@ METHOD(public_key_t, get_encoding, bool, } case PUBKEY_ASN1_DER: { - *encoding = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL)); - p = encoding->ptr; - i2d_RSAPublicKey(this->rsa, &p); + *encoding = openssl_i2chunk(PublicKey, this->key); return TRUE; } default: { - const BIGNUM *bn_n, *bn_e; chunk_t n = chunk_empty, e = chunk_empty; - RSA_get0_key(this->rsa, &bn_n, &bn_e, NULL); - if (openssl_bn2chunk(bn_n, &n) && - openssl_bn2chunk(bn_e, &e)) + if (get_n_and_e(this->key, &n, &e)) { success = lib->encoding->encode(lib->encoding, type, NULL, encoding, CRED_PART_RSA_MODULUS, n, @@ -574,10 +518,10 @@ METHOD(public_key_t, destroy, void, { if (ref_put(&this->ref)) { - if (this->rsa) + if (this->key) { - lib->encoding->clear_cache(lib->encoding, this->rsa); - RSA_free(this->rsa); + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); } free(this); } @@ -586,7 +530,7 @@ METHOD(public_key_t, destroy, void, /** * Generic private constructor */ -static private_openssl_rsa_public_key_t *create_empty() +static private_openssl_rsa_public_key_t *create_internal(EVP_PKEY *key) { private_openssl_rsa_public_key_t *this; @@ -606,6 +550,7 @@ static private_openssl_rsa_public_key_t *create_empty() }, }, .ref = 1, + .key = key, ); return this; @@ -618,6 +563,7 @@ openssl_rsa_public_key_t *openssl_rsa_public_key_load(key_type_t type, va_list args) { private_openssl_rsa_public_key_t *this; + EVP_PKEY *key = NULL; chunk_t blob, n, e; n = e = blob = chunk_empty; @@ -642,41 +588,98 @@ openssl_rsa_public_key_t *openssl_rsa_public_key_load(key_type_t type, break; } - this = create_empty(); if (blob.ptr) { switch (type) { case KEY_ANY: - this->rsa = d2i_RSA_PUBKEY(NULL, (const u_char**)&blob.ptr, - blob.len); + key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len); + if (key && EVP_PKEY_base_id(key) != EVP_PKEY_RSA) + { + EVP_PKEY_free(key); + key = NULL; + } break; case KEY_RSA: - this->rsa = d2i_RSAPublicKey(NULL, (const u_char**)&blob.ptr, - blob.len); +#if defined(OPENSSL_IS_BORINGSSL) && \ + (!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 10) + { + RSA *rsa = d2i_RSAPublicKey(NULL, (const u_char**)&blob.ptr, + blob.len); + key = EVP_PKEY_new(); + if (!key || !EVP_PKEY_assign_RSA(key, rsa)) + { + RSA_free(rsa); + EVP_PKEY_free(key); + key = NULL; + } + } +#else + key = d2i_PublicKey(EVP_PKEY_RSA, NULL, (const u_char**)&blob.ptr, + blob.len); +#endif break; default: break; } - if (this->rsa) - { - return &this->public; - } } else if (n.ptr && e.ptr && type == KEY_RSA) { BIGNUM *bn_n, *bn_e; - this->rsa = RSA_new(); bn_n = BN_bin2bn((const u_char*)n.ptr, n.len, NULL); bn_e = BN_bin2bn((const u_char*)e.ptr, e.len, NULL); - if (RSA_set0_key(this->rsa, bn_n, bn_e, NULL)) + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx; + + bld = OSSL_PARAM_BLD_new(); + if (bld && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_n) && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_e)) { - return &this->public; + params = OSSL_PARAM_BLD_to_param(bld); } + OSSL_PARAM_BLD_free(bld); + BN_free(bn_n); + BN_free(bn_e); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (!params || !ctx || + EVP_PKEY_fromdata_init(ctx) <= 0 || + EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params) <= 0) + { + key = NULL; + } + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); +#else /* OPENSSL_VERSION_NUMBER */ + RSA *rsa = RSA_new(); + + if (RSA_set0_key(rsa, bn_n, bn_e, NULL)) + { + key = EVP_PKEY_new(); + if (!key || !EVP_PKEY_assign_RSA(key, rsa)) + { + RSA_free(rsa); + EVP_PKEY_free(key); + key = NULL; + } + } + else + { + RSA_free(rsa); + } +#endif /* OPENSSL_VERSION_NUMBER */ } - destroy(this); - return NULL; + if (!key) + { + return NULL; + } + this = create_internal(key); + return &this->public; } #endif /* OPENSSL_NO_RSA */ diff --git a/src/libstrongswan/tests/suites/test_rsa.c b/src/libstrongswan/tests/suites/test_rsa.c index 0ab9dc5c9..33a223d57 100644 --- a/src/libstrongswan/tests/suites/test_rsa.c +++ b/src/libstrongswan/tests/suites/test_rsa.c @@ -177,6 +177,7 @@ END_TEST static struct { chunk_t key; chunk_t pkcs8; + chunk_t spki; chunk_t pub; chunk_t fp_pk; chunk_t fp_spki; @@ -252,6 +253,14 @@ static struct { 0x4c,0xa9,0xa2,0x42,0xbe,0xdd,0xdb,0xf7,0xd3,0x28,0x07,0x10,0x88,0x53,0x15,0xb2, 0x4f,0xb5,0x9d,0x47,0x9b,0xd6,0xc8,0xfe,0x5b,0xa2,0xd7,0xe1,0x13,0xca,0x0b,0xce, 0x7a,0xed,0xa2,0x3e,0xd5,0x9b,0xb8,0x8b,0x4f,0x02,0x03,0x01,0x00,0x01), + chunk_from_chars( + 0x30,0x68,0x02,0x61,0x00,0xd1,0x5d,0x98,0x97,0x95,0x98,0x19,0x87,0x20,0x3f,0x10, + 0xb0,0x05,0x36,0x1e,0x1b,0xcd,0xc8,0x93,0x66,0xd7,0x43,0xed,0x84,0xb0,0x3e,0x96, + 0xd3,0xe7,0x27,0x0e,0xc0,0xba,0xdf,0x7e,0x32,0x05,0xd3,0x08,0xd6,0x44,0xd5,0x01, + 0x2b,0x3e,0x5d,0xc0,0x37,0xae,0x4f,0xe0,0xea,0x8d,0x2c,0x42,0x4c,0xa9,0xa2,0x42, + 0xbe,0xdd,0xdb,0xf7,0xd3,0x28,0x07,0x10,0x88,0x53,0x15,0xb2,0x4f,0xb5,0x9d,0x47, + 0x9b,0xd6,0xc8,0xfe,0x5b,0xa2,0xd7,0xe1,0x13,0xca,0x0b,0xce,0x7a,0xed,0xa2,0x3e, + 0xd5,0x9b,0xb8,0x8b,0x4f,0x02,0x03,0x01,0x00,0x01), chunk_from_chars( 0x06,0xad,0x82,0xc3,0x58,0x22,0xbb,0x79,0xb5,0xfc,0x48,0xdb,0xa0,0x3c,0x39,0x60, 0x00,0x85,0x06,0xca), @@ -351,6 +360,16 @@ static struct { 0xb8,0x9d,0x07,0x84,0x03,0x68,0x6b,0x9f,0xbf,0xe5,0xd8,0x14,0x2a,0xe0,0xef,0xbd, 0x1a,0x61,0x0d,0x3a,0xc8,0x67,0xcd,0x99,0x90,0xe3,0xe6,0x52,0x83,0x02,0x03,0x01, 0x00,0x01), + chunk_from_chars( + 0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc0,0xbd,0x48,0x83,0xbc,0xea,0x0b,0x32,0x06, + 0x4b,0xf5,0x10,0x54,0x1b,0xba,0x88,0xc4,0x10,0x7e,0x47,0xec,0x0e,0xf9,0xb4,0xcf, + 0x9a,0x02,0xc6,0xb3,0xaf,0x35,0xc8,0xaf,0x78,0x1a,0xbc,0x37,0x1a,0x25,0x7a,0x37, + 0x24,0x73,0x53,0x9a,0xf0,0x44,0x64,0x5b,0x6b,0x64,0x4c,0xfa,0x83,0x3a,0x0f,0x77, + 0x5d,0x7b,0x21,0xa2,0x25,0x00,0x11,0xae,0x72,0x36,0x35,0xd9,0x0d,0xef,0x5a,0xdd, + 0x98,0x35,0x49,0xaf,0x44,0xa0,0x33,0x29,0xc0,0xca,0xf5,0x6f,0xfe,0xc1,0x06,0x4c, + 0x80,0x9a,0x54,0xbe,0x46,0x1a,0x96,0xb1,0xf3,0x29,0xb8,0x9d,0x07,0x84,0x03,0x68, + 0x6b,0x9f,0xbf,0xe5,0xd8,0x14,0x2a,0xe0,0xef,0xbd,0x1a,0x61,0x0d,0x3a,0xc8,0x67, + 0xcd,0x99,0x90,0xe3,0xe6,0x52,0x83,0x02,0x03,0x01,0x00,0x01), chunk_from_chars( 0xda,0xab,0x50,0x22,0x4b,0x4f,0x3b,0xd0,0x82,0xc4,0xa4,0x14,0x06,0x64,0x0b,0x6f, 0xad,0xbc,0x69,0xc0), @@ -491,6 +510,20 @@ static struct { 0x91,0xe2,0xfc,0x7b,0xea,0xb0,0x89,0x24,0xaa,0x00,0x29,0x8c,0x26,0x7c,0x94,0x54, 0x74,0xe4,0x11,0xa8,0x04,0x6f,0x40,0xeb,0xaf,0xed,0xac,0x75,0x33,0x02,0x03,0x01, 0x00,0x01), + chunk_from_chars( + 0x30,0x81,0xc9,0x02,0x81,0xc1,0x00,0xba,0xe3,0x37,0x93,0x7e,0x42,0x13,0x3c,0xba, + 0x41,0xc1,0x7b,0xf0,0xcc,0x7a,0x44,0xc6,0x54,0xc8,0x77,0x01,0x70,0x2f,0x6e,0x4a, + 0xcf,0x2d,0x07,0xab,0x01,0xc0,0x43,0xab,0x8d,0x33,0xb3,0xd4,0xeb,0xe3,0x90,0xf6, + 0x01,0x03,0x75,0x03,0x1d,0xe8,0x06,0x40,0x15,0xfa,0x96,0x0b,0xd5,0x26,0x64,0xea, + 0x55,0x82,0x16,0x7b,0xd5,0x1e,0xaa,0x08,0xc7,0x30,0x1a,0x59,0xf8,0xd9,0xe3,0x9e, + 0x89,0xd9,0x92,0x2c,0x32,0x79,0x0e,0xb3,0x25,0xbc,0x1d,0x7c,0x59,0xde,0x05,0x47, + 0x8f,0x61,0x77,0xf5,0x4f,0xed,0x82,0x2c,0xf8,0x2a,0x3e,0x02,0xf3,0xc0,0x15,0x51, + 0xde,0x05,0xc4,0xfc,0x80,0x91,0xae,0x06,0x1b,0xd7,0x39,0x8e,0x9a,0x6d,0xb3,0x2f, + 0xb0,0xd0,0xc8,0x96,0xa6,0x88,0xb3,0x17,0xca,0x58,0xbe,0x38,0x2c,0x64,0x35,0x5a, + 0x29,0xb7,0xf8,0x74,0x3d,0xbb,0xec,0x90,0x01,0x04,0x64,0x3d,0x38,0x0f,0x87,0xce, + 0xd7,0xfc,0xd2,0x96,0x93,0x31,0x85,0x0d,0x2d,0xa5,0x91,0xe2,0xfc,0x7b,0xea,0xb0, + 0x89,0x24,0xaa,0x00,0x29,0x8c,0x26,0x7c,0x94,0x54,0x74,0xe4,0x11,0xa8,0x04,0x6f, + 0x40,0xeb,0xaf,0xed,0xac,0x75,0x33,0x02,0x03,0x01,0x00,0x01), chunk_from_chars( 0x21,0x00,0x8c,0xe1,0x78,0x25,0x67,0x19,0xb7,0xd0,0xcb,0x13,0x01,0x7a,0xa3,0x71, 0x67,0x46,0x96,0xf1), @@ -671,6 +704,24 @@ static struct { 0xde,0x54,0x7d,0x95,0xd6,0x4e,0x58,0x12,0x06,0x60,0x22,0x33,0xf2,0x19,0x67,0x65, 0xdd,0xf3,0x42,0xb5,0x00,0x51,0x35,0xe5,0x62,0x4d,0x90,0x44,0xfb,0x7f,0x5b,0xb5, 0xe5,0x02,0x03,0x01,0x00,0x01), + chunk_from_chars( + 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xba,0xbf,0x27,0x0b,0x22,0x59,0xd8, + 0x6f,0xff,0x26,0x5d,0x41,0x3d,0xb0,0x94,0x58,0x5d,0xc0,0x46,0xb6,0x77,0xa9,0x78, + 0x10,0x6d,0xe9,0xbf,0xca,0x6f,0x04,0xe1,0xda,0x85,0x12,0x1e,0xe0,0xa6,0xc7,0xa2, + 0x71,0x04,0x8b,0x6e,0x84,0xf9,0x86,0x2b,0xeb,0x72,0x01,0x72,0xc8,0x0a,0x83,0xa6, + 0xf7,0xc0,0xd6,0x76,0x1d,0x28,0x38,0xb5,0x7e,0x6c,0x8c,0x6a,0x13,0xf4,0xf1,0x7f, + 0xf2,0x79,0xae,0x73,0xba,0x1a,0x3f,0x30,0x65,0xb6,0x23,0xa7,0x94,0x34,0x29,0x87, + 0xce,0x06,0x99,0xee,0x85,0x10,0xce,0x08,0xe2,0x8d,0xd5,0x47,0xf3,0xc8,0xf0,0x18, + 0x41,0xc0,0x59,0x66,0x06,0xda,0xb6,0x18,0xd2,0xa3,0xa0,0xbd,0x3a,0x90,0x7f,0x37, + 0x39,0xdf,0x98,0x55,0xa2,0x19,0x5e,0x37,0xbc,0x86,0xf3,0x02,0xf8,0x68,0x49,0x53, + 0xf2,0x4b,0x3d,0x7a,0xe3,0x1d,0xa4,0x15,0x10,0xa6,0xce,0x8c,0xb8,0xfd,0x95,0x54, + 0xa2,0x50,0xa2,0xd9,0x35,0x12,0x56,0xae,0xbc,0x51,0x33,0x6d,0xb8,0x63,0x7c,0x26, + 0xab,0x19,0x01,0xa5,0xda,0xfa,0x4b,0xb6,0x57,0xd3,0x4b,0xdd,0xc0,0x62,0xc5,0x05, + 0xb7,0xc3,0x2e,0x1f,0x17,0xc8,0x09,0x87,0x12,0x37,0x21,0xd7,0x7a,0x53,0xb0,0x47, + 0x60,0xa2,0xb5,0x23,0x3b,0x99,0xdf,0xea,0x8b,0x94,0xea,0x9d,0x53,0x5d,0x02,0x52, + 0xf7,0x29,0xfb,0x63,0xb0,0xff,0x27,0x5e,0xde,0x54,0x7d,0x95,0xd6,0x4e,0x58,0x12, + 0x06,0x60,0x22,0x33,0xf2,0x19,0x67,0x65,0xdd,0xf3,0x42,0xb5,0x00,0x51,0x35,0xe5, + 0x62,0x4d,0x90,0x44,0xfb,0x7f,0x5b,0xb5,0xe5,0x02,0x03,0x01,0x00,0x01), chunk_from_chars( 0x4f,0xe8,0x82,0xee,0xaa,0x2c,0x7b,0x3f,0x3a,0xf1,0xb4,0xe1,0xe3,0x85,0xd4,0xb1, 0xb4,0x34,0x5c,0x2d), @@ -708,9 +759,17 @@ START_TEST(test_load) pubkey = privkey->get_public_key(privkey); ck_assert(pubkey != NULL); ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding)); - ck_assert_chunk_eq(keys[_i].pub, encoding); + ck_assert_chunk_eq(keys[_i].spki, encoding); chunk_free(&encoding); - + if (!pubkey->get_encoding(pubkey, PUBKEY_ASN1_DER, &encoding)) + { + warn("PUBKEY_ASN1_DER encoding not supported, ignored"); + } + else + { + ck_assert_chunk_eq(keys[_i].pub, encoding); + chunk_free(&encoding); + } ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp)); ck_assert_chunk_eq(keys[_i].fp_pk, fp); ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp)); From 544fb1cf928a11e35bf45b1c9cd6aa0b778b1d8d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Mar 2022 08:21:42 +0100 Subject: [PATCH 07/15] pkcs8: Parse the decrypted PKCS#8 structure via regular builders This allows other plugins to parse such structures directly. The pkcs8 plugin is called recursively again if necessary. --- .../plugins/pkcs8/pkcs8_builder.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c index 1d7a48fb2..9916def19 100644 --- a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c @@ -124,7 +124,8 @@ end: * Try to decrypt the given blob with multiple passwords using the given * pkcs5 object. */ -static private_key_t *decrypt_private_key(pkcs5_t *pkcs5, chunk_t blob) +static private_key_t *decrypt_private_key(key_type_t type, pkcs5_t *pkcs5, + chunk_t blob) { enumerator_t *enumerator; shared_key_t *shared; @@ -140,7 +141,15 @@ static private_key_t *decrypt_private_key(pkcs5_t *pkcs5, chunk_t blob) { continue; } - private_key = parse_private_key(decrypted); + /* do a quick check to validate whether the password was correct */ + if (!is_asn1(decrypted)) + { + chunk_clear(&decrypted); + continue; + } + private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + type, BUILD_BLOB_ASN1_DER, + decrypted, BUILD_END); if (private_key) { chunk_clear(&decrypted); @@ -169,7 +178,7 @@ static const asn1Object_t encryptedPKIObjects[] = { * Load an encrypted private key from an ASN.1 encoded blob * Schemes per PKCS#5 (RFC 2898) */ -static private_key_t *parse_encrypted_private_key(chunk_t blob) +static private_key_t *parse_encrypted_private_key(key_type_t type, chunk_t blob) { asn1_parser_t *parser; chunk_t object; @@ -195,7 +204,7 @@ static private_key_t *parse_encrypted_private_key(chunk_t blob) } case EPKINFO_ENCRYPTED_DATA: { - key = decrypt_private_key(pkcs5, object); + key = decrypt_private_key(type, pkcs5, object); break; } } @@ -230,7 +239,7 @@ private_key_t *pkcs8_private_key_load(key_type_t type, va_list args) break; } /* we don't know whether it is encrypted or not, try both ways */ - key = parse_encrypted_private_key(blob); + key = parse_encrypted_private_key(type, blob); if (!key) { key = parse_private_key(blob); From be0ce6db93a7d4cc2d4392a83365a54f4cfe1d8c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 14 Apr 2022 11:57:30 +0200 Subject: [PATCH 08/15] configure: Move pkcs8 plugin after plugins that can parse PKCS#8 directly With such plugins we only need the pkcs8 plugin to load encrypted files. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 04a1c5ce3..de77dc373 100644 --- a/configure.ac +++ b/configure.ac @@ -1480,7 +1480,6 @@ ADD_PLUGIN([acert], [s charon]) ADD_PLUGIN([pubkey], [s charon pki cmd aikgen]) ADD_PLUGIN([pkcs1], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz]) ADD_PLUGIN([pkcs7], [s charon scepclient pki scripts nm cmd]) -ADD_PLUGIN([pkcs8], [s charon scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts cmd]) ADD_PLUGIN([pgp], [s charon]) ADD_PLUGIN([dnskey], [s charon pki]) @@ -1493,6 +1492,7 @@ ADD_PLUGIN([openssl], [s charon scepclient pki scripts manager meds ADD_PLUGIN([wolfssl], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen]) ADD_PLUGIN([gcrypt], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen]) ADD_PLUGIN([botan], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen]) +ADD_PLUGIN([pkcs8], [s charon scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([af-alg], [s charon scepclient pki scripts medsrv attest nm cmd aikgen]) ADD_PLUGIN([fips-prf], [s charon nm cmd]) ADD_PLUGIN([gmp], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz]) From 293a912c7de67bbd2720c77c0a9320aade54b2b0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 3 Mar 2022 14:19:03 +0100 Subject: [PATCH 09/15] openssl: Fixes for ECDSA with OpenSSL 3.0 --- .../plugins/openssl/openssl_ec_private_key.c | 263 +++++++++------- .../plugins/openssl/openssl_ec_public_key.c | 282 +++++++++--------- .../plugins/openssl/openssl_rsa_public_key.c | 50 +--- .../plugins/openssl/openssl_util.c | 42 +++ .../plugins/openssl/openssl_util.h | 10 + 5 files changed, 347 insertions(+), 300 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c index 0c208be7e..54c20dcb9 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c @@ -46,7 +46,7 @@ struct private_openssl_ec_private_key_t { /** * EC key object */ - EC_KEY *ec; + EVP_PKEY *key; /** * TRUE if the key is from an OpenSSL ENGINE and might not be readable @@ -59,25 +59,78 @@ struct private_openssl_ec_private_key_t { refcount_t ref; }; -/* from ec public key */ -bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp); +/* from openssl_ec_public_key */ +bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve); + +/** + * Build a DER encoded signature as in RFC 3279 + */ +static bool build_der_signature(private_openssl_ec_private_key_t *this, + int nid_hash, chunk_t data, chunk_t *signature) +{ + EVP_MD_CTX *ctx; + const EVP_MD *md; + + md = EVP_get_digestbynid(nid_hash); + if (!md) + { + return FALSE; + } + *signature = chunk_alloc(EVP_PKEY_size(this->key)); + ctx = EVP_MD_CTX_create(); + if (!ctx || + EVP_DigestSignInit(ctx, NULL, md, NULL, this->key) <= 0 || + EVP_DigestSignUpdate(ctx, data.ptr, data.len) <= 0 || + EVP_DigestSignFinal(ctx, signature->ptr, &signature->len) != 1) + { + chunk_free(signature); + EVP_MD_CTX_destroy(ctx); + return FALSE; + } + EVP_MD_CTX_destroy(ctx); + return TRUE; +} /** * Build a signature as in RFC 4754 */ static bool build_signature(private_openssl_ec_private_key_t *this, - chunk_t hash, chunk_t *signature) + int nid_hash, chunk_t data, chunk_t *signature) { - const BIGNUM *r, *s; + EVP_PKEY_CTX *ctx; ECDSA_SIG *sig; + const BIGNUM *r, *s; + const u_char *p; + chunk_t der_sig; bool built = FALSE; - sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec); + if (!nid_hash) + { /* EVP_DigestSign*() has issues with NULL EVP_MD */ + der_sig = chunk_alloc(EVP_PKEY_size(this->key)); + ctx = EVP_PKEY_CTX_new(this->key, NULL); + if (!ctx || + EVP_PKEY_sign_init(ctx) <= 0 || + EVP_PKEY_sign(ctx, der_sig.ptr, &der_sig.len, data.ptr, data.len) <= 0) + { + chunk_free(&der_sig); + EVP_PKEY_CTX_free(ctx); + return FALSE; + } + EVP_PKEY_CTX_free(ctx); + } + else if (!build_der_signature(this, nid_hash, data, &der_sig)) + { + return FALSE; + } + /* extract r and s from the DER-encoded signature */ + p = der_sig.ptr; + sig = d2i_ECDSA_SIG(NULL, &p, der_sig.len); + chunk_free(&der_sig); if (sig) { ECDSA_SIG_get0(sig, &r, &s); /* concatenate BNs r/s to a signature chunk */ - built = openssl_bn_cat(EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec)), + built = openssl_bn_cat((EVP_PKEY_bits(this->key) + 7) / 8, r, s, signature); ECDSA_SIG_free(sig); } @@ -91,62 +144,13 @@ static bool build_curve_signature(private_openssl_ec_private_key_t *this, signature_scheme_t scheme, int nid_hash, int nid_curve, chunk_t data, chunk_t *signature) { - const EC_GROUP *my_group; - EC_GROUP *req_group; - chunk_t hash; - bool built; - - req_group = EC_GROUP_new_by_curve_name(nid_curve); - if (!req_group) + if (!openssl_check_ec_key_curve(this->key, nid_curve)) { - DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve " - "not supported)", signature_scheme_names, scheme); - return FALSE; - } - my_group = EC_KEY_get0_group(this->ec); - if (EC_GROUP_cmp(my_group, req_group, NULL) != 0) - { - DBG1(DBG_LIB, "signature scheme %N not supported by private key", + DBG1(DBG_LIB, "signature scheme %N not supported by key", signature_scheme_names, scheme); return FALSE; } - EC_GROUP_free(req_group); - if (!openssl_hash_chunk(nid_hash, data, &hash)) - { - return FALSE; - } - built = build_signature(this, hash, signature); - chunk_free(&hash); - return built; -} - -/** - * Build a DER encoded signature as in RFC 3279 - */ -static bool build_der_signature(private_openssl_ec_private_key_t *this, - int hash_nid, chunk_t data, chunk_t *signature) -{ - chunk_t hash, sig; - int siglen = 0; - bool built; - - if (!openssl_hash_chunk(hash_nid, data, &hash)) - { - return FALSE; - } - sig = chunk_alloc(ECDSA_size(this->ec)); - built = ECDSA_sign(0, hash.ptr, hash.len, sig.ptr, &siglen, this->ec) == 1; - sig.len = siglen; - if (built) - { - *signature = sig; - } - else - { - free(sig.ptr); - } - free(hash.ptr); - return built; + return build_signature(this, nid_hash, data, signature); } METHOD(private_key_t, sign, bool, @@ -156,7 +160,7 @@ METHOD(private_key_t, sign, bool, switch (scheme) { case SIGN_ECDSA_WITH_NULL: - return build_signature(this, data, signature); + return build_signature(this, 0, data, signature); case SIGN_ECDSA_WITH_SHA1_DER: return build_der_signature(this, NID_sha1, data, signature); case SIGN_ECDSA_WITH_SHA256_DER: @@ -192,7 +196,7 @@ METHOD(private_key_t, decrypt, bool, METHOD(private_key_t, get_keysize, int, private_openssl_ec_private_key_t *this) { - return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec)); + return EVP_PKEY_bits(this->key); } METHOD(private_key_t, get_type, key_type_t, @@ -206,12 +210,8 @@ METHOD(private_key_t, get_public_key, public_key_t*, { public_key_t *public; chunk_t key; - u_char *p; - - key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); - p = key.ptr; - i2d_EC_PUBKEY(this->ec, &p); + key = openssl_i2chunk(PUBKEY, this->key); public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER, key, BUILD_END); free(key.ptr); @@ -222,20 +222,17 @@ METHOD(private_key_t, get_fingerprint, bool, private_openssl_ec_private_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint) { - return openssl_ec_fingerprint(this->ec, type, fingerprint); + return openssl_fingerprint(this->key, type, fingerprint); } METHOD(private_key_t, get_encoding, bool, private_openssl_ec_private_key_t *this, cred_encoding_type_t type, chunk_t *encoding) { - u_char *p; - if (this->engine) { return FALSE; } - switch (type) { case PRIVKEY_ASN1_DER: @@ -243,9 +240,7 @@ METHOD(private_key_t, get_encoding, bool, { bool success = TRUE; - *encoding = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL)); - p = encoding->ptr; - i2d_ECPrivateKey(this->ec, &p); + *encoding = openssl_i2chunk(PrivateKey, this->key); if (type == PRIVKEY_PEM) { @@ -275,10 +270,10 @@ METHOD(private_key_t, destroy, void, { if (ref_put(&this->ref)) { - if (this->ec) + if (this->key) { - lib->encoding->clear_cache(lib->encoding, this->ec); - EC_KEY_free(this->ec); + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); } free(this); } @@ -287,7 +282,7 @@ METHOD(private_key_t, destroy, void, /** * Internal generic constructor */ -static private_openssl_ec_private_key_t *create_empty(void) +static private_openssl_ec_private_key_t *create_internal(EVP_PKEY *key) { private_openssl_ec_private_key_t *this; @@ -309,6 +304,7 @@ static private_openssl_ec_private_key_t *create_empty(void) }, }, .ref = 1, + .key = key, ); return this; @@ -320,16 +316,13 @@ static private_openssl_ec_private_key_t *create_empty(void) private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine) { private_openssl_ec_private_key_t *this; - EC_KEY *ec; - ec = EVP_PKEY_get1_EC_KEY(key); - EVP_PKEY_free(key); - if (!ec) + if (EVP_PKEY_base_id(key) != EVP_PKEY_EC) { + EVP_PKEY_free(key); return NULL; } - this = create_empty(); - this->ec = ec; + this = create_internal(key); this->engine = engine; return &this->public.key; } @@ -341,6 +334,7 @@ openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type, va_list args) { private_openssl_ec_private_key_t *this; + EVP_PKEY *key = NULL; u_int key_size = 0; while (TRUE) @@ -361,32 +355,58 @@ openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type, { return NULL; } - this = create_empty(); + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L switch (key_size) { case 256: - this->ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + key = EVP_EC_gen("P-256"); break; case 384: - this->ec = EC_KEY_new_by_curve_name(NID_secp384r1); + key = EVP_EC_gen("P-384"); break; case 521: - this->ec = EC_KEY_new_by_curve_name(NID_secp521r1); + key = EVP_EC_gen("P-521"); break; default: DBG1(DBG_LIB, "EC private key size %d not supported", key_size); - destroy(this); return NULL; } - if (EC_KEY_generate_key(this->ec) != 1) +#else /* OPENSSL_VERSION_NUMBER */ + EC_KEY *ec; + + switch (key_size) + { + case 256: + ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + break; + case 384: + ec = EC_KEY_new_by_curve_name(NID_secp384r1); + break; + case 521: + ec = EC_KEY_new_by_curve_name(NID_secp521r1); + break; + default: + DBG1(DBG_LIB, "EC private key size %d not supported", key_size); + return NULL; + } + if (ec && EC_KEY_generate_key(ec) == 1) + { + key = EVP_PKEY_new(); + if (!EVP_PKEY_assign_EC_KEY(key, ec)) + { + EC_KEY_free(ec); + EVP_PKEY_free(key); + key = NULL; + } + } +#endif /* OPENSSL_VERSION_NUMBER */ + + if (!key) { - DBG1(DBG_LIB, "EC private key generation failed", key_size); - destroy(this); return NULL; } - /* encode as a named curve key (no parameters), uncompressed public key */ - EC_KEY_set_asn1_flag(this->ec, OPENSSL_EC_NAMED_CURVE); - EC_KEY_set_conv_form(this->ec, POINT_CONVERSION_UNCOMPRESSED); + this = create_internal(key); return &this->public; } @@ -397,7 +417,8 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, va_list args) { private_openssl_ec_private_key_t *this; - chunk_t par = chunk_empty, key = chunk_empty; + chunk_t par = chunk_empty, blob = chunk_empty; + EVP_PKEY *key = NULL; while (TRUE) { @@ -407,7 +428,7 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, par = va_arg(args, chunk_t); continue; case BUILD_BLOB_ASN1_DER: - key = va_arg(args, chunk_t); + blob = va_arg(args, chunk_t); continue; case BUILD_END: break; @@ -417,36 +438,46 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, break; } - this = create_empty(); - if (par.ptr) { - this->ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len); - if (!this->ec) + /* for OpenSSL 3, the combination of d2i_KeyParams/d2i_PrivateKey, which + * are intended to replace the functions below, does currently not work + * because OpenSSL does not pass the internal EC_KEY that stores the + * parameters from the first call to the call that parses the private + * key. however, since parsing PKCS#8 is the only use case for this and + * OpenSSL 3 parses this format directly, there isn't really any need + * for it anyway */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L + EC_KEY *ec; + + ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len); + if (ec && d2i_ECPrivateKey(&ec, (const u_char**)&blob.ptr, blob.len)) { - goto error; + key = EVP_PKEY_new(); + if (!EVP_PKEY_assign_EC_KEY(key, ec)) + { + EC_KEY_free(ec); + EVP_PKEY_free(key); + key = NULL; + } } - if (!d2i_ECPrivateKey(&this->ec, (const u_char**)&key.ptr, key.len)) + else { - goto error; + EC_KEY_free(ec); } +#endif } else { - this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&key.ptr, key.len); - if (!this->ec) - { - goto error; - } + key = d2i_PrivateKey(EVP_PKEY_EC, NULL, (const u_char**)&blob.ptr, + blob.len); } - if (!EC_KEY_check_key(this->ec)) - { - goto error; - } - return &this->public; -error: - destroy(this); - return NULL; + if (!key) + { + return NULL; + } + this = create_internal(key); + return &this->public; } #endif /* OPENSSL_NO_ECDSA */ diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c index 79ab82db5..7b529719b 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c @@ -27,6 +27,10 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif + #if OPENSSL_VERSION_NUMBER < 0x10100000L OPENSSL_KEY_FALLBACK(ECDSA_SIG, r, s) #endif @@ -45,7 +49,7 @@ struct private_openssl_ec_public_key_t { /** * EC key object */ - EC_KEY *ec; + EVP_PKEY *key; /** * reference counter @@ -53,14 +57,48 @@ struct private_openssl_ec_public_key_t { refcount_t ref; }; +/** + * Verification of a DER encoded signature as in RFC 3279 + */ +static bool verify_der_signature(private_openssl_ec_public_key_t *this, + int nid_hash, chunk_t data, chunk_t signature) +{ + EVP_MD_CTX *ctx; + const EVP_MD *md; + + /* remove any preceding 0-bytes from signature */ + while (signature.len && signature.ptr[0] == 0x00) + { + signature = chunk_skip(signature, 1); + } + md = EVP_get_digestbynid(nid_hash); + if (!md) + { + return FALSE; + } + ctx = EVP_MD_CTX_create(); + if (!ctx || + EVP_DigestVerifyInit(ctx, NULL, md, NULL, this->key) <= 0 || + EVP_DigestVerifyUpdate(ctx, data.ptr, data.len) <= 0 || + EVP_DigestVerifyFinal(ctx, signature.ptr, signature.len) != 1) + { + EVP_MD_CTX_destroy(ctx); + return FALSE; + } + EVP_MD_CTX_destroy(ctx); + return TRUE; +} + /** * Verification of a signature as in RFC 4754 */ static bool verify_signature(private_openssl_ec_public_key_t *this, - chunk_t hash, chunk_t signature) + int nid_hash, chunk_t data, chunk_t signature) { + EVP_PKEY_CTX *ctx; BIGNUM *r, *s; ECDSA_SIG *sig; + chunk_t der_sig; bool valid = FALSE; sig = ECDSA_SIG_new(); @@ -77,13 +115,73 @@ static bool verify_signature(private_openssl_ec_public_key_t *this, } if (ECDSA_SIG_set0(sig, r, s)) { - valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1); + der_sig = openssl_i2chunk(ECDSA_SIG, sig); + if (!nid_hash) + { /* EVP_DigestVerify*() has issues with NULL EVP_MD */ + ctx = EVP_PKEY_CTX_new(this->key, NULL); + valid = ctx && EVP_PKEY_verify_init(ctx) > 0 && + EVP_PKEY_verify(ctx, der_sig.ptr, der_sig.len, + data.ptr, data.len) > 0; + EVP_PKEY_CTX_free(ctx); + } + else + { + valid = verify_der_signature(this, nid_hash, data, der_sig); + } + chunk_free(&der_sig); } ECDSA_SIG_free(sig); } return valid; } +/** + * Check that the given key's curve matches a specific one. Also used by + * private key. + */ +bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve) +{ + EC_GROUP *req_group, *my_group = NULL; + bool matches = FALSE; + + req_group = EC_GROUP_new_by_curve_name(nid_curve); + if (!req_group) + { + goto error; + } + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + char name[BUF_LEN]; + OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, name, sizeof(name)), + OSSL_PARAM_END, + }; + + if (!EVP_PKEY_get_group_name(key, name, sizeof(name), NULL)) + { + goto error; + } + my_group = EC_GROUP_new_from_params(params, NULL, NULL); +#elif OPENSSL_VERSION_NUMBER >= 0x1010000fL + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(key); + my_group = EC_GROUP_dup(EC_KEY_get0_group(ec)); +#else + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); + my_group = EC_GROUP_dup(EC_KEY_get0_group(ec)); + EC_KEY_free(ec); +#endif + + if (EC_GROUP_cmp(my_group, req_group, NULL) == 0) + { + matches = TRUE; + } + +error: + EC_GROUP_free(my_group); + EC_GROUP_free(req_group); + return matches; +} + /** * Verify a RFC 4754 signature for a specified curve and hash algorithm */ @@ -91,56 +189,13 @@ static bool verify_curve_signature(private_openssl_ec_public_key_t *this, signature_scheme_t scheme, int nid_hash, int nid_curve, chunk_t data, chunk_t signature) { - const EC_GROUP *my_group; - EC_GROUP *req_group; - chunk_t hash; - bool valid; - - req_group = EC_GROUP_new_by_curve_name(nid_curve); - if (!req_group) + if (!openssl_check_ec_key_curve(this->key, nid_curve)) { - DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve " - "not supported)", signature_scheme_names, scheme); - return FALSE; - } - my_group = EC_KEY_get0_group(this->ec); - if (EC_GROUP_cmp(my_group, req_group, NULL) != 0) - { - DBG1(DBG_LIB, "signature scheme %N not supported by private key", + DBG1(DBG_LIB, "signature scheme %N not supported by key", signature_scheme_names, scheme); return FALSE; } - EC_GROUP_free(req_group); - if (!openssl_hash_chunk(nid_hash, data, &hash)) - { - return FALSE; - } - valid = verify_signature(this, hash, signature); - chunk_free(&hash); - return valid; -} - -/** - * Verification of a DER encoded signature as in RFC 3279 - */ -static bool verify_der_signature(private_openssl_ec_public_key_t *this, - int nid_hash, chunk_t data, chunk_t signature) -{ - chunk_t hash; - bool valid = FALSE; - - /* remove any preceding 0-bytes from signature */ - while (signature.len && signature.ptr[0] == 0x00) - { - signature = chunk_skip(signature, 1); - } - if (openssl_hash_chunk(nid_hash, data, &hash)) - { - valid = ECDSA_verify(0, hash.ptr, hash.len, - signature.ptr, signature.len, this->ec) == 1; - free(hash.ptr); - } - return valid; + return verify_signature(this, nid_hash, data, signature); } METHOD(public_key_t, get_type, key_type_t, @@ -164,7 +219,7 @@ METHOD(public_key_t, verify, bool, case SIGN_ECDSA_WITH_SHA512_DER: return verify_der_signature(this, NID_sha512, data, signature); case SIGN_ECDSA_WITH_NULL: - return verify_signature(this, data, signature); + return verify_signature(this, 0, data, signature); case SIGN_ECDSA_256: return verify_curve_signature(this, scheme, NID_sha256, NID_X9_62_prime256v1, data, signature); @@ -192,56 +247,14 @@ METHOD(public_key_t, encrypt, bool, METHOD(public_key_t, get_keysize, int, private_openssl_ec_public_key_t *this) { - return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec)); -} - -/** - * Calculate fingerprint from a EC_KEY, also used in ec private key. - */ -bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp) -{ - hasher_t *hasher; - chunk_t key; - u_char *p; - - if (lib->encoding->get_cache(lib->encoding, type, ec, fp)) - { - return TRUE; - } - switch (type) - { - case KEYID_PUBKEY_SHA1: - key = chunk_alloc(i2o_ECPublicKey(ec, NULL)); - p = key.ptr; - i2o_ECPublicKey(ec, &p); - break; - case KEYID_PUBKEY_INFO_SHA1: - key = chunk_alloc(i2d_EC_PUBKEY(ec, NULL)); - p = key.ptr; - i2d_EC_PUBKEY(ec, &p); - break; - default: - return FALSE; - } - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher || !hasher->allocate_hash(hasher, key, fp)) - { - DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); - DESTROY_IF(hasher); - free(key.ptr); - return FALSE; - } - hasher->destroy(hasher); - free(key.ptr); - lib->encoding->cache(lib->encoding, type, ec, *fp); - return TRUE; + return EVP_PKEY_bits(this->key); } METHOD(public_key_t, get_fingerprint, bool, private_openssl_ec_public_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint) { - return openssl_ec_fingerprint(this->ec, type, fingerprint); + return openssl_fingerprint(this->key, type, fingerprint); } METHOD(public_key_t, get_encoding, bool, @@ -249,11 +262,8 @@ METHOD(public_key_t, get_encoding, bool, chunk_t *encoding) { bool success = TRUE; - u_char *p; - *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); - p = encoding->ptr; - i2d_EC_PUBKEY(this->ec, &p); + *encoding = openssl_i2chunk(PUBKEY, this->key); if (type != PUBKEY_SPKI_ASN1_DER) { @@ -279,21 +289,45 @@ METHOD(public_key_t, destroy, void, { if (ref_put(&this->ref)) { - if (this->ec) + if (this->key) { - lib->encoding->clear_cache(lib->encoding, this->ec); - EC_KEY_free(this->ec); + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); } free(this); } } /** - * Generic private constructor + * See header. */ -static private_openssl_ec_public_key_t *create_empty() +openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type, + va_list args) { private_openssl_ec_public_key_t *this; + chunk_t blob = chunk_empty; + EVP_PKEY *key; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len); + if (!key || EVP_PKEY_base_id(key) != EVP_PKEY_EC) + { + EVP_PKEY_free(key); + return NULL; + } INIT(this, .public = { @@ -311,47 +345,9 @@ static private_openssl_ec_public_key_t *create_empty() }, }, .ref = 1, + .key = key, ); - - return this; -} - -/** - * See header. - */ -openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type, - va_list args) -{ - private_openssl_ec_public_key_t *this; - chunk_t blob = chunk_empty; - - if (type != KEY_ECDSA) - { - return NULL; - } - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - this = create_empty(); - this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len); - if (!this->ec) - { - destroy(this); - return NULL; - } return &this->public; } -#endif /* OPENSSL_NO_ECDSA */ +#endif /* OPENSSL_NO_ECDSA */ diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 43ebe0362..c5a1eb725 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -402,53 +402,21 @@ error: */ bool openssl_rsa_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp) { - hasher_t *hasher; - chunk_t enc; - u_char *p; + if (!openssl_fingerprint(key, type, fp)) + { + chunk_t n = chunk_empty, e = chunk_empty; + bool success = FALSE; - if (lib->encoding->get_cache(lib->encoding, type, key, fp)) - { - return TRUE; - } - switch (type) - { - case KEYID_PUBKEY_SHA1: - enc = chunk_alloc(i2d_PublicKey(key, NULL)); - p = enc.ptr; - i2d_PublicKey(key, &p); - break; - case KEYID_PUBKEY_INFO_SHA1: - enc = chunk_alloc(i2d_PUBKEY(key, NULL)); - p = enc.ptr; - i2d_PUBKEY(key, &p); - break; - default: + if (get_n_and_e(key, &n, &e)) { - chunk_t n = chunk_empty, e = chunk_empty; - bool success = FALSE; - - if (get_n_and_e(key, &n, &e)) - { - success = lib->encoding->encode(lib->encoding, type, key, fp, + success = lib->encoding->encode(lib->encoding, type, key, fp, CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END); - } - chunk_free(&n); - chunk_free(&e); - return success; } + chunk_free(&n); + chunk_free(&e); + return success; } - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher || !hasher->allocate_hash(hasher, enc, fp)) - { - DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); - DESTROY_IF(hasher); - free(enc.ptr); - return FALSE; - } - free(enc.ptr); - hasher->destroy(hasher); - lib->encoding->cache(lib->encoding, type, key, *fp); return TRUE; } diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c index f01ac797e..fce8d29a2 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.c +++ b/src/libstrongswan/plugins/openssl/openssl_util.c @@ -86,6 +86,48 @@ error: return success; } +/* + * Described in header + */ +bool openssl_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp) +{ + hasher_t *hasher; + chunk_t enc; + u_char *p; + + if (lib->encoding->get_cache(lib->encoding, type, key, fp)) + { + return TRUE; + } + switch (type) + { + case KEYID_PUBKEY_SHA1: + enc = chunk_alloc(i2d_PublicKey(key, NULL)); + p = enc.ptr; + i2d_PublicKey(key, &p); + break; + case KEYID_PUBKEY_INFO_SHA1: + enc = chunk_alloc(i2d_PUBKEY(key, NULL)); + p = enc.ptr; + i2d_PUBKEY(key, &p); + break; + default: + return FALSE; + } + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher || !hasher->allocate_hash(hasher, enc, fp)) + { + DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed"); + DESTROY_IF(hasher); + free(enc.ptr); + return FALSE; + } + free(enc.ptr); + hasher->destroy(hasher); + lib->encoding->cache(lib->encoding, type, key, *fp); + return TRUE; +} + /** * Described in header. */ diff --git a/src/libstrongswan/plugins/openssl/openssl_util.h b/src/libstrongswan/plugins/openssl/openssl_util.h index 0b5562c4e..150eebe20 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.h +++ b/src/libstrongswan/plugins/openssl/openssl_util.h @@ -46,6 +46,16 @@ */ bool openssl_compute_shared_key(EVP_PKEY *priv, EVP_PKEY *pub, chunk_t *shared); +/** + * Calculate a fingerprint from the given key (cached under it). + * + * @param key key object + * @param type encoding type + * @param fp allocated fingerprint + * @return TRUE on success, FALSE otherwise + */ +bool openssl_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp); + /** * Creates a hash of a given type of a chunk of data. * From db0c53c20788e7375d755501b93aae382f3337cc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Mar 2022 10:49:04 +0100 Subject: [PATCH 10/15] openssl: Fixes for HMAC with OpenSSL 3.0 --- .../plugins/openssl/openssl_hmac.c | 124 +++++++++++++----- 1 file changed, 91 insertions(+), 33 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_hmac.c b/src/libstrongswan/plugins/openssl/openssl_hmac.c index d186134e2..e4fe7fa76 100644 --- a/src/libstrongswan/plugins/openssl/openssl_hmac.c +++ b/src/libstrongswan/plugins/openssl/openssl_hmac.c @@ -42,6 +42,10 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif + #include "openssl_hmac.h" #include @@ -60,6 +64,19 @@ struct private_mac_t { */ mac_t public; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + /** + * HMAC context + */ + EVP_MAC_CTX *hmac; + + /** + * Base context because EVP_MAC_init() does not reset the internal state if + * no key is passed, so the above is a copy that's replaced with every + * reset that does not change the key + */ + EVP_MAC_CTX *hmac_base; +#else /** * Hasher to use */ @@ -69,6 +86,7 @@ struct private_mac_t { * Current HMAC context */ HMAC_CTX *hmac; +#endif #if OPENSSL_VERSION_NUMBER < 0x10100000L /** @@ -84,16 +102,20 @@ struct private_mac_t { */ static bool reset(private_mac_t *this, chunk_t key) { -#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!key.len || EVP_MAC_init(this->hmac_base, key.ptr, key.len, NULL)) + { + EVP_MAC_CTX_free(this->hmac); + this->hmac = EVP_MAC_CTX_dup(this->hmac_base); + return TRUE; + } +#else if (HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL)) { return TRUE; } - return FALSE; -#else /* OPENSSL_VERSION_NUMBER < 1.0 */ - HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL); - return TRUE; #endif + return FALSE; } METHOD(mac_t, set_key, bool, @@ -104,46 +126,62 @@ METHOD(mac_t, set_key, bool, * use a lengthy string in case there is a limit in FIPS-mode */ key = chunk_from_str("00000000000000000000000000000000"); } - return reset(this, key); -} - -METHOD(mac_t, get_mac, bool, - private_mac_t *this, chunk_t data, uint8_t *out) -{ -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - if (!HMAC_Update(this->hmac, data.ptr, data.len)) + if (!reset(this, key)) { return FALSE; } - if (out == NULL) - { - return TRUE; - } - if (!HMAC_Final(this->hmac, out, NULL)) - { - return FALSE; - } -#else /* OPENSSL_VERSION_NUMBER < 1.0 */ - HMAC_Update(this->hmac, data.ptr, data.len); - if (out == NULL) - { - return TRUE; - } - HMAC_Final(this->hmac, out, NULL); -#endif - return reset(this, chunk_empty); + return TRUE; } METHOD(mac_t, get_mac_size, size_t, private_mac_t *this) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_MAC_CTX_get_mac_size(this->hmac); +#else return EVP_MD_size(this->hasher); +#endif +} + +METHOD(mac_t, get_mac, bool, + private_mac_t *this, chunk_t data, uint8_t *out) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!EVP_MAC_update(this->hmac, data.ptr, data.len)) + { + return FALSE; + } +#else + if (!HMAC_Update(this->hmac, data.ptr, data.len)) + { + return FALSE; + } +#endif + if (!out) + { + return TRUE; + } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!EVP_MAC_final(this->hmac, out, NULL, get_mac_size(this))) + { + return FALSE; + } +#else + if (!HMAC_Final(this->hmac, out, NULL)) + { + return FALSE; + } +#endif + return reset(this, chunk_empty); } METHOD(mac_t, destroy, void, private_mac_t *this) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_CTX_free(this->hmac_base); + EVP_MAC_CTX_free(this->hmac); +#elif OPENSSL_VERSION_NUMBER >= 0x10100000L HMAC_CTX_free(this->hmac); #else HMAC_CTX_cleanup(&this->hmac_ctx); @@ -172,21 +210,41 @@ static mac_t *hmac_create(hash_algorithm_t algo) .set_key = _set_key, .destroy = _destroy, }, - .hasher = EVP_get_digestbyname(name), ); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, name, 0), + OSSL_PARAM_END, + }; + EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + + if (!mac) + { + free(this); + return NULL; + } + this->hmac_base = EVP_MAC_CTX_new(mac); + EVP_MAC_free(mac); + if (!this->hmac_base || !EVP_MAC_CTX_set_params(this->hmac_base, params)) + { + free(this); + return NULL; + } +#else /* OPENSSL_VERSION_NUMBER */ + this->hasher = EVP_get_digestbyname(name); if (!this->hasher) { free(this); return NULL; } - #if OPENSSL_VERSION_NUMBER >= 0x10100000L this->hmac = HMAC_CTX_new(); #else HMAC_CTX_init(&this->hmac_ctx); this->hmac = &this->hmac_ctx; #endif +#endif /* OPENSSL_VERSION_NUMBER */ /* make sure the underlying hash algorithm is supported */ if (!set_key(this, chunk_empty)) From f26639de2caecebe7afeefaedd270ba4504d2f1a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Mar 2022 10:57:20 +0100 Subject: [PATCH 11/15] openssl: Remove checks and legacy compatibility code for OpenSSL < 1.0.2 More of this code was already removed with previous commits. While versions < 1.1.1 are not officially supported anymore, 1.0.2 might still be in use because before 3.x that was the latest version with official FIPS support (OpenSSL apparently also provides extended commercial support for it). --- .../plugins/openssl/openssl_aead.c | 4 --- .../plugins/openssl/openssl_plugin.c | 28 +++---------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_aead.c b/src/libstrongswan/plugins/openssl/openssl_aead.c index 9262cfb23..4d1aa7cd4 100644 --- a/src/libstrongswan/plugins/openssl/openssl_aead.c +++ b/src/libstrongswan/plugins/openssl/openssl_aead.c @@ -15,8 +15,6 @@ #include -#if OPENSSL_VERSION_NUMBER >= 0x1000100fL - #include "openssl_aead.h" #include @@ -363,5 +361,3 @@ aead_t *openssl_aead_create(encryption_algorithm_t algo, return &this->public; } - -#endif /* OPENSSL_VERSION_NUMBER */ diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index 7ea53b858..3446dd0d4 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -160,42 +160,27 @@ static thread_value_t *cleanup; */ static void cleanup_thread(void *arg) { -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL CRYPTO_THREADID tid; CRYPTO_THREADID_set_numeric(&tid, (u_long)(uintptr_t)arg); ERR_remove_thread_state(&tid); -#else - ERR_remove_state((u_long)(uintptr_t)arg); -#endif } /** - * Thread-ID callback function + * Callback for thread ID */ -static u_long id_function(void) +static void threadid_function(CRYPTO_THREADID *threadid) { u_long id; /* ensure the thread ID is never zero, otherwise OpenSSL might try to * acquire locks recursively */ id = 1 + (u_long)thread_current_id(); - /* cleanup a thread's state later if OpenSSL interacted with it */ cleanup->set(cleanup, (void*)(uintptr_t)id); - return id; + CRYPTO_THREADID_set_numeric(threadid, id); } -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL -/** - * Callback for thread ID - */ -static void threadid_function(CRYPTO_THREADID *threadid) -{ - CRYPTO_THREADID_set_numeric(threadid, id_function()); -} -#endif /* OPENSSL_VERSION_NUMBER */ - /** * initialize OpenSSL for multi-threaded use */ @@ -205,14 +190,9 @@ static void threading_init() cleanup = thread_value_create(cleanup_thread); -#if OPENSSL_VERSION_NUMBER >= 0x1000000fL CRYPTO_THREADID_set_callback(threadid_function); -#else - CRYPTO_set_id_callback(id_function); -#endif CRYPTO_set_locking_callback(locking_function); - CRYPTO_set_dynlock_create_callback(create_function); CRYPTO_set_dynlock_lock_callback(lock_function); CRYPTO_set_dynlock_destroy_callback(destroy_function); @@ -663,7 +643,7 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(KDF, KDF_PRF_PLUS), #endif #endif /* OPENSSL_NO_HMAC */ -#if (OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_AES)) || \ +#if (!defined(OPENSSL_NO_AES)) || \ (OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA)) /* AEAD (AES GCM since 1.0.1, ChaCha20-Poly1305 since 1.1.0) */ PLUGIN_REGISTER(AEAD, openssl_aead_create), From a8bab0ee15f509a3452c776357bbb2e3b5255f43 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Mar 2022 11:26:52 +0100 Subject: [PATCH 12/15] openssl: Move ENGINE-specific code into a separate file This way we can compile it with OPENSSL_SUPPRESS_DEPRECATED for OpenSSL 3.0, which deprecated the ENGINE API. --- src/libstrongswan/plugins/openssl/Makefile.am | 1 + .../plugins/openssl/openssl_engine.c | 214 ++++++++++++++++++ .../plugins/openssl/openssl_engine.h | 53 +++++ .../plugins/openssl/openssl_plugin.c | 166 +------------- 4 files changed, 272 insertions(+), 162 deletions(-) create mode 100644 src/libstrongswan/plugins/openssl/openssl_engine.c create mode 100644 src/libstrongswan/plugins/openssl/openssl_engine.h diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am index 4df4a81b4..979bd8886 100644 --- a/src/libstrongswan/plugins/openssl/Makefile.am +++ b/src/libstrongswan/plugins/openssl/Makefile.am @@ -19,6 +19,7 @@ libstrongswan_openssl_la_SOURCES = \ openssl_plugin.h openssl_plugin.c \ openssl_util.c openssl_util.h \ openssl_crypter.c openssl_crypter.h \ + openssl_engine.c openssl_engine.h \ openssl_hasher.c openssl_hasher.h \ openssl_sha1_prf.c openssl_sha1_prf.h \ openssl_diffie_hellman.c openssl_diffie_hellman.h \ diff --git a/src/libstrongswan/plugins/openssl/openssl_engine.c b/src/libstrongswan/plugins/openssl/openssl_engine.c new file mode 100644 index 000000000..a4b2cba5f --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_engine.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2008-2018 Tobias Brunner + * Copyright (C) 2008 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 . + * + * 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. + */ + +/* the ENGINE API has been deprecated with OpenSSL 3.0 (the provider API should + * be used instead) */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include +#include + +#include "openssl_engine.h" + +#if !defined(OPENSSL_NO_ENGINE) && \ + (OPENSSL_VERSION_NUMBER < 0x30000000L || !defined(OPENSSL_NO_DEPRECATED)) + +#include + +#include "openssl_ec_private_key.h" +#include "openssl_ed_private_key.h" +#include "openssl_rsa_private_key.h" + +/** + * Login to engine with a PIN specified for a keyid + */ +static bool login(ENGINE *engine, chunk_t keyid) +{ + enumerator_t *enumerator; + shared_key_t *shared; + identification_t *id; + chunk_t key; + char pin[64]; + bool found = FALSE, success = FALSE; + + id = identification_create_from_encoding(ID_KEY_ID, keyid); + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_PIN, id, NULL); + while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) + { + found = TRUE; + key = shared->get_key(shared); + if (snprintf(pin, sizeof(pin), + "%.*s", (int)key.len, key.ptr) >= sizeof(pin)) + { + continue; + } + if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0)) + { + success = TRUE; + break; + } + else + { + DBG1(DBG_CFG, "setting PIN on engine failed"); + } + } + enumerator->destroy(enumerator); + id->destroy(id); + if (!found) + { + DBG1(DBG_CFG, "no PIN found for %#B", &keyid); + } + return success; +} + +/* + * Described in header + */ +private_key_t *openssl_private_key_connect(key_type_t type, va_list args) +{ + char *engine_id = NULL; + char keyname[BUF_LEN]; + chunk_t keyid = chunk_empty; + EVP_PKEY *key; + ENGINE *engine; + int slot = -1; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_PKCS11_KEYID: + keyid = va_arg(args, chunk_t); + continue; + case BUILD_PKCS11_SLOT: + slot = va_arg(args, int); + continue; + case BUILD_PKCS11_MODULE: + engine_id = va_arg(args, char*); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + if (!keyid.len) + { + return NULL; + } + + memset(keyname, 0, sizeof(keyname)); + if (slot != -1) + { + snprintf(keyname, sizeof(keyname), "%d:", slot); + } + if (sizeof(keyname) - strlen(keyname) <= keyid.len * 2 + 1) + { + return NULL; + } + chunk_to_hex(keyid, keyname + strlen(keyname), FALSE); + + if (!engine_id) + { + engine_id = lib->settings->get_str(lib->settings, + "%s.plugins.openssl.engine_id", "pkcs11", lib->ns); + } + engine = ENGINE_by_id(engine_id); + if (!engine) + { + DBG2(DBG_LIB, "engine '%s' is not available", engine_id); + return NULL; + } + if (!ENGINE_init(engine)) + { + DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id); + ENGINE_free(engine); + return NULL; + } + ENGINE_free(engine); + if (!login(engine, keyid)) + { + DBG1(DBG_LIB, "login to engine '%s' failed", engine_id); + ENGINE_finish(engine); + return NULL; + } + key = ENGINE_load_private_key(engine, keyname, NULL, NULL); + ENGINE_finish(engine); + if (!key) + { + DBG1(DBG_LIB, "failed to load private key with ID '%s' from " + "engine '%s'", keyname, engine_id); + return NULL; + } + + switch (EVP_PKEY_base_id(key)) + { +#ifndef OPENSSL_NO_RSA + case EVP_PKEY_RSA: + return openssl_rsa_private_key_create(key, TRUE); +#endif +#ifndef OPENSSL_NO_ECDSA + case EVP_PKEY_EC: + return openssl_ec_private_key_create(key, TRUE); +#endif +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC) + case EVP_PKEY_ED25519: + case EVP_PKEY_ED448: + return openssl_ed_private_key_create(key, TRUE); +#endif /* OPENSSL_VERSION_NUMBER */ + default: + EVP_PKEY_free(key); + break; + } + return NULL; +} + +/* + * Described in header + */ +void openssl_engine_deinit() +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + ENGINE_cleanup(); +#endif +} + +/* + * Described in header + */ +void openssl_engine_init() +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* activate support for hardware accelerators */ + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); +#endif +} + +#else /* OPENSSL_NO_ENGINE */ + +private_key_t *openssl_private_key_connect(key_type_t type, va_list args) +{ + return NULL; +} + +void openssl_engine_deinit() {} + +void openssl_engine_init() {} + +#endif /* OPENSSL_NO_ENGINE */ diff --git a/src/libstrongswan/plugins/openssl/openssl_engine.h b/src/libstrongswan/plugins/openssl/openssl_engine.h new file mode 100644 index 000000000..d25d12321 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_engine.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * + * 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. + */ + +/** + * Compatibility code for legacy ENGINE support. + * + * @defgroup openssl_engine openssl_engine + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_ENGINE_H_ +#define OPENSSL_ENGINE_H_ + +#include + +/** + * Load a private key from a token/ENGINE. + * + * @param type key type to load + * @param args build arguments + */ +private_key_t *openssl_private_key_connect(key_type_t type, va_list args); + +/** + * Initialize ENGINE support. + */ +void openssl_engine_init(); + +/** + * Deinitialize ENGINE support. + */ +void openssl_engine_deinit(); + +#endif /** OPENSSL_ENGINE_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index 3446dd0d4..77422f8be 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -25,9 +25,6 @@ #include #include #include -#ifndef OPENSSL_NO_ENGINE -#include -#endif #ifndef OPENSSL_NO_ECDH #include #endif @@ -38,6 +35,7 @@ #include "openssl_plugin.h" #include "openssl_util.h" #include "openssl_crypter.h" +#include "openssl_engine.h" #include "openssl_hasher.h" #include "openssl_sha1_prf.h" #include "openssl_diffie_hellman.h" @@ -316,157 +314,6 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args) return NULL; } -#ifndef OPENSSL_NO_ENGINE -/** - * Login to engine with a PIN specified for a keyid - */ -static bool login(ENGINE *engine, chunk_t keyid) -{ - enumerator_t *enumerator; - shared_key_t *shared; - identification_t *id; - chunk_t key; - char pin[64]; - bool found = FALSE, success = FALSE; - - id = identification_create_from_encoding(ID_KEY_ID, keyid); - enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, - SHARED_PIN, id, NULL); - while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) - { - found = TRUE; - key = shared->get_key(shared); - if (snprintf(pin, sizeof(pin), - "%.*s", (int)key.len, key.ptr) >= sizeof(pin)) - { - continue; - } - if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0)) - { - success = TRUE; - break; - } - else - { - DBG1(DBG_CFG, "setting PIN on engine failed"); - } - } - enumerator->destroy(enumerator); - id->destroy(id); - if (!found) - { - DBG1(DBG_CFG, "no PIN found for %#B", &keyid); - } - return success; -} -#endif /* OPENSSL_NO_ENGINE */ - -/** - * Load private key via engine - */ -static private_key_t *openssl_private_key_connect(key_type_t type, - va_list args) -{ -#ifndef OPENSSL_NO_ENGINE - char *engine_id = NULL; - char keyname[BUF_LEN]; - chunk_t keyid = chunk_empty; - EVP_PKEY *key; - ENGINE *engine; - int slot = -1; - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_PKCS11_KEYID: - keyid = va_arg(args, chunk_t); - continue; - case BUILD_PKCS11_SLOT: - slot = va_arg(args, int); - continue; - case BUILD_PKCS11_MODULE: - engine_id = va_arg(args, char*); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - if (!keyid.len) - { - return NULL; - } - - memset(keyname, 0, sizeof(keyname)); - if (slot != -1) - { - snprintf(keyname, sizeof(keyname), "%d:", slot); - } - if (sizeof(keyname) - strlen(keyname) <= keyid.len * 2 + 1) - { - return NULL; - } - chunk_to_hex(keyid, keyname + strlen(keyname), FALSE); - - if (!engine_id) - { - engine_id = lib->settings->get_str(lib->settings, - "%s.plugins.openssl.engine_id", "pkcs11", lib->ns); - } - engine = ENGINE_by_id(engine_id); - if (!engine) - { - DBG2(DBG_LIB, "engine '%s' is not available", engine_id); - return NULL; - } - if (!ENGINE_init(engine)) - { - DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id); - ENGINE_free(engine); - return NULL; - } - ENGINE_free(engine); - if (!login(engine, keyid)) - { - DBG1(DBG_LIB, "login to engine '%s' failed", engine_id); - ENGINE_finish(engine); - return NULL; - } - key = ENGINE_load_private_key(engine, keyname, NULL, NULL); - ENGINE_finish(engine); - if (!key) - { - DBG1(DBG_LIB, "failed to load private key with ID '%s' from " - "engine '%s'", keyname, engine_id); - return NULL; - } - - switch (EVP_PKEY_base_id(key)) - { -#ifndef OPENSSL_NO_RSA - case EVP_PKEY_RSA: - return openssl_rsa_private_key_create(key, TRUE); -#endif -#ifndef OPENSSL_NO_ECDSA - case EVP_PKEY_EC: - return openssl_ec_private_key_create(key, TRUE); -#endif -#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC) - case EVP_PKEY_ED25519: - case EVP_PKEY_ED448: - return openssl_ed_private_key_create(key, TRUE); -#endif /* OPENSSL_VERSION_NUMBER */ - default: - EVP_PKEY_free(key); - break; - } -#endif /* OPENSSL_NO_ENGINE */ - return NULL; -} - METHOD(plugin_t, get_name, char*, private_openssl_plugin_t *this) { @@ -865,6 +712,7 @@ METHOD(plugin_t, get_features, int, METHOD(plugin_t, destroy, void, private_openssl_plugin_t *this) { + /* OpenSSL 1.1.0 cleans up itself at exit and while OPENSSL_cleanup() exists we * can't call it as we couldn't re-initialize the library (as required by the * unit tests and the Android app) */ @@ -874,9 +722,7 @@ METHOD(plugin_t, destroy, void, OBJ_cleanup(); #endif EVP_cleanup(); -#ifndef OPENSSL_NO_ENGINE - ENGINE_cleanup(); -#endif /* OPENSSL_NO_ENGINE */ + openssl_engine_deinit(); CRYPTO_cleanup_all_ex_data(); threading_cleanup(); ERR_free_strings(); @@ -960,11 +806,7 @@ plugin_t *openssl_plugin_create() OPENSSL_config(NULL); #endif OpenSSL_add_all_algorithms(); -#ifndef OPENSSL_NO_ENGINE - /* activate support for hardware accelerators */ - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); -#endif /* OPENSSL_NO_ENGINE */ + openssl_engine_init(); #endif /* OPENSSL_VERSION_NUMBER */ #if OPENSSL_VERSION_NUMBER >= 0x30000000L From 7d99b29b994803091641e05c3735c3cb0cad424c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Mar 2022 15:16:12 +0100 Subject: [PATCH 13/15] unit-tests: Add support for more than one warning per test case Warnings are usually short (as compared to failures that contain data dumps), so the buffer size can be reduced. --- src/libstrongswan/tests/test_runner.c | 38 +++++++++++++++----- src/libstrongswan/tests/test_suite.c | 50 +++++++++++++++++---------- src/libstrongswan/tests/test_suite.h | 12 +++++++ 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 67fe80f7f..6abdfd0c1 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -456,23 +456,45 @@ static void collect_failure_info(array_t *failures, char *name, int i) array_insert(failures, -1, &failure); } +/** + * Context data to collect warnings + */ +typedef struct { + char *name; + int i; + array_t *warnings; +} warning_ctx_t; + +/** + * Callback to collect warnings + */ +CALLBACK(warning_cb, void, + warning_ctx_t *ctx, const char *msg, const char *file, const int line) +{ + failure_t warning = { + .name = ctx->name, + .i = ctx->i, + .file = file, + .line = line, + }; + + strncpy(warning.msg, msg, sizeof(warning.msg) - 1); + warning.msg[sizeof(warning.msg)-1] = 0; + array_insert(ctx->warnings, -1, &warning); +} + /** * Collect warning information, add failure_t to array */ static bool collect_warning_info(array_t *warnings, char *name, int i) { - failure_t warning = { + warning_ctx_t ctx = { .name = name, .i = i, + .warnings = warnings, }; - warning.line = test_warning_get(warning.msg, sizeof(warning.msg), - &warning.file); - if (warning.line) - { - array_insert(warnings, -1, &warning); - } - return warning.line; + return test_warnings_get(warning_cb, &ctx); } /** diff --git a/src/libstrongswan/tests/test_suite.c b/src/libstrongswan/tests/test_suite.c index 412d9fbf6..1149e1357 100644 --- a/src/libstrongswan/tests/test_suite.c +++ b/src/libstrongswan/tests/test_suite.c @@ -50,19 +50,26 @@ static backtrace_t *failure_backtrace; static bool worker_failed; /** - * Warning message buf + * Warning information */ -static char warning_buf[4096]; +typedef struct { + /** Warning message */ + char msg[BUF_LEN]; + /** Source file warning was issued */ + const char *file; + /** Line of source warning was issued */ + int line; +} warning_info_t; /** - * Source file warning was issued + * Warnings that occurred */ -static const char *warning_file; +static warning_info_t warnings[3]; /** - * Line of source file warning was issued + * Current warning index */ -static int warning_line; +static int warning_idx = -1; /** * See header. @@ -442,11 +449,16 @@ void test_warn_msg(const char *file, int line, char *fmt, ...) { va_list args; + if (++warning_idx >= countof(warnings)) + { + return; + } va_start(args, fmt); - vsnprintf(warning_buf, sizeof(warning_buf), fmt, args); - warning_line = line; - warning_file = file; + vsnprintf(warnings[warning_idx].msg, sizeof(warnings[warning_idx].msg), + fmt, args); va_end(args); + warnings[warning_idx].file = file; + warnings[warning_idx].line = line; } /** @@ -479,20 +491,22 @@ int test_failure_get(char *msg, int len, const char **file) /** * See header. */ -int test_warning_get(char *msg, int len, const char **file) +bool test_warnings_get(void (*cb)(void *ctx, const char *msg, const char *file, + const int line), void *ctx) { - int line = warning_line; + int i; - if (!line) + if (warning_idx < 0) { - return 0; + return FALSE; + } + for (i = 0; i <= warning_idx && i < countof(warnings); i++) + { + cb(ctx, warnings[i].msg, warnings[i].file, warnings[i].line); } - strncpy(msg, warning_buf, len - 1); - msg[len - 1] = 0; - *file = warning_file; /* reset state */ - warning_line = 0; - return line; + warning_idx = -1; + return TRUE; } /** diff --git a/src/libstrongswan/tests/test_suite.h b/src/libstrongswan/tests/test_suite.h index a35e9ec63..e0629356b 100644 --- a/src/libstrongswan/tests/test_suite.h +++ b/src/libstrongswan/tests/test_suite.h @@ -219,6 +219,18 @@ void test_setup_timeout(int s); */ int test_failure_get(char *msg, int len, const char **file); +/** + * Get info about warnings if any were issued during the test. Resets the + * warning state. + * + * @param cb callback that receives a custom context object, message, + * source file and line of each warning + * @param ctx context object + * @return TRUE if any warnings were issued + */ +bool test_warnings_get(void (*cb)(void *ctx, const char *msg, const char *file, + const int line), void *ctx); + /** * Get info about a warning if one was issued during the test. Resets the * warning state. From 76ff49b76104dbe0d2c535bbebbb9910fd9c7da0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Mar 2022 16:45:16 +0100 Subject: [PATCH 14/15] unit-tests: Add environment variable to skip IPv6 stream tests This is an issue e.g. when running tests in default Docker containers. --- src/libstrongswan/tests/suites/test_stream.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libstrongswan/tests/suites/test_stream.c b/src/libstrongswan/tests/suites/test_stream.c index 899306af2..d273cd057 100644 --- a/src/libstrongswan/tests/suites/test_stream.c +++ b/src/libstrongswan/tests/suites/test_stream.c @@ -245,23 +245,29 @@ Suite *stream_suite_create() { Suite *s; TCase *tc; + int count = countof(services); + + if (getenv("TESTS_NO_IPV6")) + { + count--; + } s = suite_create("stream"); tc = tcase_create("sync"); - tcase_add_loop_test(tc, test_sync, 0, countof(services)); + tcase_add_loop_test(tc, test_sync, 0, count); suite_add_tcase(s, tc); tc = tcase_create("async"); - tcase_add_loop_test(tc, test_async, 0, countof(services)); + tcase_add_loop_test(tc, test_async, 0, count); suite_add_tcase(s, tc); tc = tcase_create("all"); - tcase_add_loop_test(tc, test_all, 0, countof(services)); + tcase_add_loop_test(tc, test_all, 0, count); suite_add_tcase(s, tc); tc = tcase_create("concurrency"); - tcase_add_loop_test(tc, test_concurrency, 0, countof(services)); + tcase_add_loop_test(tc, test_concurrency, 0, count); suite_add_tcase(s, tc); return s; From a5cfa571346e9eeedb452d1826574ff0f1839978 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Mar 2022 14:04:15 +0100 Subject: [PATCH 15/15] github: Add a build against OpenSSL 3.0 --- .github/workflows/linux.yml | 2 +- scripts/test.sh | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 9ac3ef098..a807ef98b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -87,7 +87,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test: [ botan, wolfssl, openssl, gcrypt ] + test: [ botan, wolfssl, openssl, openssl-3, gcrypt ] leak-detective: [ no, yes ] env: LEAK_DETECTIVE: ${{ matrix.leak-detective || 'no' }} diff --git a/scripts/test.sh b/scripts/test.sh index c397e00ec..b1e352033 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -89,6 +89,46 @@ build_tss2() cd - } +build_openssl() +{ + SSL_REV=3.0.2 + SSL_PKG=openssl-$SSL_REV + SSL_DIR=$DEPS_BUILD_DIR/$SSL_PKG + SSL_SRC=https://www.openssl.org/source/$SSL_PKG.tar.gz + SSL_INS=$DEPS_PREFIX/ssl + SSL_OPT="shared no-tls no-dtls no-ssl3 no-zlib no-comp no-idea no-psk no-srp + no-stdio no-tests enable-rfc3779 enable-ec_nistp_64_gcc_128" + + if test -d "$SSL_DIR"; then + return + fi + + # insist on compiling with gcc and debug information as symbols are otherwise not found + if test "$LEAK_DETECTIVE" = "yes"; then + SSL_OPT="$SSL_OPT CC=gcc -d" + fi + + echo "$ build_openssl()" + + curl -L $SSL_SRC | tar xz -C $DEPS_BUILD_DIR && + cd $SSL_DIR && + ./config --prefix=$SSL_INS --openssldir=$SSL_INS --libdir=lib $SSL_OPT && + make -j4 >/dev/null && + sudo make install_sw >/dev/null && + sudo ldconfig || exit $? + cd - +} + +use_custom_openssl() +{ + CFLAGS="$CFLAGS -I$DEPS_PREFIX/ssl/include" + export LDFLAGS="$LDFLAGS -L$DEPS_PREFIX/ssl/lib" + export LD_LIBRARY_PATH="$DEPS_PREFIX/ssl/lib:$LD_LIBRARY_PATH" + if test "$1" = "build-deps"; then + build_openssl + fi +} + : ${BUILD_DIR=$PWD} : ${DEPS_BUILD_DIR=$BUILD_DIR/..} : ${DEPS_PREFIX=/usr/local} @@ -114,6 +154,10 @@ openssl*) CONFIG="--disable-defaults --enable-pki --enable-openssl --enable-pem" export TESTS_PLUGINS="test-vectors pem openssl!" DEPS="libssl-dev" + if test "$TEST" = "openssl-3"; then + DEPS="" + use_custom_openssl $1 + fi ;; gcrypt) CONFIG="--disable-defaults --enable-pki --enable-gcrypt --enable-pkcs1 --enable-pkcs8" @@ -184,6 +228,7 @@ all|coverage|sonarcloud) build_wolfssl build_tss2 fi + use_custom_openssl $1 ;; win*) CONFIG="--disable-defaults --enable-svc --enable-ikev2