From 7186bff3fa2a3dd939e1bc0fed48e733da4477a7 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Mon, 8 Jan 2024 08:52:24 +0100 Subject: [PATCH 1/4] engine: Enable external AES-GCM IV when libica is in FIPS mode When the system is in FIPS mode, newer libica versions may prevent AES-GCM from being used with an external IV. FIPS requires that the AES-GCM IV is created libica internally via an approved random source. The IBMCA engine can not support the internal generation of the AES-GCM IV, because the engine API for AES-GCM does not allow this. Applications using OpenSSL to perform AES-GCM (e.g. the TLS protocol) may require to provide an external IV. Enable the use of external AES-GCM IVs for libica, if the used libica library supports this. Newer libica versions support to allow external AES-GCM IVs via function ica_allow_external_gcm_iv_in_fips_mode(). Signed-off-by: Ingo Franzki --- src/engine/e_ibmca.c | 12 +++++++++++- src/engine/ibmca.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/engine/e_ibmca.c b/src/engine/e_ibmca.c index 6cbf745..afed3fe 100644 --- a/src/engine/e_ibmca.c +++ b/src/engine/e_ibmca.c @@ -103,6 +103,8 @@ ica_aes_gcm_intermediate_t p_ica_aes_gcm_intermediate; ica_aes_gcm_last_t p_ica_aes_gcm_last; #endif ica_cleanup_t p_ica_cleanup; +ica_allow_external_gcm_iv_in_fips_mode_t + p_ica_allow_external_gcm_iv_in_fips_mode; /* save libcrypto's default ec methods */ #ifndef NO_EC @@ -825,7 +827,15 @@ static int ibmca_init(ENGINE *e) BIND(ibmca_dso, ica_ed448_ctx_del); /* ica_cleanup is not always present and only needed for newer libraries */ - p_ica_cleanup = (ica_cleanup_t)dlsym(ibmca_dso, "ica_cleanup"); + BIND(ibmca_dso, ica_cleanup); + + /* + * Allow external AES-GCM IV when libica runs in FIPS mode. + * ica_allow_external_gcm_iv_in_fips_mode() is not always present and only + * available with newer libraries. + */ + if (BIND(ibmca_dso, ica_allow_external_gcm_iv_in_fips_mode)) + p_ica_allow_external_gcm_iv_in_fips_mode(1); /* disable fallbacks on Libica */ if (BIND(ibmca_dso, ica_set_fallback_mode)) diff --git a/src/engine/ibmca.h b/src/engine/ibmca.h index 7281a5b..01465eb 100644 --- a/src/engine/ibmca.h +++ b/src/engine/ibmca.h @@ -617,6 +617,7 @@ typedef int (*ica_ed448_ctx_del_t)(ICA_ED448_CTX **ctx); typedef void (*ica_cleanup_t)(void); +typedef void (*ica_allow_external_gcm_iv_in_fips_mode_t)(int allow); /* entry points into libica, filled out at DSO load time */ extern ica_get_functionlist_t p_ica_get_functionlist; -- 2.45.1 From 2f420ff28cedfea2ca730d7e54dba39fa4e06cbc Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Wed, 10 Jan 2024 15:08:47 +0100 Subject: [PATCH 2/4] test/provider: Do not link against libica use dlopen instead When an application links against libica (via -lica), then the libica library constructor runs before the program's main function. Libica's library constructor does initialize OpenSSL and thus parses the config file. However, the test programs set up some OpenSSL configuration related environment variables within function check_libica() called from the main function. If libica has already initialized OpenSSL prior to that, OpenSSL won't initialize again, and thus these environment variables have no effect. Dynamically load libica (via dlopen) only after setting the environment variables. Signed-off-by: Ingo Franzki --- configure.ac | 2 ++ test/provider/Makefile.am | 15 +++++++++------ test/provider/dhkey.c | 24 ++++++++++++++++++++++-- test/provider/eckey.c | 24 ++++++++++++++++++++++-- test/provider/rsakey.c | 24 ++++++++++++++++++++++-- 5 files changed, 77 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index b43a659..09df230 100644 --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,8 @@ AC_ARG_WITH([provider-libica-full], []) AM_CONDITIONAL([PROVIDER_FULL_LIBICA], [test "x$useproviderfulllibica" = xyes]) +AC_SUBST(libicaversion, "$libicaversion") + # If compiled against OpenSSL 3.0 or later, build the provider unless # explicitely disabled. # If build against OpenSSL 1.1.1, we can not build the provider. diff --git a/test/provider/Makefile.am b/test/provider/Makefile.am index 15a5466..fce06b3 100644 --- a/test/provider/Makefile.am +++ b/test/provider/Makefile.am @@ -24,24 +24,27 @@ TESTS = \ check_PROGRAMS = rsakey eckey dhkey threadtest dhkey_SOURCES = dhkey.c +dhkey_LDADD = -lcrypto -ldl if PROVIDER_FULL_LIBICA -dhkey_LDADD = -lcrypto -lica +dhkey_CFLAGS = -DLIBICA_NAME=\"libica.so.@libicaversion@\" else -dhkey_LDADD = -lcrypto -lica-cex +dhkey_CFLAGS = -DLIBICA_NAME=\"libica-cex.so.@libicaversion@\" endif eckey_SOURCES = eckey.c +eckey_LDADD = -lcrypto -ldl if PROVIDER_FULL_LIBICA -eckey_LDADD = -lcrypto -lica +eckey_CFLAGS = -DLIBICA_NAME=\"libica.so.@libicaversion@\" else -eckey_LDADD = -lcrypto -lica-cex +eckey_CFLAGS = -DLIBICA_NAME=\"libica-cex.so.@libicaversion@\" endif rsakey_SOURCES = rsakey.c +rsakey_LDADD = -lcrypto -ldl if PROVIDER_FULL_LIBICA -rsakey_LDADD = -lcrypto -lica +rsakey_CFLAGS = -DLIBICA_NAME=\"libica.so.@libicaversion@\" else -rsakey_LDADD = -lcrypto -lica-cex +rsakey_CFLAGS = -DLIBICA_NAME=\"libica-cex.so.@libicaversion@\" endif threadtest_SOURCES = threadtest.c diff --git a/test/provider/dhkey.c b/test/provider/dhkey.c index 8829ecc..0ec2c03 100644 --- a/test/provider/dhkey.c +++ b/test/provider/dhkey.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -355,13 +356,32 @@ static const unsigned int required_ica_mechs[] = { RSA_ME }; static const unsigned int required_ica_mechs_len = sizeof(required_ica_mechs) / sizeof(unsigned int); +typedef unsigned int (*ica_get_functionlist_t)(libica_func_list_element *, + unsigned int *); + int check_libica() { unsigned int mech_len, i, k, found = 0; libica_func_list_element *mech_list = NULL; + void *ibmca_dso; + ica_get_functionlist_t p_ica_get_functionlist; int rc; - rc = ica_get_functionlist(NULL, &mech_len); + ibmca_dso = dlopen(LIBICA_NAME, RTLD_NOW); + if (ibmca_dso == NULL) { + fprintf(stderr, "Failed to load libica '%s'!\n", LIBICA_NAME); + return 77; + } + + p_ica_get_functionlist = + (ica_get_functionlist_t)dlsym(ibmca_dso, "ica_get_functionlist"); + if (p_ica_get_functionlist == NULL) { + fprintf(stderr, "Failed to get ica_get_functionlist from '%s'!\n", + LIBICA_NAME); + return 77; + } + + rc = p_ica_get_functionlist(NULL, &mech_len); if (rc != 0) { fprintf(stderr, "Failed to get function list from libica!\n"); return 77; @@ -373,7 +393,7 @@ int check_libica() return 77; } - rc = ica_get_functionlist(mech_list, &mech_len); + rc = p_ica_get_functionlist(mech_list, &mech_len); if (rc != 0) { fprintf(stderr, "Failed to get function list from libica!\n"); free(mech_list); diff --git a/test/provider/eckey.c b/test/provider/eckey.c index b2334d7..b8f47b7 100644 --- a/test/provider/eckey.c +++ b/test/provider/eckey.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -788,13 +789,32 @@ static const unsigned int required_ica_mechs[] = { EC_DH, EC_DSA_SIGN, static const unsigned int required_ica_mechs_len = sizeof(required_ica_mechs) / sizeof(unsigned int); +typedef unsigned int (*ica_get_functionlist_t)(libica_func_list_element *, + unsigned int *); + int check_libica() { unsigned int mech_len, i, k, found = 0; libica_func_list_element *mech_list = NULL; + void *ibmca_dso; + ica_get_functionlist_t p_ica_get_functionlist; int rc; - rc = ica_get_functionlist(NULL, &mech_len); + ibmca_dso = dlopen(LIBICA_NAME, RTLD_NOW); + if (ibmca_dso == NULL) { + fprintf(stderr, "Failed to load libica '%s'!\n", LIBICA_NAME); + return 77; + } + + p_ica_get_functionlist = + (ica_get_functionlist_t)dlsym(ibmca_dso, "ica_get_functionlist"); + if (p_ica_get_functionlist == NULL) { + fprintf(stderr, "Failed to get ica_get_functionlist from '%s'!\n", + LIBICA_NAME); + return 77; + } + + rc = p_ica_get_functionlist(NULL, &mech_len); if (rc != 0) { fprintf(stderr, "Failed to get function list from libica!\n"); return 77; @@ -806,7 +826,7 @@ int check_libica() return 77; } - rc = ica_get_functionlist(mech_list, &mech_len); + rc = p_ica_get_functionlist(mech_list, &mech_len); if (rc != 0) { fprintf(stderr, "Failed to get function list from libica!\n"); free(mech_list); diff --git a/test/provider/rsakey.c b/test/provider/rsakey.c index 366b503..9d6a618 100644 --- a/test/provider/rsakey.c +++ b/test/provider/rsakey.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -735,13 +736,32 @@ static const unsigned int required_ica_mechs[] = { RSA_ME, RSA_CRT }; static const unsigned int required_ica_mechs_len = sizeof(required_ica_mechs) / sizeof(unsigned int); +typedef unsigned int (*ica_get_functionlist_t)(libica_func_list_element *, + unsigned int *); + int check_libica() { unsigned int mech_len, i, k, found = 0; libica_func_list_element *mech_list = NULL; + void *ibmca_dso; + ica_get_functionlist_t p_ica_get_functionlist; int rc; - rc = ica_get_functionlist(NULL, &mech_len); + ibmca_dso = dlopen(LIBICA_NAME, RTLD_NOW); + if (ibmca_dso == NULL) { + fprintf(stderr, "Failed to load libica '%s'!\n", LIBICA_NAME); + return 77; + } + + p_ica_get_functionlist = + (ica_get_functionlist_t)dlsym(ibmca_dso, "ica_get_functionlist"); + if (p_ica_get_functionlist == NULL) { + fprintf(stderr, "Failed to get ica_get_functionlist from '%s'!\n", + LIBICA_NAME); + return 77; + } + + rc = p_ica_get_functionlist(NULL, &mech_len); if (rc != 0) { fprintf(stderr, "Failed to get function list from libica!\n"); return 77; @@ -753,7 +773,7 @@ int check_libica() return 77; } - rc = ica_get_functionlist(mech_list, &mech_len); + rc = p_ica_get_functionlist(mech_list, &mech_len); if (rc != 0) { fprintf(stderr, "Failed to get function list from libica!\n"); free(mech_list); -- 2.45.1 From d2254c6641b1cf34d5f735f335edf9a05ddfd67e Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Thu, 18 Jan 2024 16:35:14 +0100 Subject: [PATCH 3/4] test/provider: Explicitly initialize OpenSSL after setting env vars. When running with a libica version without commit https://github.com/opencryptoki/libica/commit/42e197f61b298c6e6992b080c1923e7e85edea5a it is necessary to explicitly initialize OpenSSL before loading libica. Because otherwise libica's library constructor will initialize OpenSSL the first time, which in turn will load the IBMCA provider, and it will fall into the same problem as fixed by above libica commit, i.e. the provider won't be able to get the supported algorithms from libica an thus will not register any algorithms. Signed-off-by: Ingo Franzki --- test/provider/dhkey.c | 2 ++ test/provider/eckey.c | 2 ++ test/provider/rsakey.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/test/provider/dhkey.c b/test/provider/dhkey.c index 0ec2c03..b1270f5 100644 --- a/test/provider/dhkey.c +++ b/test/provider/dhkey.c @@ -461,6 +461,8 @@ int main(int argc, char **argv) return 77; } + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); + ret = check_libica(); if (ret != 0) return ret; diff --git a/test/provider/eckey.c b/test/provider/eckey.c index b8f47b7..a65bea5 100644 --- a/test/provider/eckey.c +++ b/test/provider/eckey.c @@ -895,6 +895,8 @@ int main(int argc, char **argv) return 77; } + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); + ret = check_libica(); if (ret != 0) return ret; diff --git a/test/provider/rsakey.c b/test/provider/rsakey.c index 9d6a618..874de6d 100644 --- a/test/provider/rsakey.c +++ b/test/provider/rsakey.c @@ -839,6 +839,8 @@ int main(int argc, char **argv) return 77; } + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); + ret = check_libica(); if (ret != 0) return ret; -- 2.45.1 From 4ea48e0682ff9a58340421dc9d896c7ca06a2621 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Mon, 13 May 2024 08:53:56 +0200 Subject: [PATCH 4/4] engine: Fix compile error on Fedora 40 ibmca_pkey.c:627:47: error: passing argument 2 of 'EVP_PKEY_meth_set_copy' from incompatible pointer type [-Wincompatible-pointer-types] 627 | EVP_PKEY_meth_set_copy(ibmca_ed448_pmeth, ibmca_ed448_copy); Signed-off-by: Ingo Franzki --- src/engine/ibmca_pkey.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/ibmca_pkey.c b/src/engine/ibmca_pkey.c index 9c8de94..6cd8fcd 100644 --- a/src/engine/ibmca_pkey.c +++ b/src/engine/ibmca_pkey.c @@ -258,7 +258,7 @@ ret: /* ED25519 */ -static int ibmca_ed25519_copy(EVP_PKEY_CTX *to, EVP_PKEY_CTX *from) +static int ibmca_ed25519_copy(EVP_PKEY_CTX *to, const EVP_PKEY_CTX *from) { return 1; } @@ -402,7 +402,7 @@ ret: /* ED448 */ -static int ibmca_ed448_copy(EVP_PKEY_CTX *to, EVP_PKEY_CTX *from) +static int ibmca_ed448_copy(EVP_PKEY_CTX *to, const EVP_PKEY_CTX *from) { return 1; } -- 2.45.1