crypto: drbg - Do not seed RNG in drbg_kcapi_init
authorHerbert Xu <herbert@gondor.apana.org.au>
Mon, 20 Apr 2015 03:29:15 +0000 (11:29 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Tue, 21 Apr 2015 02:19:53 +0000 (10:19 +0800)
Initialising the RNG in drbg_kcapi_init is a waste of precious
entropy because all users will immediately seed the RNG after
the allocation.

In fact, all users should seed the RNG before using it.  So there
is no point in doing the seeding in drbg_kcapi_init.

This patch removes the initial seeding and the user must seed
the RNG explicitly (as they all currently do).

This patch also changes drbg_kcapi_reset to allow reseeding.
That is, if you call it after a successful initial seeding, then
it will not reset the internal state of the DRBG before mixing
the new input and entropy.

If you still wish to reset the internal state, you can always
free the DRBG and allocate a new one.

Finally this patch removes locking from drbg_uninstantiate because
it's now only called from the destruction path which must not be
executed in parallel with normal operations.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: Stephan Mueller <smueller@chronox.de>
crypto/drbg.c

index 57fd479b8f777f927d7f4b2690c91e6679817956..5bce15918de5ffb808c6b6d06c0cb2196be09cf0 100644 (file)
@@ -1136,6 +1136,8 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
        kzfree(drbg->scratchpad);
        drbg->scratchpad = NULL;
        drbg->reseed_ctr = 0;
+       drbg->d_ops = NULL;
+       drbg->core = NULL;
 #ifdef CONFIG_CRYPTO_FIPS
        kzfree(drbg->prev);
        drbg->prev = NULL;
@@ -1152,6 +1154,27 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
        int ret = -ENOMEM;
        unsigned int sb_size = 0;
 
+       switch (drbg->core->flags & DRBG_TYPE_MASK) {
+#ifdef CONFIG_CRYPTO_DRBG_HMAC
+       case DRBG_HMAC:
+               drbg->d_ops = &drbg_hmac_ops;
+               break;
+#endif /* CONFIG_CRYPTO_DRBG_HMAC */
+#ifdef CONFIG_CRYPTO_DRBG_HASH
+       case DRBG_HASH:
+               drbg->d_ops = &drbg_hash_ops;
+               break;
+#endif /* CONFIG_CRYPTO_DRBG_HASH */
+#ifdef CONFIG_CRYPTO_DRBG_CTR
+       case DRBG_CTR:
+               drbg->d_ops = &drbg_ctr_ops;
+               break;
+#endif /* CONFIG_CRYPTO_DRBG_CTR */
+       default:
+               ret = -EOPNOTSUPP;
+               goto err;
+       }
+
        drbg->V = kmalloc(drbg_statelen(drbg), GFP_KERNEL);
        if (!drbg->V)
                goto err;
@@ -1215,6 +1238,10 @@ static int drbg_generate(struct drbg_state *drbg,
        int len = 0;
        LIST_HEAD(addtllist);
 
+       if (!drbg->core) {
+               pr_devel("DRBG: not yet seeded\n");
+               return -EINVAL;
+       }
        if (0 == buflen || !buf) {
                pr_devel("DRBG: no output buffer provided\n");
                return -EINVAL;
@@ -1372,33 +1399,12 @@ static int drbg_generate_long(struct drbg_state *drbg,
 static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
                            int coreref, bool pr)
 {
-       int ret = -EOPNOTSUPP;
+       int ret;
+       bool reseed = true;
 
        pr_devel("DRBG: Initializing DRBG core %d with prediction resistance "
                 "%s\n", coreref, pr ? "enabled" : "disabled");
        mutex_lock(&drbg->drbg_mutex);
-       drbg->core = &drbg_cores[coreref];
-       drbg->pr = pr;
-       drbg->seeded = false;
-       switch (drbg->core->flags & DRBG_TYPE_MASK) {
-#ifdef CONFIG_CRYPTO_DRBG_HMAC
-       case DRBG_HMAC:
-               drbg->d_ops = &drbg_hmac_ops;
-               break;
-#endif /* CONFIG_CRYPTO_DRBG_HMAC */
-#ifdef CONFIG_CRYPTO_DRBG_HASH
-       case DRBG_HASH:
-               drbg->d_ops = &drbg_hash_ops;
-               break;
-#endif /* CONFIG_CRYPTO_DRBG_HASH */
-#ifdef CONFIG_CRYPTO_DRBG_CTR
-       case DRBG_CTR:
-               drbg->d_ops = &drbg_ctr_ops;
-               break;
-#endif /* CONFIG_CRYPTO_DRBG_CTR */
-       default:
-               goto unlock;
-       }
 
        /* 9.1 step 1 is implicit with the selected DRBG type */
 
@@ -1410,21 +1416,31 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
 
        /* 9.1 step 4 is implicit in  drbg_sec_strength */
 
-       ret = drbg_alloc_state(drbg);
-       if (ret)
-               goto unlock;
+       if (!drbg->core) {
+               drbg->core = &drbg_cores[coreref];
+               drbg->pr = pr;
+               drbg->seeded = false;
 
-       ret = -EFAULT;
-       if (drbg->d_ops->crypto_init(drbg))
-               goto err;
-       ret = drbg_seed(drbg, pers, false);
-       if (ret) {
+               ret = drbg_alloc_state(drbg);
+               if (ret)
+                       goto unlock;
+
+               ret = -EFAULT;
+               if (drbg->d_ops->crypto_init(drbg))
+                       goto err;
+
+               reseed = false;
+       }
+
+       ret = drbg_seed(drbg, pers, reseed);
+
+       if (ret && !reseed) {
                drbg->d_ops->crypto_fini(drbg);
                goto err;
        }
 
        mutex_unlock(&drbg->drbg_mutex);
-       return 0;
+       return ret;
 
 err:
        drbg_dealloc_state(drbg);
@@ -1444,11 +1460,10 @@ unlock:
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-       mutex_lock(&drbg->drbg_mutex);
-       drbg->d_ops->crypto_fini(drbg);
+       if (drbg->d_ops)
+               drbg->d_ops->crypto_fini(drbg);
        drbg_dealloc_state(drbg);
        /* no scrubbing of test_data -- this shall survive an uninstantiate */
-       mutex_unlock(&drbg->drbg_mutex);
        return 0;
 }
 
@@ -1615,16 +1630,10 @@ static inline void drbg_convert_tfm_core(const char *cra_driver_name,
 static int drbg_kcapi_init(struct crypto_tfm *tfm)
 {
        struct drbg_state *drbg = crypto_tfm_ctx(tfm);
-       bool pr = false;
-       int coreref = 0;
 
        mutex_init(&drbg->drbg_mutex);
-       drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm), &coreref, &pr);
-       /*
-        * when personalization string is needed, the caller must call reset
-        * and provide the personalization string as seed information
-        */
-       return drbg_instantiate(drbg, NULL, coreref, pr);
+
+       return 0;
 }
 
 static void drbg_kcapi_cleanup(struct crypto_tfm *tfm)
@@ -1665,10 +1674,9 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, u8 *rdata,
 }
 
 /*
- * Reset the DRBG invoked by the kernel crypto API
- * The reset implies a full re-initialization of the DRBG. Similar to the
- * generate function of drbg_kcapi_random, this function extends the
- * kernel crypto API interface with struct drbg_gen
+ * Seed the DRBG invoked by the kernel crypto API
+ * Similar to the generate function of drbg_kcapi_random, this
+ * function extends the kernel crypto API interface with struct drbg_gen
  */
 static int drbg_kcapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
 {
@@ -1678,7 +1686,6 @@ static int drbg_kcapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
        struct drbg_string seed_string;
        int coreref = 0;
 
-       drbg_uninstantiate(drbg);
        drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm_base), &coreref,
                              &pr);
        if (0 < slen) {