crypto: drbg - prepare for more fine-grained tracking of seeding state
authorNicolai Stange <nstange@suse.de>
Thu, 2 Jun 2022 20:22:29 +0000 (22:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 25 Jun 2022 09:46:41 +0000 (11:46 +0200)
commit ce8ce31b2c5c8b18667784b8c515650c65d57b4e upstream.

There are two different randomness sources the DRBGs are getting seeded
from, namely the jitterentropy source (if enabled) and get_random_bytes().
At initial DRBG seeding time during boot, the latter might not have
collected sufficient entropy for seeding itself yet and thus, the DRBG
implementation schedules a reseed work from a random_ready_callback once
that has happened. This is particularly important for the !->pr DRBG
instances, for which (almost) no further reseeds are getting triggered
during their lifetime.

Because collecting data from the jitterentropy source is a rather expensive
operation, the aforementioned asynchronously scheduled reseed work
restricts itself to get_random_bytes() only. That is, it in some sense
amends the initial DRBG seed derived from jitterentropy output at full
(estimated) entropy with fresh randomness obtained from get_random_bytes()
once that has been seeded with sufficient entropy itself.

With the advent of rng_is_initialized(), there is no real need for doing
the reseed operation from an asynchronously scheduled work anymore and a
subsequent patch will make it synchronous by moving it next to related
logic already present in drbg_generate().

However, for tracking whether a full reseed including the jitterentropy
source is required or a "partial" reseed involving only get_random_bytes()
would be sufficient already, the boolean struct drbg_state's ->seeded
member must become a tristate value.

Prepare for this by introducing the new enum drbg_seed_state and change
struct drbg_state's ->seeded member's type from bool to that type.

For facilitating review, enum drbg_seed_state is made to only contain
two members corresponding to the former ->seeded values of false and true
resp. at this point: DRBG_SEED_STATE_UNSEEDED and DRBG_SEED_STATE_FULL. A
third one for tracking the intermediate state of "seeded from jitterentropy
only" will be introduced with a subsequent patch.

There is no change in behaviour at this point.

Signed-off-by: Nicolai Stange <nstange@suse.de>
Reviewed-by: Stephan Müller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
crypto/drbg.c
include/crypto/drbg.h

index b55a3bc181ad0d04028bdf6ce8c988268d7a886f..c618550f65f7944741dd1d619f97abe77749ee67 100644 (file)
@@ -1044,7 +1044,7 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,
        if (ret)
                return ret;
 
-       drbg->seeded = true;
+       drbg->seeded = DRBG_SEED_STATE_FULL;
        /* 10.1.1.2 / 10.1.1.3 step 5 */
        drbg->reseed_ctr = 1;
 
@@ -1089,14 +1089,14 @@ static void drbg_async_seed(struct work_struct *work)
        if (ret)
                goto unlock;
 
-       /* Set seeded to false so that if __drbg_seed fails the
-        * next generate call will trigger a reseed.
+       /* Reset ->seeded so that if __drbg_seed fails the next
+        * generate call will trigger a reseed.
         */
-       drbg->seeded = false;
+       drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
 
        __drbg_seed(drbg, &seedlist, true);
 
-       if (drbg->seeded)
+       if (drbg->seeded == DRBG_SEED_STATE_FULL)
                drbg->reseed_threshold = drbg_max_requests(drbg);
 
 unlock:
@@ -1385,13 +1385,14 @@ static int drbg_generate(struct drbg_state *drbg,
         * here. The spec is a bit convoluted here, we make it simpler.
         */
        if (drbg->reseed_threshold < drbg->reseed_ctr)
-               drbg->seeded = false;
+               drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
 
-       if (drbg->pr || !drbg->seeded) {
+       if (drbg->pr || drbg->seeded == DRBG_SEED_STATE_UNSEEDED) {
                pr_devel("DRBG: reseeding before generation (prediction "
                         "resistance: %s, state %s)\n",
                         drbg->pr ? "true" : "false",
-                        drbg->seeded ? "seeded" : "unseeded");
+                        (drbg->seeded ==  DRBG_SEED_STATE_FULL ?
+                         "seeded" : "unseeded"));
                /* 9.3.1 steps 7.1 through 7.3 */
                len = drbg_seed(drbg, addtl, true);
                if (len)
@@ -1576,7 +1577,7 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
        if (!drbg->core) {
                drbg->core = &drbg_cores[coreref];
                drbg->pr = pr;
-               drbg->seeded = false;
+               drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
                drbg->reseed_threshold = drbg_max_requests(drbg);
 
                ret = drbg_alloc_state(drbg);
index d94e6d33ee218e3962859630bcfdffceebdbdabd..f3667c2ec0e50b4789342b479f226ee64cd20434 100644 (file)
@@ -105,6 +105,11 @@ struct drbg_test_data {
        struct drbg_string *testentropy; /* TEST PARAMETER: test entropy */
 };
 
+enum drbg_seed_state {
+       DRBG_SEED_STATE_UNSEEDED,
+       DRBG_SEED_STATE_FULL,
+};
+
 struct drbg_state {
        struct mutex drbg_mutex;        /* lock around DRBG */
        unsigned char *V;       /* internal state 10.1.1.1 1a) */
@@ -129,7 +134,7 @@ struct drbg_state {
        struct completion ctr_completion;       /* CTR mode async handler */
        int ctr_async_err;                      /* CTR mode async error */
 
-       bool seeded;            /* DRBG fully seeded? */
+       enum drbg_seed_state seeded;            /* DRBG fully seeded? */
        bool pr;                /* Prediction resistance enabled? */
        bool fips_primed;       /* Continuous test primed? */
        unsigned char *prev;    /* FIPS 140-2 continuous test value */