Browse Source

fips: use seed source requested

Fixes #21909

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21964)
Pauli 7 months ago
parent
commit
4cde7585ce

+ 1 - 1
crypto/initthread.c

@@ -257,7 +257,7 @@ void *ossl_thread_event_ctx_new(OSSL_LIB_CTX *libctx)
     if (tlocal == NULL)
         return NULL;
 
-    if (!CRYPTO_THREAD_init_local(tlocal,  NULL)) {
+    if (!CRYPTO_THREAD_init_local(tlocal, NULL)) {
         goto err;
     }
 

+ 60 - 8
crypto/provider_core.c

@@ -1930,10 +1930,12 @@ OSSL_FUNC_BIO_free_fn ossl_core_bio_free;
 OSSL_FUNC_BIO_vprintf_fn ossl_core_bio_vprintf;
 OSSL_FUNC_BIO_vsnprintf_fn BIO_vsnprintf;
 static OSSL_FUNC_self_test_cb_fn core_self_test_get_callback;
-OSSL_FUNC_get_entropy_fn ossl_rand_get_entropy;
-OSSL_FUNC_cleanup_entropy_fn ossl_rand_cleanup_entropy;
-OSSL_FUNC_get_nonce_fn ossl_rand_get_nonce;
-OSSL_FUNC_cleanup_nonce_fn ossl_rand_cleanup_nonce;
+static OSSL_FUNC_get_user_entropy_fn rand_get_user_entropy;
+static OSSL_FUNC_get_entropy_fn rand_get_entropy;
+static OSSL_FUNC_cleanup_entropy_fn rand_cleanup_entropy;
+static OSSL_FUNC_get_user_nonce_fn rand_get_user_nonce;
+static OSSL_FUNC_get_nonce_fn rand_get_nonce;
+static OSSL_FUNC_cleanup_nonce_fn rand_cleanup_nonce;
 #endif
 OSSL_FUNC_CRYPTO_malloc_fn CRYPTO_malloc;
 OSSL_FUNC_CRYPTO_zalloc_fn CRYPTO_zalloc;
@@ -2094,6 +2096,54 @@ static void core_self_test_get_callback(OPENSSL_CORE_CTX *libctx,
     OSSL_SELF_TEST_get_callback((OSSL_LIB_CTX *)libctx, cb, cbarg);
 }
 
+static size_t rand_get_entropy(const OSSL_CORE_HANDLE *handle,
+                               unsigned char **pout, int entropy,
+                               size_t min_len, size_t max_len)
+{
+    return ossl_rand_get_entropy((OSSL_LIB_CTX *)core_get_libctx(handle),
+                                 pout, entropy, min_len, max_len);
+}
+
+static size_t rand_get_user_entropy(const OSSL_CORE_HANDLE *handle,
+                                    unsigned char **pout, int entropy,
+                                    size_t min_len, size_t max_len)
+{
+    return ossl_rand_get_user_entropy((OSSL_LIB_CTX *)core_get_libctx(handle),
+                                      pout, entropy, min_len, max_len);
+}
+
+static void rand_cleanup_entropy(const OSSL_CORE_HANDLE *handle,
+                                 unsigned char *buf, size_t len)
+{
+    ossl_rand_cleanup_entropy((OSSL_LIB_CTX *)core_get_libctx(handle),
+                              buf, len);
+}
+
+static size_t rand_get_nonce(const OSSL_CORE_HANDLE *handle,
+                             unsigned char **pout,
+                             size_t min_len, size_t max_len,
+                             const void *salt, size_t salt_len)
+{
+    return ossl_rand_get_nonce((OSSL_LIB_CTX *)core_get_libctx(handle),
+                               pout, min_len, max_len, salt, salt_len);
+}
+
+static size_t rand_get_user_nonce(const OSSL_CORE_HANDLE *handle,
+                                  unsigned char **pout,
+                                  size_t min_len, size_t max_len,
+                                  const void *salt, size_t salt_len)
+{
+    return ossl_rand_get_user_nonce((OSSL_LIB_CTX *)core_get_libctx(handle),
+                                    pout, min_len, max_len, salt, salt_len);
+}
+
+static void rand_cleanup_nonce(const OSSL_CORE_HANDLE *handle,
+                               unsigned char *buf, size_t len)
+{
+    ossl_rand_cleanup_nonce((OSSL_LIB_CTX *)core_get_libctx(handle),
+                            buf, len);
+}
+
 static const char *core_provider_get0_name(const OSSL_CORE_HANDLE *prov)
 {
     return OSSL_PROVIDER_get0_name((const OSSL_PROVIDER *)prov);
@@ -2187,10 +2237,12 @@ static const OSSL_DISPATCH core_dispatch_[] = {
     { OSSL_FUNC_BIO_VPRINTF, (void (*)(void))ossl_core_bio_vprintf },
     { OSSL_FUNC_BIO_VSNPRINTF, (void (*)(void))BIO_vsnprintf },
     { OSSL_FUNC_SELF_TEST_CB, (void (*)(void))core_self_test_get_callback },
-    { OSSL_FUNC_GET_ENTROPY, (void (*)(void))ossl_rand_get_entropy },
-    { OSSL_FUNC_CLEANUP_ENTROPY, (void (*)(void))ossl_rand_cleanup_entropy },
-    { OSSL_FUNC_GET_NONCE, (void (*)(void))ossl_rand_get_nonce },
-    { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))ossl_rand_cleanup_nonce },
+    { OSSL_FUNC_GET_ENTROPY, (void (*)(void))rand_get_entropy },
+    { OSSL_FUNC_CLEANUP_ENTROPY, (void (*)(void))rand_cleanup_entropy },
+    { OSSL_FUNC_GET_NONCE, (void (*)(void))rand_get_nonce },
+    { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))rand_cleanup_nonce },
+    { OSSL_FUNC_GET_USER_ENTROPY, (void (*)(void))rand_get_user_entropy },
+    { OSSL_FUNC_GET_USER_NONCE, (void (*)(void))rand_get_user_nonce },
 #endif
     { OSSL_FUNC_CRYPTO_MALLOC, (void (*)(void))CRYPTO_malloc },
     { OSSL_FUNC_CRYPTO_ZALLOC, (void (*)(void))CRYPTO_zalloc },

+ 61 - 5
crypto/rand/prov_seed.c

@@ -7,12 +7,14 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include "rand_local.h"
 #include "crypto/rand.h"
 #include "crypto/rand_pool.h"
+#include "internal/core.h"
 #include <openssl/core_dispatch.h>
 #include <openssl/err.h>
 
-size_t ossl_rand_get_entropy(ossl_unused const OSSL_CORE_HANDLE *handle,
+size_t ossl_rand_get_entropy(ossl_unused OSSL_LIB_CTX *ctx,
                              unsigned char **pout, int entropy,
                              size_t min_len, size_t max_len)
 {
@@ -38,14 +40,46 @@ size_t ossl_rand_get_entropy(ossl_unused const OSSL_CORE_HANDLE *handle,
     return ret;
 }
 
-void ossl_rand_cleanup_entropy(ossl_unused const OSSL_CORE_HANDLE *handle,
+size_t ossl_rand_get_user_entropy(OSSL_LIB_CTX *ctx,
+                                  unsigned char **pout, int entropy,
+                                  size_t min_len, size_t max_len)
+{
+    unsigned char *buf;
+    EVP_RAND_CTX *rng = ossl_rand_get0_seed_noncreating(ctx);
+    size_t ret;
+
+    if (rng == NULL)
+        return ossl_rand_get_entropy(ctx, pout, entropy, min_len, max_len);
+
+    /* Determine how many bytes to generate */
+    ret = entropy > 0 ? (size_t)(7 + entropy) / 8 : min_len;
+    if (ret < min_len)
+        ret = min_len;
+    else if (ret > max_len)
+        ret = max_len;
+
+    /* Allocate the return buffer */
+    if ((buf = OPENSSL_secure_malloc(ret)) == NULL)
+        return 0;
+
+    /* Fill the buffer */
+    if (!EVP_RAND_generate(rng, buf, ret, entropy, 0, NULL, 0)) {
+        OPENSSL_free(buf);
+        return 0;
+    }
+    *pout = buf;
+    return ret;
+}
+
+void ossl_rand_cleanup_entropy(ossl_unused OSSL_LIB_CTX *ctx,
                                unsigned char *buf, size_t len)
 {
     OPENSSL_secure_clear_free(buf, len);
 }
 
-size_t ossl_rand_get_nonce(ossl_unused const OSSL_CORE_HANDLE *handle,
-                           unsigned char **pout, size_t min_len, size_t max_len,
+size_t ossl_rand_get_nonce(ossl_unused OSSL_LIB_CTX *ctx,
+                           unsigned char **pout,
+                           size_t min_len, ossl_unused size_t max_len,
                            const void *salt, size_t salt_len)
 {
     size_t ret = 0;
@@ -69,7 +103,29 @@ size_t ossl_rand_get_nonce(ossl_unused const OSSL_CORE_HANDLE *handle,
     return ret;
 }
 
-void ossl_rand_cleanup_nonce(ossl_unused const OSSL_CORE_HANDLE *handle,
+size_t ossl_rand_get_user_nonce(OSSL_LIB_CTX *ctx,
+                                unsigned char **pout,
+                                size_t min_len, size_t max_len,
+                                const void *salt, size_t salt_len)
+{
+    unsigned char *buf;
+    EVP_RAND_CTX *rng = ossl_rand_get0_seed_noncreating(ctx);
+
+    if (rng == NULL)
+        return ossl_rand_get_nonce(ctx, pout, min_len, max_len, salt, salt_len);
+
+    if ((buf = OPENSSL_malloc(min_len)) == NULL)
+        return 0;
+
+    if (!EVP_RAND_generate(rng, buf, min_len, 0, 0, salt, salt_len)) {
+        OPENSSL_free(buf);
+        return 0;
+    }
+    *pout = buf;
+    return min_len;
+}
+
+void ossl_rand_cleanup_nonce(ossl_unused OSSL_LIB_CTX *ctx,
                              unsigned char *buf, size_t len)
 {
     OPENSSL_clear_free(buf, len);

+ 88 - 12
crypto/rand/rand_lib.c

@@ -30,6 +30,7 @@
 # include "crypto/rand_pool.h"
 # include "prov/seeding.h"
 # include "internal/e_os.h"
+# include "internal/property.h"
 
 # ifndef OPENSSL_NO_ENGINE
 /* non-NULL if default_RAND_meth is ENGINE-provided */
@@ -345,8 +346,6 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
     }
 #endif
 
-    if (num < 0)
-        return 0;
     rand = RAND_get0_private(ctx);
     if (rand != NULL)
         return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0);
@@ -356,6 +355,8 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
 
 int RAND_priv_bytes(unsigned char *buf, int num)
 {
+    if (num < 0)
+        return 0;
     return RAND_priv_bytes_ex(NULL, buf, (size_t)num, 0);
 }
 
@@ -374,8 +375,6 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
     }
 #endif
 
-    if (num < 0)
-        return 0;
     rand = RAND_get0_public(ctx);
     if (rand != NULL)
         return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0);
@@ -385,6 +384,8 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
 
 int RAND_bytes(unsigned char *buf, int num)
 {
+    if (num < 0)
+        return 0;
     return RAND_bytes_ex(NULL, buf, (size_t)num, 0);
 }
 
@@ -534,29 +535,104 @@ static EVP_RAND_CTX *rand_new_seed(OSSL_LIB_CTX *libctx)
 {
     EVP_RAND *rand;
     RAND_GLOBAL *dgbl = rand_get_global(libctx);
-    EVP_RAND_CTX *ctx;
-    char *name;
+    EVP_RAND_CTX *ctx = NULL;
+    const char *propq = dgbl->seed_propq;
+    char *name, *props = NULL;
+    size_t props_len;
+    OSSL_PROPERTY_LIST *pl1, *pl2, *pl3 = NULL;
 
     if (dgbl == NULL)
         return NULL;
-    name = dgbl->seed_name != NULL ? dgbl->seed_name : "SEED-SRC";
-    rand = EVP_RAND_fetch(libctx, name, dgbl->seed_propq);
+    if (dgbl->seed_name != NULL) {
+        name = dgbl->seed_name;
+    } else {
+        /*
+         * Default to our internal seed source.  This isn't part of the FIPS
+         * provider so we need to override any FIPS properties.
+         */
+        if (propq == NULL || *propq == '\0') {
+            propq = "-fips";
+        } else {
+            pl1 = ossl_parse_query(libctx, propq, 1);
+            if (pl1 == NULL) {
+                ERR_raise(ERR_LIB_RAND, RAND_R_INVALID_PROPERTY_QUERY);
+                return NULL;
+            }
+            pl2 = ossl_parse_query(libctx, "-fips", 1);
+            if (pl2 == NULL) {
+                ossl_property_free(pl1);
+                ERR_raise(ERR_LIB_RAND, ERR_R_INTERNAL_ERROR);
+                return NULL;
+            }
+            pl3 = ossl_property_merge(pl2, pl1);
+            ossl_property_free(pl1);
+            ossl_property_free(pl2);
+            if (pl3 == NULL) {
+                ERR_raise(ERR_LIB_RAND, ERR_R_INTERNAL_ERROR);
+                return NULL;
+            }
+            props_len = ossl_property_list_to_string(libctx, pl3, NULL, 0);
+            if (props_len == 0) {
+                /* Shouldn't happen since we added a query element */
+                ERR_raise(ERR_LIB_RAND, ERR_R_INTERNAL_ERROR);
+                goto err;
+            } else {
+                props = OPENSSL_malloc(props_len);
+                if (props == NULL) {
+                    ERR_raise(ERR_LIB_RAND, ERR_R_MALLOC_FAILURE);
+                    goto err;
+                }
+                if (ossl_property_list_to_string(libctx, pl3,
+                                                 props, props_len) == 0) {
+                    ERR_raise(ERR_LIB_RAND, ERR_R_INTERNAL_ERROR);
+                    goto err;
+                }
+                ossl_property_free(pl3);
+                pl3 = NULL;
+                propq = props;
+            }
+        }
+        name = "SEED-SRC";
+    }
+
+    rand = EVP_RAND_fetch(libctx, name, propq);
     if (rand == NULL) {
         ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG);
-        return NULL;
+        goto err;
     }
     ctx = EVP_RAND_CTX_new(rand, NULL);
     EVP_RAND_free(rand);
     if (ctx == NULL) {
         ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_CREATE_DRBG);
-        return NULL;
+        goto err;
     }
     if (!EVP_RAND_instantiate(ctx, 0, 0, NULL, 0, NULL)) {
         ERR_raise(ERR_LIB_RAND, RAND_R_ERROR_INSTANTIATING_DRBG);
         EVP_RAND_CTX_free(ctx);
-        return NULL;
+        goto err;
     }
+    OPENSSL_free(props);
     return ctx;
+ err:
+    EVP_RAND_CTX_free(ctx);
+    ossl_property_free(pl3);
+    OPENSSL_free(props);
+    return NULL;
+}
+
+EVP_RAND_CTX *ossl_rand_get0_seed_noncreating(OSSL_LIB_CTX *ctx)
+{
+    RAND_GLOBAL *dgbl = rand_get_global(ctx);
+    EVP_RAND_CTX *ret;
+
+    if (dgbl == NULL)
+        return NULL;
+
+    if (!CRYPTO_THREAD_read_lock(dgbl->lock))
+        return NULL;
+    ret = dgbl->seed;
+    CRYPTO_THREAD_unlock(dgbl->lock);
+    return ret;
 }
 #endif
 
@@ -882,7 +958,7 @@ int RAND_set_seed_source_type(OSSL_LIB_CTX *ctx, const char *seed,
 
     if (dgbl == NULL)
         return 0;
-    if (dgbl->primary != NULL) {
+    if (dgbl->seed != NULL) {
         ERR_raise(ERR_LIB_CRYPTO, RAND_R_ALREADY_INSTANTIATED);
         return 0;
     }

+ 36 - 9
doc/internal/man3/ossl_rand_get_entropy.pod

@@ -2,8 +2,8 @@
 
 =head1 NAME
 
-ossl_rand_get_entropy, ossl_rand_cleanup_entropy,
-ossl_rand_get_nonce, ossl_rand_cleanup_nonce
+ossl_rand_get_entropy, ossl_rand_get_user_entropy, ossl_rand_cleanup_entropy,
+ossl_rand_get_nonce, ossl_rand_get_user_nonce, ossl_rand_cleanup_nonce
 - get seed material from the operating system
 
 =head1 SYNOPSIS
@@ -13,11 +13,17 @@ ossl_rand_get_nonce, ossl_rand_cleanup_nonce
  size_t ossl_rand_get_entropy(OSSL_CORE_HANDLE *handle,
                               unsigned char **pout, int entropy,
                               size_t min_len, size_t max_len);
+ size_t ossl_rand_get_user_entropy(OSSL_CORE_HANDLE *handle,
+                                   unsigned char **pout, int entropy,
+                                   size_t min_len, size_t max_len);
  void ossl_rand_cleanup_entropy(OSSL_CORE_HANDLE *handle,
                                 unsigned char *buf, size_t len);
  size_t ossl_rand_get_nonce(OSSL_CORE_HANDLE *handle,
                             unsigned char **pout, size_t min_len,
                             size_t max_len, const void *salt, size_t salt_len);
+ size_t ossl_rand_get_user_nonce(OSSL_CORE_HANDLE *handle, unsigned char **pout,
+                                 size_t min_len, size_t max_len,
+                                 const void *salt, size_t salt_len);
  void ossl_rand_cleanup_nonce(OSSL_CORE_HANDLE *handle,
                               unsigned char *buf, size_t len);
 
@@ -29,9 +35,14 @@ stored in a buffer which contains at least I<min_len> and at most I<max_len>
 bytes.  The buffer address is stored in I<*pout> and the buffer length is
 returned to the caller.
 
+ossl_rand_get_user_entropy() is the same as ossl_rand_get_entropy()
+except that it retrieves the seeding material from the library context's
+DRBG seed source.  By default this is the operating system but it can
+be changed by calling L<RAND_set_seed_source_type(3)>.
+
 ossl_rand_cleanup_entropy() cleanses and frees any storage allocated by
-ossl_rand_get_entropy().  The seeding buffer is pointed to by I<buf> and is
-of length I<len> bytes.
+ossl_rand_get_entropy() or ossl_rand_get_user_entropy().  The entropy
+buffer is pointed to by I<buf> and is of length I<len> bytes.
 
 ossl_rand_get_nonce() retrieves a nonce using the passed I<salt> parameter
 of length I<salt_len> and operating system specific information.
@@ -41,18 +52,34 @@ The output is stored in a buffer which contains at least I<min_len> and at
 most I<max_len> bytes.  The buffer address is stored in I<*pout> and the
 buffer length returned to the caller.
 
+ossl_rand_get_user_nonce() is the same as ossl_rand_get_nonce() except
+that it retrieves the seeding material from the library context's DRBG
+seed source.  By default this is the operating system but it can be
+changed by calling L<RAND_set_seed_source_type(3)>.
+
 ossl_rand_cleanup_nonce() cleanses and frees any storage allocated by
-ossl_rand_get_nonce().  The nonce buffer is pointed to by I<buf> and is
-of length I<len> bytes.
+ossl_rand_get_nonce() or ossl_rand_get_user_nonce().  The nonce buffer
+is pointed to by I<buf> and is of length I<len> bytes.
+
+=head1 NOTES
+
+FIPS providers 3.0.0, 3.0.8 and 3.0.9 incorrectly pass a provider
+internal pointer to ossl_rand_get_entropy(), ossl_rand_cleanup_entropy(),
+ossl_rand_get_nonce() and ossl_rand_cleanup_nonce().  This pointer cannot
+be safely dereferenced.
 
 =head1 RETURN VALUES
 
-ossl_rand_get_entropy() and ossl_rand_get_nonce() return the number of bytes
-in I<*pout> or 0 on error.
+ossl_rand_get_entropy(), ossl_rand_get_user_entropy(),
+ossl_rand_get_nonce() and ossl_rand_get_user_nonce() return the number
+of bytes in I<*pout> or 0 on error.
 
 =head1 HISTORY
 
-The functions described here were all added in OpenSSL 3.0.
+The functions ossl_rand_get_user_entropy() and ossl_rand_get_user_nonce()
+were added in OpenSSL 3.0.12, 3.1.4 and 3.2.0.
+
+The remaining functions described here were all added in OpenSSL 3.0.
 
 =head1 COPYRIGHT
 

+ 7 - 0
doc/man7/EVP_RAND-TEST-RAND.pod

@@ -60,6 +60,13 @@ If there are insufficient data present to satisfy a call, an error is returned.
 Sets the bytes returned when the test generator is sent a nonce request.
 Each nonce request will return all of the bytes.
 
+=item "generate" (B<OSSL_RAND_PARAM_GENERATE>) <integer>
+
+If this parameter is zero, it will only emit the nonce and entropy data
+supplied via the aforementioned parameters.  Otherwise, low quality
+non-cryptographic pseudorandom output is produced.  This parameter defaults
+to zero.
+
 =back
 
 =head1 NOTES

+ 23 - 5
doc/man7/provider-base.pod

@@ -76,11 +76,17 @@ provider-base
  size_t get_entropy(const OSSL_CORE_HANDLE *handle,
                     unsigned char **pout, int entropy,
                     size_t min_len, size_t max_len);
+ size_t get_user_entropy(const OSSL_CORE_HANDLE *handle,
+                         unsigned char **pout, int entropy,
+                         size_t min_len, size_t max_len);
  void cleanup_entropy(const OSSL_CORE_HANDLE *handle,
                       unsigned char *buf, size_t len);
  size_t get_nonce(const OSSL_CORE_HANDLE *handle,
                   unsigned char **pout, size_t min_len, size_t max_len,
                   const void *salt, size_t salt_len);
+ size_t get_user_nonce(const OSSL_CORE_HANDLE *handle,
+                       unsigned char **pout, size_t min_len, size_t max_len,
+                       const void *salt, size_t salt_len);
  void cleanup_nonce(const OSSL_CORE_HANDLE *handle,
                     unsigned char *buf, size_t len);
 
@@ -171,8 +177,10 @@ provider):
  OPENSSL_cleanse                OSSL_FUNC_OPENSSL_CLEANSE
  OSSL_SELF_TEST_set_callback    OSSL_FUNC_SELF_TEST_CB
  ossl_rand_get_entropy          OSSL_FUNC_GET_ENTROPY
+ ossl_rand_get_user_entropy     OSSL_FUNC_GET_USER_ENTROPY
  ossl_rand_cleanup_entropy      OSSL_FUNC_CLEANUP_ENTROPY
  ossl_rand_get_nonce            OSSL_FUNC_GET_NONCE
+ ossl_rand_get_user_nonce       OSSL_FUNC_GET_USER_NONCE
  ossl_rand_cleanup_nonce        OSSL_FUNC_CLEANUP_NONCE
  provider_register_child_cb     OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB
  provider_deregister_child_cb   OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB
@@ -302,9 +310,14 @@ output will have at least I<min_len> and at most I<max_len> bytes.
 The buffer address is stored in I<*pout> and the buffer length is
 returned to the caller.  On error, zero is returned.
 
+get_user_entropy() is the same as get_entropy() except that it will
+attempt to gather seed material via the seed source specified by a call to
+L<RAND_set_seed_source_type(3)> or via L<config(5)/Random Configuration>.
+
 cleanup_entropy() is used to clean up and free the buffer returned by
-get_entropy().  The entropy pointer returned by get_entropy() is passed in
-B<buf> and its length in B<len>.
+get_entropy() or get_user_entropy().  The entropy pointer returned by
+get_entropy() or get_user_entropy() is passed in B<buf> and its length
+in B<len>.
 
 get_nonce() retrieves a nonce using the passed I<salt> parameter
 of length I<salt_len> and operating system specific information.
@@ -314,9 +327,14 @@ The output is stored in a buffer which contains at least I<min_len> and at
 most I<max_len> bytes.  The buffer address is stored in I<*pout> and the
 buffer length returned to the caller.  On error, zero is returned.
 
-cleanup_nonce() is used to clean up and free the buffer returned by
-get_nonce().  The nonce pointer returned by get_nonce() is passed in
-B<buf> and its length in B<len>.
+get_user_nonce() is the same as get_nonce() except that it will attempt
+to gather seed material via the seed source specified by a call to
+L<RAND_set_seed_source_type(3)> or via L<config(5)/Random Configuration>.
+
+cleanup_nonce() is used to clean up and free the buffer returned
+by get_nonce() or get_user_nonce().  The nonce pointer returned by
+get_nonce() or get_user_nonce() is passed in B<buf> and its length
+in B<len>.
 
 provider_register_child_cb() registers callbacks for being informed about the
 loading and unloading of providers in the application's library context.

+ 12 - 5
include/crypto/rand.h

@@ -108,15 +108,21 @@ void ossl_random_add_conf_module(void);
 /*
  * Get and cleanup random seed material.
  */
-size_t ossl_rand_get_entropy(ossl_unused const OSSL_CORE_HANDLE *handle,
+size_t ossl_rand_get_entropy(OSSL_LIB_CTX *ctx,
                              unsigned char **pout, int entropy,
                              size_t min_len, size_t max_len);
-void ossl_rand_cleanup_entropy(ossl_unused const OSSL_CORE_HANDLE *handle,
+size_t ossl_rand_get_user_entropy(OSSL_LIB_CTX *ctx,
+                                  unsigned char **pout, int entropy,
+                                  size_t min_len, size_t max_len);
+void ossl_rand_cleanup_entropy(OSSL_LIB_CTX *ctx,
                                unsigned char *buf, size_t len);
-size_t ossl_rand_get_nonce(ossl_unused const OSSL_CORE_HANDLE *handle,
+size_t ossl_rand_get_nonce(OSSL_LIB_CTX *ctx,
                            unsigned char **pout, size_t min_len, size_t max_len,
                            const void *salt, size_t salt_len);
-void ossl_rand_cleanup_nonce(ossl_unused const OSSL_CORE_HANDLE *handle,
+size_t ossl_rand_get_user_nonce(OSSL_LIB_CTX *ctx, unsigned char **pout,
+                                size_t min_len, size_t max_len,
+                                const void *salt, size_t salt_len);
+void ossl_rand_cleanup_nonce(OSSL_LIB_CTX *ctx,
                              unsigned char *buf, size_t len);
 
 /*
@@ -127,6 +133,7 @@ int ossl_pool_add_nonce_data(RAND_POOL *pool);
 
 # ifdef FIPS_MODULE
 EVP_RAND_CTX *ossl_rand_get0_private_noncreating(OSSL_LIB_CTX *ctx);
+# else
+EVP_RAND_CTX *ossl_rand_get0_seed_noncreating(OSSL_LIB_CTX *ctx);
 # endif
-
 #endif

+ 11 - 0
include/openssl/core_dispatch.h

@@ -176,6 +176,10 @@ OSSL_CORE_MAKE_FUNC(int, BIO_vsnprintf,
 OSSL_CORE_MAKE_FUNC(int, BIO_ctrl, (OSSL_CORE_BIO *bio,
                                     int cmd, long num, void *ptr))
 
+/* New seeding functions prototypes with the 101-104 series */
+#define OSSL_FUNC_GET_USER_ENTROPY            98
+#define OSSL_FUNC_GET_USER_NONCE              99
+
 #define OSSL_FUNC_SELF_TEST_CB               100
 OSSL_CORE_MAKE_FUNC(void, self_test_cb, (OPENSSL_CORE_CTX *ctx, OSSL_CALLBACK **cb,
                                          void **cbarg))
@@ -188,12 +192,19 @@ OSSL_CORE_MAKE_FUNC(void, self_test_cb, (OPENSSL_CORE_CTX *ctx, OSSL_CALLBACK **
 OSSL_CORE_MAKE_FUNC(size_t, get_entropy, (const OSSL_CORE_HANDLE *handle,
                                           unsigned char **pout, int entropy,
                                           size_t min_len, size_t max_len))
+OSSL_CORE_MAKE_FUNC(size_t, get_user_entropy, (const OSSL_CORE_HANDLE *handle,
+                                               unsigned char **pout, int entropy,
+                                               size_t min_len, size_t max_len))
 OSSL_CORE_MAKE_FUNC(void, cleanup_entropy, (const OSSL_CORE_HANDLE *handle,
                                             unsigned char *buf, size_t len))
 OSSL_CORE_MAKE_FUNC(size_t, get_nonce, (const OSSL_CORE_HANDLE *handle,
                                         unsigned char **pout, size_t min_len,
                                         size_t max_len, const void *salt,
                                         size_t salt_len))
+OSSL_CORE_MAKE_FUNC(size_t, get_user_nonce, (const OSSL_CORE_HANDLE *handle,
+                                             unsigned char **pout, size_t min_len,
+                                             size_t max_len, const void *salt,
+                                             size_t salt_len))
 OSSL_CORE_MAKE_FUNC(void, cleanup_nonce, (const OSSL_CORE_HANDLE *handle,
                                           unsigned char *buf, size_t len))
 

+ 8 - 0
providers/baseprov.c

@@ -19,6 +19,7 @@
 #include "prov/providercommon.h"
 #include "prov/implementations.h"
 #include "prov/provider_util.h"
+#include "prov/names.h"
 
 /*
  * Forward declarations to ensure that interface functions are correctly
@@ -90,6 +91,11 @@ static const OSSL_ALGORITHM base_store[] = {
 #undef STORE
 };
 
+static const OSSL_ALGORITHM base_rands[] = {
+    { PROV_NAMES_SEED_SRC, "provider=base", ossl_seed_src_functions },
+    { NULL, NULL, NULL }
+};
+
 static const OSSL_ALGORITHM *base_query(void *provctx, int operation_id,
                                          int *no_cache)
 {
@@ -101,6 +107,8 @@ static const OSSL_ALGORITHM *base_query(void *provctx, int operation_id,
         return base_decoder;
     case OSSL_OP_STORE:
         return base_store;
+    case OSSL_OP_RAND:
+        return base_rands;
     }
     return NULL;
 }

+ 43 - 10
providers/common/provider_seeding.c

@@ -9,12 +9,33 @@
 
 #include <openssl/core_dispatch.h>
 #include "prov/seeding.h"
+#include "prov/providercommon.h"
 
 static OSSL_FUNC_get_entropy_fn *c_get_entropy = NULL;
+static OSSL_FUNC_get_user_entropy_fn *c_get_user_entropy = NULL;
 static OSSL_FUNC_cleanup_entropy_fn *c_cleanup_entropy = NULL;
 static OSSL_FUNC_get_nonce_fn *c_get_nonce = NULL;
+static OSSL_FUNC_get_user_nonce_fn *c_get_user_nonce = NULL;
 static OSSL_FUNC_cleanup_nonce_fn *c_cleanup_nonce = NULL;
 
+#ifdef FIPS_MODULE
+/*
+ * The FIPS provider uses an internal library context which is what the
+ * passed provider context references.  Since the seed source is external
+ * to the FIPS provider, this is the wrong one.  We need to convert this
+ * to the correct core handle before up-calling libcrypto.
+ */
+# define CORE_HANDLE(provctx) \
+    FIPS_get_core_handle(ossl_prov_ctx_get0_libctx(provctx))
+#else
+/*
+ * The non-FIPS path *should* be unused because the full DRBG chain including
+ * seed source is instantiated.  However, that might not apply for third
+ * party providers, so this is retained for compatibility.
+ */
+# define CORE_HANDLE(provctx) ossl_prov_ctx_get0_handle(provctx)
+#endif
+
 int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns)
 {
     for (; fns->function_id != 0; fns++) {
@@ -29,12 +50,18 @@ int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns)
         case OSSL_FUNC_GET_ENTROPY:
             set_func(c_get_entropy, OSSL_FUNC_get_entropy(fns));
             break;
+        case OSSL_FUNC_GET_USER_ENTROPY:
+            set_func(c_get_user_entropy, OSSL_FUNC_get_user_entropy(fns));
+            break;
         case OSSL_FUNC_CLEANUP_ENTROPY:
             set_func(c_cleanup_entropy, OSSL_FUNC_cleanup_entropy(fns));
             break;
         case OSSL_FUNC_GET_NONCE:
             set_func(c_get_nonce, OSSL_FUNC_get_nonce(fns));
             break;
+        case OSSL_FUNC_GET_USER_NONCE:
+            set_func(c_get_user_nonce, OSSL_FUNC_get_user_nonce(fns));
+            break;
         case OSSL_FUNC_CLEANUP_NONCE:
             set_func(c_cleanup_nonce, OSSL_FUNC_cleanup_nonce(fns));
             break;
@@ -47,31 +74,37 @@ int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns)
 size_t ossl_prov_get_entropy(PROV_CTX *prov_ctx, unsigned char **pout,
                              int entropy, size_t min_len, size_t max_len)
 {
-    if (c_get_entropy == NULL)
-        return 0;
-    return c_get_entropy(ossl_prov_ctx_get0_handle(prov_ctx),
-                         pout, entropy, min_len, max_len);
+    const OSSL_CORE_HANDLE *handle = CORE_HANDLE(prov_ctx);
+
+    if (c_get_user_entropy != NULL)
+        return c_get_user_entropy(handle, pout, entropy, min_len, max_len);
+    if (c_get_entropy != NULL)
+        return c_get_entropy(handle, pout, entropy, min_len, max_len);
+    return 0;
 }
 
 void ossl_prov_cleanup_entropy(PROV_CTX *prov_ctx, unsigned char *buf,
                                size_t len)
 {
     if (c_cleanup_entropy != NULL)
-        c_cleanup_entropy(ossl_prov_ctx_get0_handle(prov_ctx), buf, len);
+        c_cleanup_entropy(CORE_HANDLE(prov_ctx), buf, len);
 }
 
 size_t ossl_prov_get_nonce(PROV_CTX *prov_ctx, unsigned char **pout,
                            size_t min_len, size_t max_len,
                            const void *salt, size_t salt_len)
 {
-    if (c_get_nonce == NULL)
-        return 0;
-    return c_get_nonce(ossl_prov_ctx_get0_handle(prov_ctx), pout,
-                       min_len, max_len, salt, salt_len);
+    const OSSL_CORE_HANDLE *handle = CORE_HANDLE(prov_ctx);
+
+    if (c_get_user_nonce != NULL)
+        return c_get_user_nonce(handle, pout, min_len, max_len, salt, salt_len);
+    if (c_get_nonce != NULL)
+        return c_get_nonce(handle, pout, min_len, max_len, salt, salt_len);
+    return 0;
 }
 
 void ossl_prov_cleanup_nonce(PROV_CTX *prov_ctx, unsigned char *buf, size_t len)
 {
     if (c_cleanup_nonce != NULL)
-        c_cleanup_nonce(ossl_prov_ctx_get0_handle(prov_ctx), buf, len);
+        c_cleanup_nonce(CORE_HANDLE(prov_ctx), buf, len);
 }