]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
s390/crypto: use TRNG for seeding/reseeding
authorHarald Freudenberger <freude@linux.ibm.com>
Tue, 16 Apr 2019 11:41:26 +0000 (13:41 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 25 Apr 2019 13:34:09 +0000 (15:34 +0200)
With the z14 machine there came also a CPACF hardware extension
which provides a True Random Number Generator. This TRNG can
be accessed with a new subfunction code within the CPACF prno
instruction and provides random data with very high entropy.

So if there is a TRNG available, let's use it for initial seeding
and reseeding instead of the current implementation which tries
to generate entropy based on stckf (store clock fast) jitters.

For details about the amount of data needed and pulled for
seeding and reseeding there can be explaining comments in the
code found.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/crypto/prng.c

index fba37906045b18fc294be935909f573c64179439..12cca467af7d101cd53d10b4c54815f7190a6364 100644 (file)
@@ -61,6 +61,7 @@ static unsigned int prng_reseed_limit;
 module_param_named(reseed_limit, prng_reseed_limit, int, 0);
 MODULE_PARM_DESC(prng_reseed_limit, "PRNG reseed limit");
 
+static bool trng_available;
 
 /*
  * Any one who considers arithmetical methods of producing random digits is,
@@ -366,7 +367,7 @@ static int __init prng_sha512_selftest(void)
 
 static int __init prng_sha512_instantiate(void)
 {
-       int ret, datalen;
+       int ret, datalen, seedlen;
        u8 seed[128 + 16];
 
        pr_debug("prng runs in SHA-512 mode "
@@ -390,21 +391,35 @@ static int __init prng_sha512_instantiate(void)
        if (ret)
                goto outfree;
 
-       /*
-        * generate initial seed bytestring, we need at least
-        * 256 + 128 bits entropy. However, the generate_entropy()
-        * function anyway works in 64 byte junks so we pull
-        * 2*64 bytes here.
-        */
-       ret = generate_entropy(seed, 128);
-       if (ret != 128)
-               goto outfree;
-       /* followed by 16 bytes of unique nonce */
-       get_tod_clock_ext(seed + 128);
+       /* generate initial seed, we need at least  256 + 128 bits entropy. */
+       if (trng_available) {
+               /*
+                * Trng available, so use it. The trng works in chunks of
+                * 32 bytes and produces 100% entropy. So we pull 64 bytes
+                * which gives us 512 bits entropy.
+                */
+               seedlen = 2 * 32;
+               cpacf_trng(NULL, 0, seed, seedlen);
+       } else {
+               /*
+                * No trng available, so use the generate_entropy() function.
+                * This function works in 64 byte junks and produces
+                * 50% entropy. So we pull 2*64 bytes which gives us 512 bits
+                * of entropy.
+                */
+               seedlen = 2 * 64;
+               ret = generate_entropy(seed, seedlen);
+               if (ret != seedlen)
+                       goto outfree;
+       }
 
-       /* initial seed of the prno drng */
+       /* append the seed by 16 bytes of unique nonce */
+       get_tod_clock_ext(seed + seedlen);
+       seedlen += 16;
+
+       /* now initial seed of the prno drng */
        cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED,
-                  &prng_data->prnows, NULL, 0, seed, sizeof(seed));
+                  &prng_data->prnows, NULL, 0, seed, seedlen);
        memzero_explicit(seed, sizeof(seed));
 
        /* if fips mode is enabled, generate a first block of random
@@ -433,17 +448,25 @@ static void prng_sha512_deinstantiate(void)
 
 static int prng_sha512_reseed(void)
 {
-       int ret;
+       int ret, seedlen;
        u8 seed[64];
 
-       /* fetch 256 bits of fresh entropy */
-       ret = generate_entropy(seed, sizeof(seed));
-       if (ret != sizeof(seed))
-               return ret;
+       /* We need at least 256 bits of fresh entropy for reseeding */
+       if (trng_available) {
+               /* trng produces 256 bits entropy in 32 bytes */
+               seedlen = 32;
+               cpacf_trng(NULL, 0, seed, seedlen);
+       } else {
+               /* generate_entropy() produces 256 bits entropy in 64 bytes */
+               seedlen = 64;
+               ret = generate_entropy(seed, seedlen);
+               if (ret != sizeof(seed))
+                       return ret;
+       }
 
        /* do a reseed of the prno drng with this bytestring */
        cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED,
-                  &prng_data->prnows, NULL, 0, seed, sizeof(seed));
+                  &prng_data->prnows, NULL, 0, seed, seedlen);
        memzero_explicit(seed, sizeof(seed));
 
        return 0;
@@ -803,6 +826,10 @@ static int __init prng_init(void)
        if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG))
                return -EOPNOTSUPP;
 
+       /* check if TRNG subfunction is available */
+       if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG))
+               trng_available = true;
+
        /* choose prng mode */
        if (prng_mode != PRNG_MODE_TDES) {
                /* check for MSA5 support for PRNO operations */