diff options
author | markm <markm@FreeBSD.org> | 2015-08-17 07:36:12 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 2015-08-17 07:36:12 +0000 |
commit | 3f5a6af67aa31b22afbac2e407ff527052cbc720 (patch) | |
tree | 607f453932abecc199a5542abc16308de508677e /sys/dev/random/randomdev.c | |
parent | 9d08caeba8295dbd7762ac4c959b02bbeeeb8559 (diff) | |
download | FreeBSD-src-3f5a6af67aa31b22afbac2e407ff527052cbc720.zip FreeBSD-src-3f5a6af67aa31b22afbac2e407ff527052cbc720.tar.gz |
Add DEV_RANDOM pseudo-option and use it to "include out" random(4)
if desired.
Retire randomdev_none.c and introduce random_infra.c for resident
infrastructure. Completely stub out random(4) calls in the "without
DEV_RANDOM" case.
Add RANDOM_LOADABLE option to allow loadable Yarrow/Fortuna/LocallyWritten
algorithm. Add a skeleton "other" algorithm framework for folks
to add their own processing code. NIST, anyone?
Retire the RANDOM_DUMMY option.
Build modules for Yarrow, Fortuna and "other".
Use atomics for the live entropy rate-tracking.
Convert ints to bools for the 'seeded' logic.
Move _write() function from the algorithm-specific areas to randomdev.c
Get rid of reseed() function - it is unused.
Tidy up the opt_*.h includes.
Update documentation for random(4) modules.
Fix test program (reviewers, please leave this).
Differential Revision: https://reviews.freebsd.org/D3354
Reviewed by: wblock,delphij,jmg,bjk
Approved by: so (/dev/random blanket)
Diffstat (limited to 'sys/dev/random/randomdev.c')
-rw-r--r-- | sys/dev/random/randomdev.c | 181 |
1 files changed, 66 insertions, 115 deletions
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index 5c20c5d..f20a462 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -56,14 +56,18 @@ __FBSDID("$FreeBSD$"); #include <dev/random/randomdev.h> #include <dev/random/random_harvestq.h> -#include "opt_random.h" +#define RANDOM_UNIT 0 -#if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW) -#error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW" +#if defined(RANDOM_LOADABLE) +#define READ_RANDOM_UIO _read_random_uio +#define READ_RANDOM _read_random +static int READ_RANDOM_UIO(struct uio *, bool); +static u_int READ_RANDOM(void *, u_int); +#else +#define READ_RANDOM_UIO read_random_uio +#define READ_RANDOM read_random #endif -#define RANDOM_UNIT 0 - /* Return the largest number >= x that is a multiple of m */ #define CEIL_TO_MULTIPLE(x, m) ((((x) + (m) - 1)/(m))*(m)) @@ -84,68 +88,31 @@ static struct cdevsw random_cdevsw = { /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; -/* Set up the sysctl root node for the entropy device */ -SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); - -MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); - -#if defined(RANDOM_DUMMY) - -/*- - * Dummy "always block" pseudo algorithm, used when there is no real - * random(4) driver to provide a CSPRNG. - */ - -static u_int -dummy_random_zero(void) -{ - - return (0); -} - -static void -dummy_random(void) -{ -} - -struct random_algorithm random_alg_context = { - .ra_ident = "Dummy", - .ra_init_alg = NULL, - .ra_deinit_alg = NULL, - .ra_pre_read = dummy_random, - .ra_read = (random_alg_read_t *)dummy_random_zero, - .ra_write = (random_alg_write_t *)dummy_random_zero, - .ra_reseed = dummy_random, - .ra_seeded = (random_alg_seeded_t *)dummy_random_zero, - .ra_event_processor = NULL, - .ra_poolcount = 0, -}; - -#else /* !defined(RANDOM_DUMMY) */ - -LIST_HEAD(sources_head, random_sources); -static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); -static u_int read_rate; - static void random_alg_context_ra_init_alg(void *data) { - random_alg_context.ra_init_alg(data); + p_random_alg_context = &random_alg_context; + p_random_alg_context->ra_init_alg(data); +#if defined(RANDOM_LOADABLE) + random_infra_init(READ_RANDOM_UIO, READ_RANDOM); +#endif } static void random_alg_context_ra_deinit_alg(void *data) { - random_alg_context.ra_deinit_alg(data); +#if defined(RANDOM_LOADABLE) + random_infra_uninit(); +#endif + p_random_alg_context->ra_deinit_alg(data); + p_random_alg_context = NULL; } SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL); SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL); -#endif /* defined(RANDOM_DUMMY) */ - static struct selinfo rsel; /* @@ -156,28 +123,28 @@ static int randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags) { - return (read_random_uio(uio, (flags & O_NONBLOCK) != 0)); + return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0)); } int -read_random_uio(struct uio *uio, bool nonblock) +READ_RANDOM_UIO(struct uio *uio, bool nonblock) { uint8_t *random_buf; int error, spamcount; ssize_t read_len, total_read, c; random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); error = 0; spamcount = 0; /* (Un)Blocking logic */ - while (!random_alg_context.ra_seeded()) { + while (!p_random_alg_context->ra_seeded()) { if (nonblock) { error = EWOULDBLOCK; break; } /* keep tapping away at the pre-read until we seed/unblock. */ - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); /* Only bother the console every 10 seconds or so */ if (spamcount == 0) printf("random: %s unblock wait\n", __func__); @@ -187,10 +154,7 @@ read_random_uio(struct uio *uio, bool nonblock) break; } if (error == 0) { -#if !defined(RANDOM_DUMMY) - /* XXX: FIX!! Next line as an atomic operation? */ - read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t); -#endif + read_rate_increment((uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t)); total_read = 0; while (uio->uio_resid && !error) { read_len = uio->uio_resid; @@ -203,7 +167,7 @@ read_random_uio(struct uio *uio, bool nonblock) read_len = CEIL_TO_MULTIPLE(read_len, RANDOM_BLOCKSIZE); /* Work in chunks page-sized or less */ read_len = MIN(read_len, PAGE_SIZE); - random_alg_context.ra_read(random_buf, read_len); + p_random_alg_context->ra_read(random_buf, read_len); c = MIN(uio->uio_resid, read_len); error = uiomove(random_buf, c, uio); total_read += c; @@ -224,19 +188,16 @@ read_random_uio(struct uio *uio, bool nonblock) * RANDOM_BLOCKSIZE bytes. */ u_int -read_random(void *random_buf, u_int len) +READ_RANDOM(void *random_buf, u_int len) { u_int read_len; uint8_t local_buf[len + RANDOM_BLOCKSIZE]; KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); /* (Un)Blocking logic; if not seeded, return nothing. */ - if (random_alg_context.ra_seeded()) { -#if !defined(RANDOM_DUMMY) - /* XXX: FIX!! Next line as an atomic operation? */ - read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t); -#endif + if (p_random_alg_context->ra_seeded()) { + read_rate_increment((len + sizeof(uint32_t))/sizeof(uint32_t)); if (len > 0) { /* * Belt-and-braces. @@ -244,7 +205,7 @@ read_random(void *random_buf, u_int len) * which is what the underlying generator is expecting. */ read_len = CEIL_TO_MULTIPLE(len, RANDOM_BLOCKSIZE); - random_alg_context.ra_read(local_buf, read_len); + p_random_alg_context->ra_read(local_buf, read_len); memcpy(random_buf, local_buf, len); } } else @@ -252,6 +213,37 @@ read_random(void *random_buf, u_int len) return (len); } +static __inline void +randomdev_accumulate(uint8_t *buf, u_int count) +{ + static u_int destination = 0; + static struct harvest_event event; + static struct randomdev_hash hash; + static uint32_t entropy_data[RANDOM_KEYSIZE_WORDS]; + uint32_t timestamp; + int i; + + /* Extra timing here is helpful to scrape scheduler jitter entropy */ + randomdev_hash_init(&hash); + timestamp = (uint32_t)get_cyclecount(); + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_iterate(&hash, buf, count); + timestamp = (uint32_t)get_cyclecount(); + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_finish(&hash, entropy_data); + explicit_bzero(&hash, sizeof(hash)); + for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { + event.he_somecounter = (uint32_t)get_cyclecount(); + event.he_size = sizeof(event.he_entropy); + event.he_bits = event.he_size/8; + event.he_source = RANDOM_CACHED; + event.he_destination = destination++; /* Harmless cheating */ + memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy)); + p_random_alg_context->ra_event_processor(&event); + } + explicit_bzero(entropy_data, sizeof(entropy_data)); +} + /* ARGSUSED */ static int randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) @@ -267,7 +259,7 @@ randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) error = uiomove(random_buf, c, uio); if (error) break; - random_alg_context.ra_write(random_buf, c); + randomdev_accumulate(random_buf, c); tsleep(&random_alg_context, 0, "randwr", hz/10); } if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR)) @@ -283,7 +275,7 @@ randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused { if (events & (POLLIN | POLLRDNORM)) { - if (random_alg_context.ra_seeded()) + if (p_random_alg_context->ra_seeded()) events &= (POLLIN | POLLRDNORM); else selrecord(td, &rsel); @@ -325,9 +317,6 @@ randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, void random_source_register(struct random_source *rsource) { -#if defined(RANDOM_DUMMY) - (void)rsource; -#else /* !defined(RANDOM_DUMMY) */ struct random_sources *rrs; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); @@ -337,15 +326,11 @@ random_source_register(struct random_source *rsource) printf("random: registering fast source %s\n", rsource->rs_ident); LIST_INSERT_HEAD(&source_list, rrs, rrs_entries); -#endif /* defined(RANDOM_DUMMY) */ } void random_source_deregister(struct random_source *rsource) { -#if defined(RANDOM_DUMMY) - (void)rsource; -#else /* !defined(RANDOM_DUMMY) */ struct random_sources *rrs = NULL; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); @@ -356,41 +341,6 @@ random_source_deregister(struct random_source *rsource) } if (rrs != NULL) free(rrs, M_ENTROPY); -#endif /* defined(RANDOM_DUMMY) */ -} - -#if !defined(RANDOM_DUMMY) -/* - * Run through all fast sources reading entropy for the given - * number of rounds, which should be a multiple of the number - * of entropy accumulation pools in use; 2 for Yarrow and 32 - * for Fortuna. - * - * BEWARE!!! - * This function runs inside the RNG thread! Don't do anything silly! - */ -void -random_sources_feed(void) -{ - uint32_t entropy[HARVESTSIZE]; - struct random_sources *rrs; - u_int i, n, local_read_rate; - - /* - * Step over all of live entropy sources, and feed their output - * to the system-wide RNG. - */ - /* XXX: FIX!! Next lines as an atomic operation? */ - local_read_rate = read_rate; - read_rate = RANDOM_ALG_READ_RATE_MINIMUM; - LIST_FOREACH(rrs, &source_list, rrs_entries) { - for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) { - n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); - KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__)); - random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); - } - } - explicit_bzero(entropy, sizeof(entropy)); } static int @@ -414,7 +364,6 @@ random_source_handler(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, random_source_handler, "A", "List of active fast entropy sources."); -#endif /* !defined(RANDOM_DUMMY) */ /* ARGSUSED */ static int @@ -449,3 +398,5 @@ static moduledata_t randomdev_mod = { DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); MODULE_VERSION(random_device, 1); +MODULE_DEPEND(random_device, crypto, 1, 1, 1); +MODULE_DEPEND(random_device, random_harvestq, 1, 1, 1); |