]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
rand: add a provider side seed source.
authorPauli <paul.dale@oracle.com>
Thu, 19 Nov 2020 22:45:34 +0000 (08:45 +1000)
committerPauli <paul.dale@oracle.com>
Wed, 9 Dec 2020 02:20:32 +0000 (12:20 +1000)
This allows the operating system sources that OpenSSL supports to be
used directly as RNGs.  It also allows DRBG seeding to be explicitly
specified rather than being left to a fall back case.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/13455)

crypto/err/openssl.txt
crypto/rand/rand_lib.c
doc/man5/config.pod
doc/man7/EVP_RAND-SEED-SRC.pod [new file with mode: 0644]
providers/common/include/prov/providercommonerr.h
providers/common/provider_err.c
providers/defltprov.c
providers/implementations/include/prov/implementations.h
providers/implementations/rands/build.info
providers/implementations/rands/seed_src.c [new file with mode: 0644]

index 491f3a7cdbe202646cecc045a84d4c3a0e96844c..73f551a3e51456b690227735d41cc57203508d23 100644 (file)
@@ -2933,6 +2933,8 @@ PROV_R_REQUIRE_CTR_MODE_CIPHER:206:require ctr mode cipher
 PROV_R_RESEED_ERROR:197:reseed error
 PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES:222:\
        search only supported for directories
+PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT:200:\
+       seed sources must not have a parent
 PROV_R_SELF_TEST_KAT_FAILURE:215:self test kat failure
 PROV_R_SELF_TEST_POST_FAILURE:216:self test post failure
 PROV_R_TAG_NOTSET:119:tag notset
index 73d509a8dc5f2417620eab4c3aad0ec05332d62c..2ad3cf776fd6bd50ae59d6939dc57993431ba6e3 100644 (file)
@@ -325,6 +325,8 @@ typedef struct rand_global_st {
      */
     CRYPTO_RWLOCK *lock;
 
+    EVP_RAND_CTX *seed;
+
     /*
      * The <primary> DRBG
      *
@@ -363,6 +365,10 @@ typedef struct rand_global_st {
     char *rng_cipher;
     char *rng_digest;
     char *rng_propq;
+
+    /* Allow the randomness source to be changed */
+    char *seed_name;
+    char *seed_propq;
 } RAND_GLOBAL;
 
 /*
@@ -412,13 +418,16 @@ static void rand_ossl_ctx_free(void *vdgbl)
         return;
 
     CRYPTO_THREAD_lock_free(dgbl->lock);
-    EVP_RAND_CTX_free(dgbl->primary);
     CRYPTO_THREAD_cleanup_local(&dgbl->private);
     CRYPTO_THREAD_cleanup_local(&dgbl->public);
+    EVP_RAND_CTX_free(dgbl->primary);
+    EVP_RAND_CTX_free(dgbl->seed);
     OPENSSL_free(dgbl->rng_name);
     OPENSSL_free(dgbl->rng_cipher);
     OPENSSL_free(dgbl->rng_digest);
     OPENSSL_free(dgbl->rng_propq);
+    OPENSSL_free(dgbl->seed_name);
+    OPENSSL_free(dgbl->seed_propq);
 
     OPENSSL_free(dgbl);
 }
@@ -452,6 +461,35 @@ static void rand_delete_thread_state(void *arg)
     EVP_RAND_CTX_free(rand);
 }
 
+#ifndef FIPS_MODULE
+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;
+
+    name = dgbl->seed_name != NULL ? dgbl->seed_name : "SEED-SRC";
+    rand = EVP_RAND_fetch(libctx, name, dgbl->seed_propq);
+    if (rand == NULL) {
+        ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG);
+        return NULL;
+    }
+    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;
+    }
+    if (!EVP_RAND_instantiate(ctx, 0, 0, NULL, 0)) {
+        ERR_raise(ERR_LIB_RAND, RAND_R_ERROR_INSTANTIATING_DRBG);
+        EVP_RAND_CTX_free(ctx);
+        return NULL;
+    }
+    return ctx;
+}
+#endif
+
 static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent,
                                    unsigned int reseed_interval,
                                    time_t reseed_time_interval)
@@ -522,8 +560,13 @@ EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
     if (dgbl->primary == NULL) {
         if (!CRYPTO_THREAD_write_lock(dgbl->lock))
             return NULL;
+#ifndef FIPS_MODULE
+        if (dgbl->seed == NULL)
+            dgbl->seed = rand_new_seed(ctx);
+#endif
         if (dgbl->primary == NULL)
-            dgbl->primary = rand_new_drbg(ctx, NULL, PRIMARY_RESEED_INTERVAL,
+            dgbl->primary = rand_new_drbg(ctx, dgbl->seed,
+                                          PRIMARY_RESEED_INTERVAL,
                                           PRIMARY_RESEED_TIME_INTERVAL);
         CRYPTO_THREAD_unlock(dgbl->lock);
     }
@@ -644,6 +687,12 @@ static int random_conf_init(CONF_IMODULE *md, const CONF *cnf)
         } else if (strcasecmp(cval->name, "properties") == 0) {
             if (!random_set_string(&dgbl->rng_propq, cval->value))
                 return 0;
+        } else if (strcasecmp(cval->name, "seed") == 0) {
+            if (!random_set_string(&dgbl->seed_name, cval->value))
+                return 0;
+        } else if (strcasecmp(cval->name, "seed_properties") == 0) {
+            if (!random_set_string(&dgbl->seed_propq, cval->value))
+                return 0;
         } else {
             ERR_raise_data(ERR_LIB_CRYPTO,
                            CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION,
index 0a28f4ea4b2731af565620c4c45ab38bf86f3778..45165f20ec60b3e12f23ac66cc60dcb8eec5b78f 100644 (file)
@@ -438,6 +438,16 @@ generators will use.  Other random bit generators ignore this name.
 This sets the property query used when fetching the random bit generator and
 any underlying algorithms.
 
+=item B<seed>
+
+This sets the randomness source that should be used.  By default B<SEED-SRC>
+will be used outside of the FIPS provider.  The FIPS provider uses call backs
+to access the same randomness sources from outside the validated boundary.
+
+=item B<seed_properties>
+
+This sets the property query used when fetching the randomness source.
+
 =back
 
 =head1 EXAMPLES
diff --git a/doc/man7/EVP_RAND-SEED-SRC.pod b/doc/man7/EVP_RAND-SEED-SRC.pod
new file mode 100644 (file)
index 0000000..f301ed2
--- /dev/null
@@ -0,0 +1,87 @@
+=pod
+
+=head1 NAME
+
+EVP_RAND-SEED-SRC - The randomness seed source EVP_RAND implementation
+
+=head1 DESCRIPTION
+
+Support for deterministic random number generator seeding through the
+B<EVP_RAND> API.
+
+The seed sources used are specified at the time OpenSSL is configured for
+building using the B<--with-rand-seed=> option.  By default, operating system
+randomness sources are used.
+
+=head2 Identity
+
+"SEED-SRC" is the name for this implementation; it can be used with the
+EVP_RAND_fetch() function.
+
+=head2 Supported parameters
+
+The supported parameters are:
+
+=over 4
+
+=item "state" (B<OSSL_RAND_PARAM_STATE>) <integer>
+
+=item "strength" (B<OSSL_RAND_PARAM_STRENGTH>) <unsigned integer>
+
+=item "max_request" (B<OSSL_RAND_PARAM_MAX_REQUEST>) <unsigned integer>
+
+These parameters work as described in L<EVP_RAND(3)/PARAMETERS>.
+
+=back
+
+=head1 NOTES
+
+A context for the seed source can be obtained by calling:
+
+ EVP_RAND *rand = EVP_RAND_fetch(NULL, "SEED-SRC", NULL);
+ EVP_RAND_CTX *rctx = EVP_RAND_CTX_new(rand);
+
+=head1 EXAMPLES
+
+ EVP_RAND *rand;
+ EVP_RAND_CTX *seed, *rctx;
+ unsigned char bytes[100];
+ OSSL_PARAM params[2], *p = params;
+ unsigned int strength = 128;
+
+ /* Create a seed source */
+ rand = EVP_RAND_fetch(NULL, "SEED-SRC", NULL);
+ seed = EVP_RAND_CTX_new(rand, NULL);
+ EVP_RAND_free(rand);
+
+ /* Feed this into a DRBG */
+ rand = EVP_RAND_fetch(NULL, "CTR-DRBG", NULL);
+ rctx = EVP_RAND_CTX_new(rand, seed);
+ EVP_RAND_free(rand);
+
+ /* Configure the DRBG */
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER,
+                                         SN_aes_256_ctr, 0);
+ *p = OSSL_PARAM_construct_end();
+ EVP_RAND_set_ctx_params(rctx, params);
+
+ EVP_RAND_generate(rctx, bytes, sizeof(bytes), strength, 0, NULL, 0);
+
+ EVP_RAND_CTX_free(rctx);
+ EVP_RAND_CTX_free(seed);
+
+=head1 SEE ALSO
+
+L<EVP_RAND(3)>,
+L<EVP_RAND(3)/PARAMETERS>
+
+=head1 COPYRIGHT
+
+Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
index ad1bd20c53966498391e56ba2d1a698d4729d8b8..f044e7b7c78b00c30c97d62cbc0270456fcbdf41 100644 (file)
@@ -154,6 +154,7 @@ int err_load_PROV_strings_int(void);
 # define PROV_R_REQUIRE_CTR_MODE_CIPHER                   206
 # define PROV_R_RESEED_ERROR                              197
 # define PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES     222
+# define PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT       200
 # define PROV_R_SELF_TEST_KAT_FAILURE                     215
 # define PROV_R_SELF_TEST_POST_FAILURE                    216
 # define PROV_R_TAG_NOTSET                                119
index fed6018387b3e3bbc9e82be0a948ce8cfab43e8e..3a28eaaa2dce01bf39d81e68e694abdfbab2f9a9 100644 (file)
@@ -175,6 +175,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_RESEED_ERROR), "reseed error"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES),
     "search only supported for directories"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT),
+    "seed sources must not have a parent"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_SELF_TEST_KAT_FAILURE),
     "self test kat failure"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_SELF_TEST_POST_FAILURE),
index 9a662738d895575adea487123090618fb20d2150..3cd7dffee80d9f1c6a1d99032ddc6015b287f6ca 100644 (file)
@@ -362,6 +362,7 @@ static const OSSL_ALGORITHM deflt_rands[] = {
     { "CTR-DRBG", "provider=default", ossl_drbg_ctr_functions },
     { "HASH-DRBG", "provider=default", ossl_drbg_hash_functions },
     { "HMAC-DRBG", "provider=default", ossl_drbg_ossl_hmac_functions },
+    { "SEED-SRC", "provider=default", ossl_seed_src_functions },
     { "TEST-RAND", "provider=default", ossl_test_rng_functions },
     { NULL, NULL, NULL }
 };
index 00178d4ceb4d779e9d138a6d1480685cb709fe74..5b6f9131311f52c134a856e5ddca29818754e419 100644 (file)
@@ -265,6 +265,7 @@ extern const OSSL_DISPATCH ossl_kdf_krb5kdf_functions[];
 
 /* RNGs */
 extern const OSSL_DISPATCH ossl_test_rng_functions[];
+extern const OSSL_DISPATCH ossl_seed_src_functions[];
 extern const OSSL_DISPATCH ossl_drbg_hash_functions[];
 extern const OSSL_DISPATCH ossl_drbg_ossl_hmac_functions[];
 extern const OSSL_DISPATCH ossl_drbg_ctr_functions[];
index 2ca0cdadc72650d60d0fe7e31cb00534713a68d0..b44c1caa8a7246d95881baf2a830d2ff3408abe4 100644 (file)
@@ -3,4 +3,4 @@ SUBDIRS=seeding
 $COMMON=drbg.c test_rng.c drbg_ctr.c drbg_hash.c drbg_hmac.c crngt.c
 
 SOURCE[../../libfips.a]=$COMMON
-SOURCE[../../libnonfips.a]=$COMMON
+SOURCE[../../libnonfips.a]=$COMMON seed_src.c
diff --git a/providers/implementations/rands/seed_src.c b/providers/implementations/rands/seed_src.c
new file mode 100644 (file)
index 0000000..7080e95
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/rand.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/e_os2.h>
+#include <openssl/params.h>
+#include <openssl/core_names.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/randerr.h>
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+#include "prov/providercommonerr.h"
+#include "crypto/rand.h"
+#include "crypto/rand_pool.h"
+
+static OSSL_FUNC_rand_newctx_fn seed_src_new;
+static OSSL_FUNC_rand_freectx_fn seed_src_free;
+static OSSL_FUNC_rand_instantiate_fn seed_src_instantiate;
+static OSSL_FUNC_rand_uninstantiate_fn seed_src_uninstantiate;
+static OSSL_FUNC_rand_generate_fn seed_src_generate;
+static OSSL_FUNC_rand_reseed_fn seed_src_reseed;
+static OSSL_FUNC_rand_gettable_ctx_params_fn seed_src_gettable_ctx_params;
+static OSSL_FUNC_rand_get_ctx_params_fn seed_src_get_ctx_params;
+static OSSL_FUNC_rand_verify_zeroization_fn seed_src_verify_zeroization;
+static OSSL_FUNC_rand_enable_locking_fn seed_src_enable_locking;
+
+typedef struct {
+    void *provctx;
+    int state;
+} PROV_SEED_SRC;
+
+static void *seed_src_new(void *provctx, void *parent,
+                          const OSSL_DISPATCH *parent_dispatch)
+{
+    PROV_SEED_SRC *s;
+
+    if (parent != NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT);
+        return NULL;
+    }
+
+    s = OPENSSL_zalloc(sizeof(*s));
+    if (s == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    s->provctx = provctx;
+    s->state = EVP_RAND_STATE_UNINITIALISED;
+    return s;
+}
+
+static void seed_src_free(void *vseed)
+{
+    OPENSSL_free(vseed);
+}
+
+static int seed_src_instantiate(void *vseed, unsigned int strength,
+                                int prediction_resistance,
+                                const unsigned char *pstr, size_t pstr_len)
+{
+    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
+
+    s->state = EVP_RAND_STATE_READY;
+    return 1;
+}
+
+static int seed_src_uninstantiate(void *vseed)
+{
+    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
+
+    s->state = EVP_RAND_STATE_UNINITIALISED;
+    return 1;
+}
+
+static int seed_src_generate(void *vseed, unsigned char *out, size_t outlen,
+                             unsigned int strength,
+                             ossl_unused int prediction_resistance,
+                             ossl_unused const unsigned char *adin,
+                             ossl_unused size_t adin_len)
+{
+    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
+    size_t entropy_available;
+    RAND_POOL *pool;
+
+    if (s->state != EVP_RAND_STATE_READY) {
+        ERR_raise(ERR_LIB_PROV,
+                  s->state == EVP_RAND_STATE_ERROR ? PROV_R_IN_ERROR_STATE
+                                                   : PROV_R_NOT_INSTANTIATED);
+        return 0;
+    }
+
+    pool = rand_pool_new(strength, 1, outlen, outlen);
+    if (pool == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    /* Get entropy by polling system entropy sources. */
+    entropy_available = ossl_pool_acquire_entropy(pool);
+
+    if (entropy_available > 0)
+        memcpy(out, rand_pool_detach(pool), rand_pool_length(pool));
+
+    rand_pool_free(pool);
+    return entropy_available > 0;
+}
+
+static int seed_src_reseed(void *vseed,
+                           ossl_unused int prediction_resistance,
+                           ossl_unused const unsigned char *ent,
+                           ossl_unused size_t ent_len,
+                           ossl_unused const unsigned char *adin,
+                           ossl_unused size_t adin_len)
+{
+    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
+
+    if (s->state != EVP_RAND_STATE_READY) {
+        ERR_raise(ERR_LIB_PROV,
+                  s->state == EVP_RAND_STATE_ERROR ? PROV_R_IN_ERROR_STATE
+                                                   : PROV_R_NOT_INSTANTIATED);
+        return 0;
+    }
+    return 1;
+}
+
+static int seed_src_get_ctx_params(void *vseed, OSSL_PARAM params[])
+{
+    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
+    OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE);
+    if (p != NULL && !OSSL_PARAM_set_int(p, s->state))
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH);
+    if (p != NULL && !OSSL_PARAM_set_int(p, 1024))
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, 128))
+        return 0;
+    return 1;
+}
+
+static const OSSL_PARAM *seed_src_gettable_ctx_params(ossl_unused void *provctx)
+{
+    static const OSSL_PARAM known_gettable_ctx_params[] = {
+        OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL),
+        OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL),
+        OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL),
+        OSSL_PARAM_END
+    };
+    return known_gettable_ctx_params;
+}
+
+static int seed_src_verify_zeroization(ossl_unused void *vseed)
+{
+    return 1;
+}
+
+static int seed_src_enable_locking(ossl_unused void *vseed)
+{
+    return 1;
+}
+
+const OSSL_DISPATCH ossl_seed_src_functions[] = {
+    { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))seed_src_new },
+    { OSSL_FUNC_RAND_FREECTX, (void(*)(void))seed_src_free },
+    { OSSL_FUNC_RAND_INSTANTIATE,
+      (void(*)(void))seed_src_instantiate },
+    { OSSL_FUNC_RAND_UNINSTANTIATE,
+      (void(*)(void))seed_src_uninstantiate },
+    { OSSL_FUNC_RAND_GENERATE, (void(*)(void))seed_src_generate },
+    { OSSL_FUNC_RAND_RESEED, (void(*)(void))seed_src_reseed },
+    { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))seed_src_enable_locking },
+    { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,
+      (void(*)(void))seed_src_gettable_ctx_params },
+    { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))seed_src_get_ctx_params },
+    { OSSL_FUNC_RAND_VERIFY_ZEROIZATION,
+      (void(*)(void))seed_src_verify_zeroization },
+    { 0, NULL }
+};