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

openSUSE Build Service is sponsored by