kern_nrandom, rnd drivers: update for new CSPRNG
authorAlex Hornung <alex@alexhornung.com>
Mon, 14 Jul 2014 07:53:06 +0000 (08:53 +0100)
committerAlex Hornung <alex@alexhornung.com>
Mon, 14 Jul 2014 10:21:12 +0000 (11:21 +0100)
 * Identify each source of entropy with an identifier, so that
   for example the Fortuna CSPRNG can manage the pool index
   for each source.

 * Add a new sysctl, kern.rand_mode, which can be used to select
   which generator is used for /dev/random; valid values are:
    - csprng (to use only the Fortuna-based CSPRNG)
    - ibaa (to use only IBAA)
    - mixed (to XOR both csprng and ibaa in the output stream
   It defaults to "mixed".

sys/dev/crypto/glxsb/glxsb.c
sys/dev/crypto/hifn/hifn7751.c
sys/dev/crypto/padlock/padlock_rng.c
sys/dev/crypto/rdrand/rdrand.c
sys/dev/crypto/safe/safe.c
sys/dev/crypto/ubsec/ubsec.c
sys/kern/kern_memio.c
sys/kern/kern_nrandom.c
sys/sys/random.h

index bd3f217..17f15d7 100644 (file)
@@ -488,7 +488,8 @@ glxsb_rnd(void *v)
        if (status & SB_RNS_TRNG_VALID) {
                value = bus_read_4(sc->sc_sr, SB_RANDOM_NUM);
                /* feed with one uint32 */
-               add_buffer_randomness((const char *)&value, sizeof(value));
+               add_buffer_randomness_src((const char *)&value, sizeof(value),
+                   RAND_SRC_GLXSB);
        }
 
        callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc);
index 1441c23..4379561 100644 (file)
@@ -256,7 +256,7 @@ hifn_partname(struct hifn_softc *sc)
 static void
 default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
 {
-       add_buffer_randomness(buf, count);
+       add_buffer_randomness_src(buf, count, RAND_SRC_HIFN);
 }
 
 static u_int
index 6aa37c2..f1e00b4 100644 (file)
@@ -51,7 +51,7 @@ padlock_rng_harvest(void *arg)
        arandomness = PADLOCK_ALIGN(randomness);
        cnt = padlock_rng(arandomness, PADLOCK_RNDBYTES);
 
-       add_buffer_randomness(arandomness, cnt);
+       add_buffer_randomness_src(arandomness, cnt, RAND_SRC_PADLOCK);
 
        callout_reset(&sc->sc_rng_co, sc->sc_rng_ticks,
            padlock_rng_harvest, sc);
index 9f259aa..65408ff 100644 (file)
@@ -125,7 +125,7 @@ rdrand_rng_harvest(void *arg)
 
        cnt = rdrand_rng(arandomness, RDRAND_SIZE);
        if (cnt > 0 && cnt < sizeof(randomness)) {
-               add_buffer_randomness(arandomness, cnt);
+               add_buffer_randomness_src(arandomness, cnt, RAND_SRC_RDRAND);
 
                if (rdrand_debug) {
                        kprintf("rdrand(%d): %02x %02x %02x %02x...\n",
index 3e10478..7eef940 100644 (file)
@@ -210,7 +210,7 @@ safe_partname(struct safe_softc *sc)
 static void
 default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
 {
-       add_buffer_randomness(buf, count);
+       add_buffer_randomness_src(buf, count, RAND_SRC_SAFE);
 }
 #endif /* SAFE_NO_RNG */
 
index 61101ff..acdcafe 100644 (file)
@@ -258,7 +258,7 @@ ubsec_partname(struct ubsec_softc *sc)
 static void
 default_harvest(struct rndtest_state *rsp __unused, void *buf, u_int count)
 {
-       add_buffer_randomness(buf, count);
+       add_buffer_randomness_src(buf, count, RAND_SRC_UBSEC);
 }
 
 static int
index af98f03..3f3d46c 100644 (file)
@@ -241,7 +241,7 @@ mmrw(cdev_t dev, struct uio *uio, int flags)
                                if (error == 0 &&
                                    seedenable &&
                                    securelevel <= 0) {
-                                       error = add_buffer_randomness(buf, c);
+                                       error = add_buffer_randomness_src(buf, c, RAND_SRC_SEEDING);
                                } else if (error == 0) {
                                        error = EPERM;
                                }
index d4c358e..944b5f7 100644 (file)
@@ -1,5 +1,10 @@
 /*
- * Copyright (c) 2004, 2005, 2006 Robin J Carey. All rights reserved.
+ * Copyright (c) 2004-2014 The DragonFly Project. All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ * by Alex Hornung <alex@alexhornung.com>
+ * by Robin J Carey
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * o Added missing (u_char *) cast in RnddevRead() function.
  * o Changed copyright to 3-clause BSD license and cleaned up the layout
  *   of this file.
+ *
+ * For a proper changelog, refer to the version control history of this
+ * file.
  */
 
 #include <sys/types.h>
 #include <sys/lock.h>
 #include <sys/sysctl.h>
 #include <sys/spinlock.h>
+#include <sys/csprng.h>
+#include <machine/atomic.h>
 #include <machine/clock.h>
 
 #include <sys/thread2.h>
 #include <sys/spinlock2.h>
 #include <sys/mplock2.h>
 
+
+struct csprng_state csprng_state;
+
 /*
  * Portability note: The u_char/unsigned char type is used where
  * uint8_t from <stdint.h> or u_int8_t from <sys/types.h> should really
@@ -255,6 +268,24 @@ IBAA_Seed (const u_int32_t val)
        ++memIndex;
 }
 
+static void
+IBAA_Vector (const char *buf, int bytes)
+{
+       int i;
+
+       while (bytes >= sizeof(int)) {
+               IBAA_Seed(*(const int *)buf);
+               buf += sizeof(int);
+               bytes -= sizeof(int);
+       }
+
+       /*
+        * Warm up the generator to get rid of weak initial states.
+        */
+       for (i = 0; i < 10; ++i)
+               IBAA_Call();
+}
+
 /*
  * Extract a byte from IBAAs 256 32-bit u4 results array. 
  *
@@ -395,7 +426,7 @@ L15_Vector (const LByteType * const key, const size_t keyLen)
  *                             KERNEL INTERFACE                        *
  ************************************************************************
  *
- * By Robin J Carey and Matthew Dillon.
+ * By Robin J Carey, Matthew Dillon and Alex Hornung.
  */
 
 static int rand_thread_signal = 1;
@@ -406,9 +437,16 @@ static struct spinlock rand_spin;
 static int sysctl_kern_random(SYSCTL_HANDLER_ARGS);
 
 static int nrandevents;
+static int rand_mode = 2;
+
+static int sysctl_kern_rand_mode(SYSCTL_HANDLER_ARGS);
+
 SYSCTL_INT(_kern, OID_AUTO, nrandevents, CTLFLAG_RD, &nrandevents, 0, "");
 SYSCTL_PROC(_kern, OID_AUTO, random, CTLFLAG_RD | CTLFLAG_ANYBODY, 0, 0,
                sysctl_kern_random, "I", "Acquire random data");
+SYSCTL_PROC(_kern, OID_AUTO, rand_mode, CTLTYPE_STRING | CTLFLAG_RW, NULL, 0,
+    sysctl_kern_rand_mode, "A", "RNG mode (csprng, ibaa or mixed)");
+
 
 /*
  * Called from early boot
@@ -419,6 +457,17 @@ rand_initialize(void)
        struct timespec now;
        int i;
 
+       csprng_init(&csprng_state);
+#if 0
+       /*
+        * XXX: we do the reseeding when someone uses the RNG instead
+        * of regularly using init_reseed (which initializes a callout)
+        * to avoid unnecessary and regular reseeding.
+        */
+       csprng_init_reseed(&csprng_state);
+#endif
+
+
        spin_init(&rand_spin);
 
        /* Initialize IBAA. */
@@ -429,13 +478,11 @@ rand_initialize(void)
        L15((const LByteType *)&now.tv_nsec, sizeof(now.tv_nsec));
        for (i = 0; i < (SIZE / 2); ++i) {
                nanotime(&now);
-               IBAA_Seed(now.tv_nsec);
-               L15_Vector((const LByteType *)&now.tv_nsec,
-                          sizeof(now.tv_nsec));
+               add_buffer_randomness_src((const uint8_t *)&now.tv_nsec,
+                   sizeof(now.tv_nsec), RAND_SRC_TIMING);
                nanouptime(&now);
-               IBAA_Seed(now.tv_nsec);
-               L15_Vector((const LByteType *)&now.tv_nsec,
-                          sizeof(now.tv_nsec));
+               add_buffer_randomness_src((const uint8_t *)&now.tv_nsec,
+                   sizeof(now.tv_nsec), RAND_SRC_TIMING);
        }
 
        /*
@@ -472,36 +519,40 @@ add_interrupt_randomness(int intr)
 /*
  * True random number source
  */
-void
-add_true_randomness(int val)
+int
+add_buffer_randomness(const char *buf, int bytes)
 {
        spin_lock(&rand_spin);
-       IBAA_Seed(val);
-       L15_Vector((const LByteType *) &val, sizeof (val));
-       ++nrandevents;
+       L15_Vector((const LByteType *)buf, bytes);
+       IBAA_Vector(buf, bytes);
        spin_unlock(&rand_spin);
+
+       atomic_add_int(&nrandevents, 1);
+
+       csprng_add_entropy(&csprng_state, RAND_SRC_UNKNOWN,
+           (const uint8_t *)buf, bytes, 0);
+
+       return 0;
 }
 
+
 int
-add_buffer_randomness(const char *buf, int bytes)
+add_buffer_randomness_src(const char *buf, int bytes, int srcid)
 {
-       int i;
+       spin_lock(&rand_spin);
+       L15_Vector((const LByteType *)buf, bytes);
+       IBAA_Vector(buf, bytes);
+       spin_unlock(&rand_spin);
 
-       while (bytes >= sizeof(int)) {
-               add_true_randomness(*(const int *)buf);
-               buf += sizeof(int);
-               bytes -= sizeof(int);
-       }
+       atomic_add_int(&nrandevents, 1);
 
-       /*
-        * Warm up the generator to get rid of weak initial states.
-        */
-       for (i = 0; i < 10; ++i)
-               IBAA_Call();
+       csprng_add_entropy(&csprng_state, srcid & 0xff,
+           (const uint8_t *)buf, bytes, 0);
 
        return 0;
 }
 
+
 /*
  * Kqueue filter (always succeeds)
  */
@@ -520,14 +571,28 @@ random_filter_read(struct knote *kn, long hint)
 u_int
 read_random(void *buf, u_int nbytes)
 {
-       u_int i;
+       int i, j;
+
+       if (rand_mode == 0) {
+               /* Only use CSPRNG */
+               i = csprng_get_random(&csprng_state, buf, nbytes, 0);
+       } else if (rand_mode == 1) {
+               /* Only use IBAA */
+               spin_lock(&rand_spin);
+               for (i = 0; i < nbytes; i++)
+                       ((u_char *)buf)[i] = IBAA_Byte();
+               spin_unlock(&rand_spin);
+       } else {
+               /* Mix both CSPRNG and IBAA */
+               i = csprng_get_random(&csprng_state, buf, nbytes, 0);
+               spin_lock(&rand_spin);
+               for (j = 0; j < i; j++)
+                       ((u_char *)buf)[j] ^= IBAA_Byte();
+               spin_unlock(&rand_spin);
+       }
 
-       spin_lock(&rand_spin);
-       for (i = 0; i < nbytes; ++i)
-               ((u_char *)buf)[i] = IBAA_Byte();
-       spin_unlock(&rand_spin);
        add_interrupt_randomness(0);
-       return (i);
+       return (i > 0) ? i : 0;
 }
 
 /*
@@ -574,6 +639,49 @@ sysctl_kern_random(SYSCTL_HANDLER_ARGS)
        return(error);
 }
 
+/*
+ * Change the random mode via sysctl().
+ */
+static
+const char *
+rand_mode_to_str(int mode)
+{
+       switch (mode) {
+       case 0:
+               return "csprng";
+       case 1:
+               return "ibaa";
+       case 2:
+               return "mixed";
+       default:
+               return "unknown";
+       }
+}
+
+static
+int
+sysctl_kern_rand_mode(SYSCTL_HANDLER_ARGS)
+{
+       char mode[32];
+       int error;
+
+       strncpy(mode, rand_mode_to_str(rand_mode), sizeof(mode)-1);
+       error = sysctl_handle_string(oidp, mode, sizeof(mode), req);
+       if (error || req->newptr == NULL)
+           return error;
+
+       if ((strncmp(mode, "csprng", sizeof(mode))) == 0)
+               rand_mode = 0;
+       else if ((strncmp(mode, "ibaa", sizeof(mode))) == 0)
+               rand_mode = 1;
+       else if ((strncmp(mode, "mixed", sizeof(mode))) == 0)
+               rand_mode = 2;
+       else
+               error = EINVAL;
+
+       return error;
+}
+
 /*
  * Random number generator helper thread.  This limits code overhead from
  * high frequency events by delaying the clearing of rand_thread_signal.
@@ -630,7 +738,6 @@ NANOUP_EVENT(void)
        static struct timespec  ACCUM = { 0, 0 };
        static struct timespec  NEXT  = { 0, 0 };
        struct timespec         now;
-       int i;
 
        nanouptime(&now);
        spin_lock(&rand_spin);
@@ -655,17 +762,10 @@ NANOUP_EVENT(void)
                if (tsc_present)
                        ACCUM.tv_nsec ^= rdtsc() & 255;
 
-               IBAA_Seed(ACCUM.tv_nsec);
-               L15_Vector((const LByteType *)&ACCUM.tv_nsec,
-                          sizeof(ACCUM.tv_nsec));
-
-               /*
-                * Run another warm-up to get rid of weak inital states
-                * introduced by the seeding.
-                */
-               for (i = 0; i < 10; ++i)
-                       IBAA_Call();
-               ++nrandevents;
+               spin_unlock(&rand_spin);
+               add_buffer_randomness_src((const uint8_t *)&ACCUM.tv_nsec,
+                   sizeof(ACCUM.tv_nsec), RAND_SRC_INTR);
+               spin_lock(&rand_spin);
        }
        spin_unlock(&rand_spin);
 }
index d8a0ad1..7464700 100644 (file)
 
 #ifdef _KERNEL
 
+/*
+ * XXX: consider only statically allocating some, and allocating
+ *      most others dynamically.
+ */
+#define RAND_SRC_UNKNOWN       0x00
+#define RAND_SRC_SEEDING       0x01
+#define RAND_SRC_TIMING                0x02
+#define RAND_SRC_INTR          0x03
+#define RAND_SRC_RDRAND                0x04
+#define RAND_SRC_PADLOCK       0x05
+#define RAND_SRC_GLXSB         0x06
+#define RAND_SRC_HIFN          0x07
+#define RAND_SRC_UBSEC         0x08
+#define RAND_SRC_SAFE          0x09
+
 /* Type of the cookie passed to add_interrupt_randomness. */
 
 struct random_softc {
@@ -82,8 +97,8 @@ void add_interrupt_randomness(int intr);
 #ifdef notused
 void add_blkdev_randomness(int major);
 #endif
-void add_true_randomness(int);
 int add_buffer_randomness(const char *, int);
+int add_buffer_randomness_src(const char *, int, int srcid);
 
 #ifdef notused
 void get_random_bytes(void *buf, u_int nbytes);