Always try locale initialization from OPENSSL_strcasecmp

Fixes #18172

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18282)
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index c1793c9..89381f1 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -1196,8 +1196,6 @@
 
     va_start(args, type);
 
-    OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL);
-
     if (OPENSSL_strcasecmp(type, "RSA") == 0) {
         bits = va_arg(args, size_t);
         params[0] = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bits);
diff --git a/crypto/init.c b/crypto/init.c
index 8d51a13..cca93df 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -270,15 +270,6 @@
     return 1;
 }
 
-static CRYPTO_ONCE casecmp = CRYPTO_ONCE_STATIC_INIT;
-static int casecmp_inited = 0;
-DEFINE_RUN_ONCE_STATIC(ossl_init_casecmp)
-{
-    int ret = ossl_init_casecmp_int();
-
-    casecmp_inited = 1;
-    return ret;
-}
 #ifndef OPENSSL_NO_ENGINE
 static CRYPTO_ONCE engine_openssl = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_openssl)
@@ -451,10 +442,8 @@
     OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_trace_cleanup()\n");
     ossl_trace_cleanup();
 
-    if (casecmp_inited) {
-        OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_deinit_casecmp()\n");
-        ossl_deinit_casecmp();
-    }
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_deinit_casecmp()\n");
+    ossl_deinit_casecmp();
 
     base_inited = 0;
 }
@@ -468,9 +457,6 @@
 {
     uint64_t tmp;
     int aloaddone = 0;
-    if (!RUN_ONCE(&casecmp, ossl_init_casecmp))
-        return 0;
-
 
    /* Applications depend on 0 being returned when cleanup was already done */
     if (stopped) {
@@ -498,6 +484,9 @@
         aloaddone = 1;
     }
 
+    if (!ossl_init_casecmp())
+        return 0;
+
     /*
      * At some point we should look at this function with a view to moving
      * most/all of this into OSSL_LIB_CTX.
diff --git a/crypto/o_str.c b/crypto/o_str.c
index d91ac8f..40473a4 100644
--- a/crypto/o_str.c
+++ b/crypto/o_str.c
@@ -18,6 +18,7 @@
 #endif
 #include <openssl/crypto.h>
 #include "internal/cryptlib.h"
+#include "internal/thread_once.h"
 
 #define DEFAULT_SEPARATOR ':'
 #define CH_ZERO '\0'
@@ -347,13 +348,36 @@
 }
 
 #ifndef OPENSSL_NO_LOCALE
+# ifndef FIPS_MODULE
+static CRYPTO_ONCE casecmp = CRYPTO_ONCE_STATIC_INIT;
+DEFINE_RUN_ONCE_STATIC(init_casecmp)
+{
+    int ret = ossl_init_casecmp_int();
+
+    return ret;
+}
+
+int ossl_init_casecmp(void)
+{
+    if (!RUN_ONCE(&casecmp, init_casecmp))
+        return 0;
+    return 1;
+}
+# endif
+
 static locale_t loc;
 
-static locale_t ossl_c_locale(void) {
+static locale_t ossl_c_locale(void)
+{
+# ifndef FIPS_MODULE
+    if (!ossl_init_casecmp())
+        return (locale_t)0;
+# endif
     return loc;
 }
 
-int ossl_init_casecmp_int(void) {
+int ossl_init_casecmp_int(void)
+{
 # ifdef OPENSSL_SYS_WINDOWS
     loc = _create_locale(LC_COLLATE, "C");
 # else
@@ -362,9 +386,12 @@
     return (loc == (locale_t)0) ? 0 : 1;
 }
 
-void ossl_deinit_casecmp(void) {
-    freelocale(loc);
-    loc = (locale_t)0;
+void ossl_deinit_casecmp(void)
+{
+    if (loc != (locale_t)0) {
+        freelocale(loc);
+        loc = (locale_t)0;
+    }
 }
 
 int OPENSSL_strcasecmp(const char *s1, const char *s2)
@@ -387,11 +414,18 @@
     return strncasecmp_l(s1, s2, n, l);
 }
 #else
-int ossl_init_casecmp_int(void) {
+int ossl_init_casecmp(void)
+{
     return 1;
 }
 
-void ossl_deinit_casecmp(void) {
+int ossl_init_casecmp_int(void)
+{
+    return 1;
+}
+
+void ossl_deinit_casecmp(void)
+{
 }
 
 int OPENSSL_strcasecmp(const char *s1, const char *s2)
diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h
index 408924f..ebb945f 100644
--- a/include/internal/cryptlib.h
+++ b/include/internal/cryptlib.h
@@ -158,5 +158,6 @@
 unsigned char *ossl_hexstr2buf_sep(const char *str, long *buflen,
                                    const char sep);
 int ossl_init_casecmp_int(void);
+int ossl_init_casecmp(void);
 void ossl_deinit_casecmp(void);
 #endif