]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add support for random provider
authorPauli <ppzgs1@gmail.com>
Thu, 23 May 2024 02:14:47 +0000 (12:14 +1000)
committerPauli <ppzgs1@gmail.com>
Tue, 4 Feb 2025 20:20:22 +0000 (07:20 +1100)
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/24498)

crypto/provider_core.c
crypto/rand/rand_lib.c
include/crypto/rand.h
include/internal/provider.h
include/openssl/core_dispatch.h
providers/fips/fipsprov.c

index e1025f2ee18290d161b43708cb2ea3abafdbc567..7e0fe851fa68da256a687c48530bcb707008e2ce 100644 (file)
@@ -175,7 +175,7 @@ struct ossl_provider_st {
     OSSL_FUNC_provider_get_params_fn *get_params;
     OSSL_FUNC_provider_get_capabilities_fn *get_capabilities;
     OSSL_FUNC_provider_self_test_fn *self_test;
-    OSSL_FUNC_provider_random_fn *random;
+    OSSL_FUNC_provider_random_bytes_fn *random_bytes;
     OSSL_FUNC_provider_query_operation_fn *query_operation;
     OSSL_FUNC_provider_unquery_operation_fn *unquery_operation;
 
@@ -1068,8 +1068,9 @@ static int provider_init(OSSL_PROVIDER *prov)
                 prov->self_test =
                     OSSL_FUNC_provider_self_test(provider_dispatch);
                 break;
-            case OSSL_FUNC_PROVIDER_RANDOM:
-                prov->random = OSSL_FUNC_provider_random(provider_dispatch);
+            case OSSL_FUNC_PROVIDER_RANDOM_BYTES:
+                prov->random_bytes =
+                    OSSL_FUNC_provider_random_bytes(provider_dispatch);
                 break;
             case OSSL_FUNC_PROVIDER_GET_CAPABILITIES:
                 prov->get_capabilities =
@@ -1168,6 +1169,12 @@ static int provider_deactivate(OSSL_PROVIDER *prov, int upcalls,
     if (!ossl_assert(prov != NULL))
         return -1;
 
+#ifndef FIPS_MODULE
+    if (prov->random_bytes != NULL
+            && !ossl_rand_check_random_provider_on_unload(prov->libctx, prov))
+        return -1;
+#endif
+
     /*
      * No need to lock if we've got no store because we've not been shared with
      * other threads.
@@ -1264,6 +1271,10 @@ static int provider_activate(OSSL_PROVIDER *prov, int lock, int upcalls)
     }
 
 #ifndef FIPS_MODULE
+    if (prov->random_bytes != NULL
+            && !ossl_rand_check_random_provider_on_load(prov->libctx, prov))
+        return -1;
+
     if (prov->ischild && upcalls && !ossl_provider_up_ref_parent(prov, 1))
         return -1;
 #endif
@@ -1864,11 +1875,12 @@ int ossl_provider_self_test(const OSSL_PROVIDER *prov)
  * If tracing is enabled, a message is printed indicating the requested
  * capabilities.
  */
-int ossl_provider_random(const OSSL_PROVIDER *prov, int which, void *buf, size_t n,
-                         unsigned int strength)
+int ossl_provider_random_bytes(const OSSL_PROVIDER *prov, int which,
+                               void *buf, size_t n, unsigned int strength)
 {
-    return prov->random == NULL ? 0 : prov->random(prov->provctx, which, buf, n,
-                                                   strength);
+    return prov->random_bytes == NULL ? 0
+                                      : prov->random_bytes(prov->provctx, which,
+                                                           buf, n, strength);
 }
 
 int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov,
index eb983a60676af5dedbe697fbc791fb32f597f29c..ce7dfb12c806c3240d725733fd94ce0b6a198c9f 100644 (file)
@@ -22,7 +22,6 @@
 #include "rand_local.h"
 #include "crypto/context.h"
 
-
 #ifndef OPENSSL_DEFAULT_SEED_SRC
 # define OPENSSL_DEFAULT_SEED_SRC SEED-SRC
 #endif
@@ -58,6 +57,7 @@ typedef struct rand_global_st {
      */
 #ifndef FIPS_MODULE
     OSSL_PROVIDER *random_provider;
+    char *random_provider_name;
 #endif      /* !FIPS_MODULE */
 
     /*
@@ -91,6 +91,7 @@ typedef struct rand_global_st {
     char *seed_propq;
 } RAND_GLOBAL;
 
+static EVP_RAND_CTX *rand_get0_primary(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl);
 static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl);
 static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl);
 
@@ -111,6 +112,24 @@ static RAND_GLOBAL *rand_get_global(OSSL_LIB_CTX *libctx)
 # include "internal/e_os.h"
 # include "internal/property.h"
 
+/*
+ * The default name for the random provider.
+ * This ensures that the FIPS provider will supply libcrypto's random byte
+ * requirements.
+ */
+static const char random_provider_fips_name[] = "fips";
+
+static int set_random_provider_name(RAND_GLOBAL *dgbl, const char *name)
+{
+    if (dgbl->random_provider_name != NULL
+            && OPENSSL_strcasecmp(dgbl->random_provider_name, name) == 0)
+        return 1;
+
+    OPENSSL_free(dgbl->random_provider_name);
+    dgbl->random_provider_name = strdup(name);
+    return dgbl->random_provider_name != NULL;
+}
+
 # ifndef OPENSSL_NO_ENGINE
 /* non-NULL if default_RAND_meth is ENGINE-provided */
 static ENGINE *funct_ref;
@@ -431,9 +450,9 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
         return 0;
 #ifndef FIPS_MODULE
     if (dgbl->random_provider != NULL)
-        return ossl_provider_random(dgbl->random_provider,
-                                    OSSL_PROV_RANDOM_PRIVATE,
-                                    buf, num, strength);
+        return ossl_provider_random_bytes(dgbl->random_provider,
+                                          OSSL_PROV_RANDOM_PRIVATE,
+                                          buf, num, strength);
 #endif      /* !FIPS_MODULE */
     rand = rand_get0_private(ctx, dgbl);
     if (rand != NULL)
@@ -470,9 +489,9 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
         return 0;
 #ifndef FIPS_MODULE
     if (dgbl->random_provider != NULL)
-        return ossl_provider_random(dgbl->random_provider,
-                                    OSSL_PROV_RANDOM_PRIVATE,
-                                    buf, num, strength);
+        return ossl_provider_random_bytes(dgbl->random_provider,
+                                          OSSL_PROV_RANDOM_PUBLIC,
+                                          buf, num, strength);
 #endif      /* !FIPS_MODULE */
 
     rand = rand_get0_public(ctx, dgbl);
@@ -505,7 +524,12 @@ void *ossl_rand_ctx_new(OSSL_LIB_CTX *libctx)
      * We need to ensure that base libcrypto thread handling has been
      * initialised.
      */
-     OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL);
+    OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL);
+
+    /* Prepopulate the random provider name */
+    dgbl->random_provider_name = strdup(random_provider_fips_name);
+    if (dgbl->random_provider_name == NULL)
+        goto err0;
 #endif
 
     dgbl->lock = CRYPTO_THREAD_lock_new();
@@ -524,6 +548,10 @@ void *ossl_rand_ctx_new(OSSL_LIB_CTX *libctx)
     CRYPTO_THREAD_cleanup_local(&dgbl->private);
  err1:
     CRYPTO_THREAD_lock_free(dgbl->lock);
+#ifndef FIPS_MODULE
+ err0:
+    OPENSSL_free(dgbl->random_provider_name);
+#endif
     OPENSSL_free(dgbl);
     return NULL;
 }
@@ -541,7 +569,7 @@ void ossl_rand_ctx_free(void *vdgbl)
     EVP_RAND_CTX_free(dgbl->primary);
     EVP_RAND_CTX_free(dgbl->seed);
 #ifndef FIPS_MODULE
-    OSSL_PROVIDER_unload(dgbl->random_provider);
+    OPENSSL_free(dgbl->random_provider_name);
 #endif      /* !FIPS_MODULE */
     OPENSSL_free(dgbl->rng_name);
     OPENSSL_free(dgbl->rng_cipher);
@@ -778,9 +806,8 @@ static EVP_RAND_CTX *rand_new_crngt(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent)
  * Returns pointer to its EVP_RAND_CTX on success, NULL on failure.
  *
  */
-EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
+static EVP_RAND_CTX *rand_get0_primary(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
 {
-    RAND_GLOBAL *dgbl = rand_get_global(ctx);
     EVP_RAND_CTX *ret;
 
     if (dgbl == NULL)
@@ -836,6 +863,18 @@ EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
     return ret;
 }
 
+/*
+ * Get the primary random generator.
+ * Returns pointer to its EVP_RAND_CTX on success, NULL on failure.
+ *
+ */
+EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
+{
+    RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+    return dgbl == NULL ? NULL : rand_get0_primary(ctx, dgbl);
+}
+
 static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
 {
     EVP_RAND_CTX *rand, *primary;
@@ -845,7 +884,7 @@ static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
 
     rand = CRYPTO_THREAD_get_local(&dgbl->public);
     if (rand == NULL) {
-        primary = RAND_get0_primary(ctx);
+        primary = rand_get0_primary(ctx, dgbl);
         if (primary == NULL)
             return NULL;
 
@@ -884,7 +923,7 @@ static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
 
     rand = CRYPTO_THREAD_get_local(&dgbl->private);
     if (rand == NULL) {
-        primary = RAND_get0_primary(ctx);
+        primary = rand_get0_primary(ctx, dgbl);
         if (primary == NULL)
             return NULL;
 
@@ -979,7 +1018,8 @@ static int random_conf_init(CONF_IMODULE *md, const CONF *cnf)
 {
     STACK_OF(CONF_VALUE) *elist;
     CONF_VALUE *cval;
-    RAND_GLOBAL *dgbl = rand_get_global(NCONF_get0_libctx((CONF *)cnf));
+    OSSL_LIB_CTX *libctx = NCONF_get0_libctx((CONF *)cnf);
+    RAND_GLOBAL *dgbl = rand_get_global(libctx);
     int i, r = 1;
 
     OSSL_TRACE1(CONF, "Loading random module: section %s\n",
@@ -1015,6 +1055,31 @@ static int random_conf_init(CONF_IMODULE *md, const CONF *cnf)
         } else if (OPENSSL_strcasecmp(cval->name, "seed_properties") == 0) {
             if (!random_set_string(&dgbl->seed_propq, cval->value))
                 return 0;
+        } else if (OPENSSL_strcasecmp(cval->name, "random_provider") == 0) {
+# ifndef FIPS_MODULE
+            OSSL_PROVIDER *prov = ossl_provider_find(libctx, cval->value, 0);
+
+            if (prov != NULL) {
+                if (!RAND_set1_random_provider(libctx, prov)) {
+                    ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
+                    OSSL_PROVIDER_unload(prov);
+                    return 0;
+                }
+                /*
+                 * We need to release the reference from ossl_provider_find because
+                 * we don't want to keep a reference counted handle to the provider.
+                 *
+                 * The provider unload code checks for the random provider and,
+                 * if present, our reference will be NULLed when it is fully freed.
+                 * The provider load code, conversely, checks the provider name
+                 * and re-hooks our reference if required.  This means that a load,
+                 * hook random provider, use, unload, reload, reuse sequence will
+                 * work as expected.
+                 */
+                OSSL_PROVIDER_unload(prov);
+            } else if (!set_random_provider_name(dgbl, cval->value))
+                return 0;
+# endif
         } else {
             ERR_raise_data(ERR_LIB_CRYPTO,
                            CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION,
@@ -1069,16 +1134,69 @@ int RAND_set_seed_source_type(OSSL_LIB_CTX *ctx, const char *seed,
         && random_set_string(&dgbl->seed_propq, propq);
 }
 
-int RAND_set0_random_provider(OSSL_LIB_CTX *ctx, OSSL_PROVIDER *p)
+int RAND_set1_random_provider(OSSL_LIB_CTX *ctx, OSSL_PROVIDER *prov)
 {
     RAND_GLOBAL *dgbl = rand_get_global(ctx);
-    OSSL_PROVIDER *old;
 
     if (dgbl == NULL)
         return 0;
-    old = dgbl->random_provider;
-    dgbl->random_provider = p;
-    OSSL_PROVIDER_unload(old);
+
+    if (prov == NULL) {
+        OPENSSL_free(dgbl->random_provider_name);
+        dgbl->random_provider_name = NULL;
+        dgbl->random_provider = NULL;
+        return 1;
+    }
+
+    if (dgbl->random_provider == prov)
+        return 1;
+
+    if (!set_random_provider_name(dgbl, OSSL_PROVIDER_get0_name(prov)))
+        return 0;
+
+    dgbl->random_provider = prov;
     return 1;
 }
+
+/*
+ * When a new provider is loaded, we need to check to see if it is the
+ * designated randomness provider and register it if it is.
+ */
+int ossl_rand_check_random_provider_on_load(OSSL_LIB_CTX *ctx,
+                                            OSSL_PROVIDER *prov)
+{
+    RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+    if (dgbl == NULL)
+        return 0;
+
+    /* No random provider name specified, or one is installed already */
+    if (dgbl->random_provider_name == NULL || dgbl->random_provider != NULL)
+        return 1;
+
+    /* Does this provider match the name we're using? */
+    if (strcmp(dgbl->random_provider_name, OSSL_PROVIDER_get0_name(prov)) != 0)
+        return 1;
+
+    dgbl->random_provider = prov;
+    return 1;
+}
+
+/*
+ * When a provider is being unloaded, if it is the randomness provider,
+ * we need to deregister it.
+ */
+int ossl_rand_check_random_provider_on_unload(OSSL_LIB_CTX *ctx,
+                                              OSSL_PROVIDER *prov)
+{
+    RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+    if (dgbl == NULL)
+        return 0;
+
+    if (dgbl->random_provider == prov)
+        dgbl->random_provider = NULL;
+    return 1;
+}
+
 #endif      /* !FIPS_MODULE */
index d375c2f933ce1bbcf6b1458db2b84d23dae044e8..b7b5ae356417b3d11ab7af7c1e243e8bdc7651f7 100644 (file)
@@ -151,4 +151,15 @@ uint32_t ossl_rand_uniform_uint32(OSSL_LIB_CTX *ctx, uint32_t upper, int *err);
 uint32_t ossl_rand_range_uint32(OSSL_LIB_CTX *ctx, uint32_t lower, uint32_t upper,
                                 int *err);
 
+/*
+ * Check if the named provider is the nominated entropy/random provider.
+ * If it is, use it.
+ */
+# ifndef FIPS_MODULE
+int ossl_rand_check_random_provider_on_load(OSSL_LIB_CTX *ctx,
+                                            OSSL_PROVIDER *prov);
+int ossl_rand_check_random_provider_on_unload(OSSL_LIB_CTX *ctx,
+                                              OSSL_PROVIDER *prov);
+# endif     /* FIPS_MODULE */
+
 #endif
index eb8f1fbdb9f3bd092ebbb31cefe43b0c96ae3a9a..3df3c609396365471783729ff0d62703e08f6449 100644 (file)
@@ -84,8 +84,8 @@ int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov,
                                    OSSL_CALLBACK *cb,
                                    void *arg);
 int ossl_provider_self_test(const OSSL_PROVIDER *prov);
-int ossl_provider_random(const OSSL_PROVIDER *prov, int which, void *buf, size_t n,
-                         unsigned int strength);
+int ossl_provider_random_bytes(const OSSL_PROVIDER *prov, int which,
+                               void *buf, size_t n, unsigned int strength);
 const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov,
                                                     int operation_id,
                                                     int *no_cache);
index 315baffa55ebb73509fefaba750e3657b2d559f0..2be592d9362d7605c1815bb7002338a2dd7e55d7 100644 (file)
@@ -269,10 +269,10 @@ OSSL_CORE_MAKE_FUNC(int, provider_get_capabilities, (void *provctx,
                     const char *capability, OSSL_CALLBACK *cb, void *arg))
 # define OSSL_FUNC_PROVIDER_SELF_TEST          1031
 OSSL_CORE_MAKE_FUNC(int, provider_self_test, (void *provctx))
-# define OSSL_FUNC_PROVIDER_RANDOM             1032
-OSSL_CORE_MAKE_FUNC(int, provider_random, (void *provctx, int which,
-                                           void *buf, size_t n,
-                                           unsigned int strength))
+# define OSSL_FUNC_PROVIDER_RANDOM_BYTES       1032
+OSSL_CORE_MAKE_FUNC(int, provider_random_bytes, (void *provctx, int which,
+                                                 void *buf, size_t n,
+                                                 unsigned int strength))
 
 /* Operations */
 
index 568d9a6f95752ab07fb3885c6f4dc346e9c6c0c0..d939db92c25221e30ec06e5803ad9c4d9e4e6b06 100644 (file)
@@ -41,7 +41,7 @@ static OSSL_FUNC_provider_gettable_params_fn fips_gettable_params;
 static OSSL_FUNC_provider_get_params_fn fips_get_params;
 static OSSL_FUNC_provider_query_operation_fn fips_query;
 static OSSL_FUNC_provider_query_operation_fn fips_query_internal;
-static OSSL_FUNC_provider_random_fn fips_random;
+static OSSL_FUNC_provider_random_bytes_fn fips_random_bytes;
 
 #define ALGC(NAMES, FUNC, CHECK)                \
     { { NAMES, FIPS_DEFAULT_PROPERTIES, FUNC }, CHECK }
@@ -122,8 +122,8 @@ void ossl_fips_prov_ossl_ctx_free(void *fgbl)
     OPENSSL_free(fgbl);
 }
 
-static int fips_random(ossl_unused void *vprov, int which, void *buf, size_t n,
-                       unsigned int strength)
+static int fips_random_bytes(ossl_unused void *vprov, int which,
+                             void *buf, size_t n, unsigned int strength)
 {
     OSSL_LIB_CTX *libctx;
     PROV_CTX *prov = (PROV_CTX *)vprov;
@@ -619,7 +619,7 @@ static const OSSL_DISPATCH fips_dispatch_table[] = {
     { OSSL_FUNC_PROVIDER_GET_CAPABILITIES,
       (void (*)(void))ossl_prov_get_capabilities },
     { OSSL_FUNC_PROVIDER_SELF_TEST, (void (*)(void))fips_self_test },
-    { OSSL_FUNC_PROVIDER_RANDOM, (void (*)(void))fips_random },
+    { OSSL_FUNC_PROVIDER_RANDOM_BYTES, (void (*)(void))fips_random_bytes },
     OSSL_DISPATCH_END
 };