File 1311-crypto-Add-fips_provider_buildinfo-to-crypto-info-ma.patch of Package erlang
From 494811c9ec26eff38f65ea526426a90b0288aa91 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Mon, 10 Feb 2025 16:08:43 +0100
Subject: [PATCH] crypto: Add 'fips_provider_buildinfo' to crypto:info() map
The version of the fips provider may be different than rest of OpenSSL
as far from all OpenSSL versions have a *certified* fips provider.
---
lib/crypto/c_src/crypto.c | 12 +++++++++---
lib/crypto/c_src/info.c | 30 ++++++++++++++++++++++++------
lib/crypto/src/crypto.erl | 13 +++++++++----
lib/crypto/test/crypto_SUITE.erl | 19 +++++++++++++++++++
4 files changed, 61 insertions(+), 13 deletions(-)
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 343bd30fff..f37bd14f45 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -139,6 +139,9 @@ static ErlNifFunc nif_funcs[] = {
};
#ifdef HAS_3_0_API
+# ifdef FIPS_SUPPORT
+OSSL_PROVIDER *fips_provider;
+# endif
OSSL_PROVIDER *prov[MAX_NUM_PROVIDERS];
int prov_cnt;
#endif
@@ -255,9 +258,7 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
#ifdef HAS_3_0_API
prov_cnt = 0;
# ifdef FIPS_SUPPORT
- if ((prov[prov_cnt] = OSSL_PROVIDER_load(NULL, "fips"))) {
- prov_cnt++;
- }
+ fips_provider = OSSL_PROVIDER_load(NULL, "fips");
# endif
if (!(prov[prov_cnt++] = OSSL_PROVIDER_load(NULL, "default"))) {
ret = __LINE__; goto done;
@@ -392,6 +393,11 @@ static void unload(ErlNifEnv* env, void* priv_data)
destroy_engine_mutex(env);
#ifdef HAS_3_0_API
+# ifdef FIPS_SUPPORT
+ if (fips_provider) {
+ OSSL_PROVIDER_unload(fips_provider);
+ }
+# endif
while (prov_cnt > 0) {
OSSL_PROVIDER_unload(prov[--prov_cnt]);
}
diff --git a/lib/crypto/c_src/info.c b/lib/crypto/c_src/info.c
index ce764f0df5..e3a1ed1379 100644
--- a/lib/crypto/c_src/info.c
+++ b/lib/crypto/c_src/info.c
@@ -107,7 +107,10 @@ const char* resource_name(const char *name, ErlNifBinary* buf)
ERL_NIF_TERM info_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{/* () */
- ERL_NIF_TERM keys[5], vals[5];
+#if defined(HAS_3_0_API) && defined(FIPS_SUPPORT)
+ extern OSSL_PROVIDER *fips_provider;
+#endif
+ ERL_NIF_TERM keys[6], vals[6];
ERL_NIF_TERM ret;
size_t cnt;
int ok;
@@ -125,13 +128,28 @@ ERL_NIF_TERM info_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
#endif
keys[3] = enif_make_atom(env, "cryptolib_version_linked");
vals[3] = enif_make_string(env, OpenSSL_version(OPENSSL_VERSION), ERL_NIF_LATIN1);
-#ifdef HAS_3_0_API
- keys[4] = enif_make_atom(env, "fips_provider_available");
- vals[4] = OSSL_PROVIDER_available(NULL, "fips") ? atom_true : atom_false;
- cnt = 5;
-#else
cnt = 4;
+#ifdef HAS_3_0_API
+ keys[cnt] = enif_make_atom(env, "fips_provider_available");
+ vals[cnt] = OSSL_PROVIDER_available(NULL, "fips") ? atom_true : atom_false;
+ cnt++;
+# ifdef FIPS_SUPPORT
+ if (fips_provider) {
+ const char *build_info = NULL;
+ OSSL_PARAM request[] = {
+ { "buildinfo", OSSL_PARAM_UTF8_PTR, &build_info, 0, 0 },
+ { NULL, 0, NULL, 0, 0 }
+ };
+ if (!OSSL_PROVIDER_get_params(fips_provider, request)) {
+ build_info = "Not available";
+ }
+ keys[cnt] = enif_make_atom(env, "fips_provider_buildinfo");
+ vals[cnt] = enif_make_string(env, build_info, ERL_NIF_UTF8);
+ cnt++;
+ }
+# endif
#endif
+ ASSERT(cnt <= sizeof(keys)/sizeof(keys[0]));
ok = enif_make_map_from_arrays(env, keys, vals, cnt, &ret);
ASSERT(ok); (void)ok;
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 5b24800e8e..98849fbd80 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -918,19 +918,24 @@ Example:
cryptolib_version_compiled => "OpenSSL 3.0.0 7 sep 2021",
cryptolib_version_linked => "OpenSSL 3.0.0 7 sep 2021",
link_type => dynamic,
- otp_crypto_version => "5.0.2"}
+ otp_crypto_version => "5.0.2",
+ fips_provider_available => true,
+ fips_provider_buildinfo => "3.0.0"}
2>
```
-More association types than documented may be present in the map.
+More association types than documented may be present in the map. Some of the
+associations (like fips) may be absent if not supported.
""".
-doc(#{title => <<"Utility Functions">>,
since => <<"OTP 24.2">>}).
-spec info() -> #{compile_type := normal | debug | valgrind | asan,
- cryptolib_version_compiled => string() | undefined,
+ cryptolib_version_compiled := string() | undefined,
cryptolib_version_linked := string(),
link_type := dynamic | static,
- otp_crypto_version := string()
+ otp_crypto_version := string(),
+ fips_provider_available => boolean(),
+ fips_provider_buildinfo => string()
}.
info() ->
(info_nif())#{otp_crypto_version => crypto:version()}.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index dda90b0b7c..18d23b1cc8 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -4920,6 +4920,7 @@ try_enable_fips_mode(Config) ->
FIPSConfig = [{fips, true} | Config],
case crypto:info_fips() of
enabled ->
+ check_fips_provider(),
FIPSConfig;
not_enabled ->
%% Erlang/crypto configured with --enable-fips
@@ -4927,6 +4928,7 @@ try_enable_fips_mode(Config) ->
true ->
%% and also the cryptolib is fips enabled
enabled = crypto:info_fips(),
+ check_fips_provider(),
FIPSConfig;
false ->
try
@@ -4947,6 +4949,23 @@ try_enable_fips_mode(Config) ->
{skip, "FIPS mode not supported"}
end.
+check_fips_provider() ->
+ case have_provider_support() of
+ true ->
+ case crypto:info() of
+ #{fips_provider_available := true,
+ fips_provider_buildinfo := BI} when is_list(BI) ->
+ ok
+ end;
+ false ->
+ ok
+ end.
+
+have_provider_support() ->
+ [{_, PackedVsn, _}] = crypto:info_lib(),
+ MajorVsn = (PackedVsn bsr 28),
+ MajorVsn >= 3.
+
pbkdf2_hmac() ->
[{doc, "Test the pbkdf2_hmac function"}].
pbkdf2_hmac(Config) when is_list(Config) ->
--
2.43.0