diff --git a/share/examples/kld/Makefile b/share/examples/kld/Makefile index 4e3b641f57c7..5e6fc7459bc5 100644 --- a/share/examples/kld/Makefile +++ b/share/examples/kld/Makefile @@ -67,6 +67,6 @@ # $FreeBSD$ # -SUBDIR= cdev dyn_sysctl firmware khelp syscall +SUBDIR= cdev dyn_sysctl firmware khelp random_adaptor syscall .include diff --git a/share/examples/kld/random_adaptor/Makefile b/share/examples/kld/random_adaptor/Makefile new file mode 100644 index 000000000000..d19b4dc26473 --- /dev/null +++ b/share/examples/kld/random_adaptor/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= random_adaptor_example +SRCS= ${KMOD}.c + +.include diff --git a/share/examples/kld/random_adaptor/random_adaptor_example.c b/share/examples/kld/random_adaptor/random_adaptor_example.c new file mode 100644 index 000000000000..c0ab10a83fc5 --- /dev/null +++ b/share/examples/kld/random_adaptor/random_adaptor_example.c @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2013 Arthur Mesh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +#define RNG_NAME "example" + +static int random_example_read(void *, int); + +struct random_adaptor random_example = { + .ident = "Example RNG", + .init = (random_init_func_t *)random_null_func, + .deinit = (random_deinit_func_t *)random_null_func, + .read = random_example_read, + .write = (random_write_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 1, +}; + +/* + * Used under the license provided @ http://xkcd.com/221/ + * http://creativecommons.org/licenses/by-nc/2.5/ + */ +static u_char +getRandomNumber(void) +{ + return 4; /* chosen by fair dice roll, guaranteed to be random */ +} + +static int +random_example_read(void *buf, int c) +{ + u_char *b; + int count; + + b = buf; + + for (count = 0; count < c; count++) { + b[count] = getRandomNumber(); + } + + printf("returning %d bytes of pure randomness\n", c); + return (c); +} + +static int +random_example_modevent(module_t mod, int type, void *unused) +{ + + switch (type) { + case MOD_LOAD: + random_adaptor_register(RNG_NAME, &random_example); + EVENTHANDLER_INVOKE(random_adaptor_attach, &random_example); + return (0); + } + + return (EINVAL); +} + +RANDOM_ADAPTOR_MODULE(random_example, random_example_modevent, 1); diff --git a/sys/conf/files b/sys/conf/files index 832efdba3e1a..f790acb62faa 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2042,8 +2042,9 @@ rt2860.fw optional rt2860fw | ralfw \ clean "rt2860.fw" dev/random/harvest.c standard dev/random/hash.c optional random -dev/random/probe.c optional random +dev/random/pseudo_rng.c standard dev/random/random_adaptors.c standard +dev/random/random_harvestq.c standard dev/random/randomdev.c optional random dev/random/randomdev_soft.c optional random dev/random/yarrow.c optional random diff --git a/sys/dev/glxsb/glxsb.c b/sys/dev/glxsb/glxsb.c index aa1721742d6b..52041534da3e 100644 --- a/sys/dev/glxsb/glxsb.c +++ b/sys/dev/glxsb/glxsb.c @@ -476,7 +476,7 @@ glxsb_rnd(void *v) if (status & SB_RNS_TRNG_VALID) { value = bus_read_4(sc->sc_sr, SB_RANDOM_NUM); /* feed with one uint32 */ - random_harvest(&value, 4, 32, 0, RANDOM_PURE); + random_harvest(&value, 4, 32/2, 0, RANDOM_PURE); } callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc); diff --git a/sys/dev/hifn/hifn7751.c b/sys/dev/hifn/hifn7751.c index c5c5af1b3fa4..ae6c5ac6353b 100644 --- a/sys/dev/hifn/hifn7751.c +++ b/sys/dev/hifn/hifn7751.c @@ -258,7 +258,7 @@ hifn_partname(struct hifn_softc *sc) static void default_harvest(struct rndtest_state *rsp, void *buf, u_int count) { - random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE); + random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE); } static u_int diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c index a1ff8dde4c60..473e429317a8 100644 --- a/sys/dev/random/harvest.c +++ b/sys/dev/random/harvest.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2004 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,7 +60,7 @@ static int (*read_func)(void *, int) = read_random_phony; /* Initialise the harvester at load time */ void -random_yarrow_init_harvester(void (*reaper)(u_int64_t, const void *, u_int, +randomdev_init_harvester(void (*reaper)(u_int64_t, const void *, u_int, u_int, u_int, enum esource), int (*reader)(void *, int)) { reap_func = reaper; @@ -69,7 +69,7 @@ random_yarrow_init_harvester(void (*reaper)(u_int64_t, const void *, u_int, /* Deinitialise the harvester at unload time */ void -random_yarrow_deinit_harvester(void) +randomdev_deinit_harvester(void) { reap_func = NULL; read_func = read_random_phony; diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c index 611f866c4242..cf0feaa66ef9 100644 --- a/sys/dev/random/hash.c +++ b/sys/dev/random/hash.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2004 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,46 +36,46 @@ __FBSDID("$FreeBSD$"); #include -/* initialise the hash */ +/* Initialise the hash */ void -yarrow_hash_init(struct yarrowhash *context) +randomdev_hash_init(struct randomdev_hash *context) { SHA256_Init(&context->sha); } -/* iterate the hash */ +/* Iterate the hash */ void -yarrow_hash_iterate(struct yarrowhash *context, void *data, size_t size) +randomdev_hash_iterate(struct randomdev_hash *context, void *data, size_t size) { SHA256_Update(&context->sha, data, size); } -/* Conclude by returning the hash in the supplied /buf/ which must be +/* Conclude by returning the hash in the supplied <*buf> which must be * KEYSIZE bytes long. */ void -yarrow_hash_finish(struct yarrowhash *context, void *buf) +randomdev_hash_finish(struct randomdev_hash *context, void *buf) { SHA256_Final(buf, &context->sha); } /* Initialise the encryption routine by setting up the key schedule - * from the supplied /data/ which must be KEYSIZE bytes of binary - * data. + * from the supplied <*data> which must be KEYSIZE bytes of binary + * data. Use CBC mode for better avalanche. */ void -yarrow_encrypt_init(struct yarrowkey *context, void *data) +randomdev_encrypt_init(struct randomdev_key *context, void *data) { rijndael_cipherInit(&context->cipher, MODE_CBC, NULL); rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data); } /* Encrypt the supplied data using the key schedule preset in the context. - * KEYSIZE bytes are encrypted from /d_in/ to /d_out/. + * bytes are encrypted from <*d_in> to <*d_out>. must be + * a multiple of BLOCKSIZE. */ void -yarrow_encrypt(struct yarrowkey *context, void *d_in, void *d_out) +randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, unsigned length) { - rijndael_blockEncrypt(&context->cipher, &context->key, d_in, - KEYSIZE*8, d_out); + rijndael_blockEncrypt(&context->cipher, &context->key, d_in, length*8, d_out); } diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h index 8580d145d683..62f116daa00d 100644 --- a/sys/dev/random/hash.h +++ b/sys/dev/random/hash.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2004 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,19 +26,20 @@ * $FreeBSD$ */ -#define KEYSIZE 32 /* (in bytes) 32 bytes == 256 bits */ +#define KEYSIZE 32 /* (in bytes) == 256 bits */ +#define BLOCKSIZE 16 /* (in bytes) == 128 bits */ -struct yarrowhash { /* Big! Make static! */ +struct randomdev_hash { /* Big! Make static! */ SHA256_CTX sha; }; -struct yarrowkey { /* Big! Make static! */ +struct randomdev_key { /* Big! Make static! */ keyInstance key; /* Key schedule */ cipherInstance cipher; /* Rijndael internal */ }; -void yarrow_hash_init(struct yarrowhash *); -void yarrow_hash_iterate(struct yarrowhash *, void *, size_t); -void yarrow_hash_finish(struct yarrowhash *, void *); -void yarrow_encrypt_init(struct yarrowkey *, void *); -void yarrow_encrypt(struct yarrowkey *context, void *, void *); +void randomdev_hash_init(struct randomdev_hash *); +void randomdev_hash_iterate(struct randomdev_hash *, void *, size_t); +void randomdev_hash_finish(struct randomdev_hash *, void *); +void randomdev_encrypt_init(struct randomdev_key *, void *); +void randomdev_encrypt(struct randomdev_key *context, void *, void *, unsigned); diff --git a/sys/dev/random/pseudo_rng.c b/sys/dev/random/pseudo_rng.c new file mode 100644 index 000000000000..13552942f795 --- /dev/null +++ b/sys/dev/random/pseudo_rng.c @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2013 Arthur Mesh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct mtx pseudo_random_block_mtx; + +static int +pseudo_random_block_read(void *buf __unused, int c __unused) +{ + + mtx_lock(&pseudo_random_block_mtx); + + printf("random(4) device is blocking.\n"); + msleep(pseudo_random_block_read, &pseudo_random_block_mtx, 0, + "block", 0); + + mtx_unlock(&pseudo_random_block_mtx); + + return (0); +} + +static void +pseudo_random_block_init(void) +{ + + mtx_init(&pseudo_random_block_mtx, "sleep mtx for random_block", + NULL, MTX_DEF); +} + +static void +pseudo_random_block_deinit(void) +{ + + mtx_destroy(&pseudo_random_block_mtx); +} + +struct random_adaptor pseudo_random_block = { + .ident = "pseudo-RNG that always blocks", + .init = pseudo_random_block_init, + .deinit = pseudo_random_block_deinit, + .read = pseudo_random_block_read, + .write = (random_write_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 1, +}; + +static int +pseudo_random_panic_read(void *buf, int c) +{ + + panic("Insert a witty panic msg in here."); + + return (0); +} + +struct random_adaptor pseudo_random_panic = { + .ident = "pseudo-RNG that always panics on first read(2)", + .init = (random_init_func_t *)random_null_func, + .deinit = (random_deinit_func_t *)random_null_func, + .read = pseudo_random_panic_read, + .write = (random_write_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 1, +}; + +static int +pseudo_random_modevent(module_t mod, int type, void *unused) +{ + + switch (type) { + case MOD_LOAD: + random_adaptor_register("block", &pseudo_random_block); + EVENTHANDLER_INVOKE(random_adaptor_attach, + &pseudo_random_block); + + random_adaptor_register("panic", &pseudo_random_panic); + + return (0); + } + + return (EINVAL); +} + +RANDOM_ADAPTOR_MODULE(pseudo, pseudo_random_modevent, 1); diff --git a/sys/dev/random/random_adaptors.c b/sys/dev/random/random_adaptors.c index c187bdb7fcfe..f6a21f6e08f4 100644 --- a/sys/dev/random/random_adaptors.c +++ b/sys/dev/random/random_adaptors.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 David E. O'Brien + * Copyright (c) 2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,16 +31,20 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include #include #include #include #include #include #include +#include -#include #include +#include +#include LIST_HEAD(adaptors_head, random_adaptors); static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors); @@ -57,7 +62,8 @@ random_adaptor_register(const char *name, struct random_adaptor *rsp) KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__)); - rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS, M_WAITOK); + rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS, + M_WAITOK); rpp->name = name; rpp->rsp = rsp; @@ -87,6 +93,93 @@ random_adaptor_get(const char *name) return (rsp); } +/* + * In the past, the logic of the random_adaptor selection was inverted, such + * that hardware RNGs would be chosen unless disabled. This routine is here to + * preserve that functionality to avoid folks losing their hardware RNGs by + * upgrading to newer kernel. + */ +static void +random_adaptor_choose_legacy(struct random_adaptor **adaptor) +{ + struct random_adaptor *tmp; + int enable; + + /* Then go looking for hardware */ + enable = 1; + TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable); + if (enable && (tmp = random_adaptor_get("nehemiah"))) + *adaptor = tmp; + + enable = 1; + TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable); + if (enable && (tmp = random_adaptor_get("rdrand"))) + *adaptor = tmp; +} + +/* + * Walk a list of registered random(4) adaptors and pick the last non-selected + * one. + * + * If none are selected, use yarrow if available. + */ +void +random_adaptor_choose(struct random_adaptor **adaptor) +{ + char rngs[128], *token, *cp; + struct random_adaptors *rpp; + + KASSERT(adaptor != NULL, ("pre-conditions failed")); + + *adaptor = NULL; + + random_adaptor_choose_legacy(adaptor); + + if (*adaptor != NULL) + return; + + if (TUNABLE_STR_FETCH("rngs_want", rngs, sizeof(rngs))) { + cp = rngs; + + while ((token = strsep(&cp, ",")) != NULL) { + if ((*adaptor = random_adaptor_get(token)) != NULL) + break; + else if (bootverbose) + printf( + "%s random adaptor is not available, skipping\n", + token); + } + } + + if (*adaptor == NULL) { + /* + * Either no RNGs are prefered via rngs_want tunable, or + * no prefered RNGs are registered. + * Fallback to Yarrow. + */ + *adaptor = random_adaptor_get("yarrow"); + + if (*adaptor == NULL) { + /* + * Yarrow doesn't seem to be available. + * Fallback to the first thing that's on the list of + * available RNGs. + */ + sx_slock(&adaptors_lock); + + rpp = LIST_FIRST(&adaptors); + if (rpp != NULL) + *adaptor = rpp->rsp; + + sx_sunlock(&adaptors_lock); + } + + if (bootverbose && *adaptor) + printf("Falling back to <%s> random adaptor", + (*adaptor)->ident); + } +} + static void random_adaptors_deinit(void *unused) { @@ -99,18 +192,28 @@ static int random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) { struct random_adaptors *rpp; - int error; + int error, count; - error = 0; + count = error = 0; sx_slock(&adaptors_lock); - if (LIST_EMPTY(&adaptors)) - error = SYSCTL_OUT(req, "", strlen("")); + if (LIST_EMPTY(&adaptors)) { + error = SYSCTL_OUT(req, "", 0); + } else { - LIST_FOREACH(rpp, &adaptors, entries) { - if (0 != SYSCTL_OUT(req, rpp->name, strlen(rpp->name))) - break; + LIST_FOREACH(rpp, &adaptors, entries) { + + error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); + + if (error) + break; + + error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name)); + + if (error) + break; + } } sx_sunlock(&adaptors_lock); @@ -118,6 +221,37 @@ random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) return (error); } +static int +random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS) +{ + struct random_adaptor *rsp; + struct random_adaptors *rpp; + const char *name; + int error; + + name = NULL; + rsp = random_get_active_adaptor(); + + if (rsp != NULL) { + sx_slock(&adaptors_lock); + + LIST_FOREACH(rpp, &adaptors, entries) { + if (rpp->rsp == rsp) + name = rpp->name; + } + + sx_sunlock(&adaptors_lock); + } + + if (rsp == NULL || name == NULL) { + error = SYSCTL_OUT(req, "", 0); + } else { + error = SYSCTL_OUT(req, name, strlen(name)); + } + + return (error); +} + static void random_adaptors_init(void *unused) { @@ -127,6 +261,11 @@ random_adaptors_init(void *unused) NULL, 0, random_sysctl_adaptors_handler, "", "Random Number Generator adaptors"); + SYSCTL_PROC(_kern_random, OID_AUTO, active_adaptor, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, random_sysctl_active_adaptor_handler, "", + "Active Random Number Generator Adaptor"); + sx_init(&adaptors_lock, "random_adaptors"); } diff --git a/sys/dev/random/random_adaptors.h b/sys/dev/random/random_adaptors.h index 50a7a0fea017..98f8c2ebe273 100644 --- a/sys/dev/random/random_adaptors.h +++ b/sys/dev/random/random_adaptors.h @@ -39,6 +39,7 @@ struct random_adaptors { struct random_adaptor *random_adaptor_get(const char *); int random_adaptor_register(const char *, struct random_adaptor *); +void random_adaptor_choose(struct random_adaptor **); /* * random_adaptor's should be registered prior to diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c new file mode 100644 index 000000000000..fc87cde0068d --- /dev/null +++ b/sys/dev/random/random_harvestq.c @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 2013 Arthur Mesh + * Copyright (c) 2000-2009 Mark R V Murray + * Copyright (c) 2004 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "random_harvestq.h" + +#define RANDOM_FIFO_MAX 256 /* How many events to queue up */ + +MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers"); + +/* + * The harvest mutex protects the consistency of the entropy fifos and + * empty fifo. + */ +struct mtx harvest_mtx; + +/* Lockable FIFO queue holding entropy buffers */ +struct entropyfifo { + int count; + STAILQ_HEAD(harvestlist, harvest) head; +}; + +/* Empty entropy buffers */ +static struct entropyfifo emptyfifo; + +#define EMPTYBUFFERS 1024 + +/* Harvested entropy */ +static struct entropyfifo harvestfifo[ENTROPYSOURCE]; + +/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */ +int random_kthread_control = 0; + +static struct proc *random_kthread_proc; + +static void +random_kthread(void *arg) +{ + STAILQ_HEAD(, harvest) local_queue; + struct harvest *event = NULL; + int local_count; + enum esource source; + event_proc_f func = arg; + + STAILQ_INIT(&local_queue); + local_count = 0; + + /* Process until told to stop */ + mtx_lock_spin(&harvest_mtx); + for (; random_kthread_control >= 0;) { + + /* Cycle through all the entropy sources */ + for (source = RANDOM_START; source < ENTROPYSOURCE; source++) { + /* + * Drain entropy source records into a thread-local + * queue for processing while not holding the mutex. + */ + STAILQ_CONCAT(&local_queue, &harvestfifo[source].head); + local_count += harvestfifo[source].count; + harvestfifo[source].count = 0; + } + + /* + * Deal with events, if any, dropping the mutex as we process + * each event. Then push the events back into the empty + * fifo. + */ + if (!STAILQ_EMPTY(&local_queue)) { + mtx_unlock_spin(&harvest_mtx); + STAILQ_FOREACH(event, &local_queue, next) + func(event); + mtx_lock_spin(&harvest_mtx); + STAILQ_CONCAT(&emptyfifo.head, &local_queue); + emptyfifo.count += local_count; + local_count = 0; + } + + KASSERT(local_count == 0, ("random_kthread: local_count %d", + local_count)); + + /* + * If a queue flush was commanded, it has now happened, + * and we can mark this by resetting the command. + */ + if (random_kthread_control == 1) + random_kthread_control = 0; + + /* Work done, so don't belabour the issue */ + msleep_spin_sbt(&random_kthread_control, &harvest_mtx, + "-", SBT_1S / 10, 0, C_PREL(1)); + + } + mtx_unlock_spin(&harvest_mtx); + + random_set_wakeup_exit(&random_kthread_control); + /* NOTREACHED */ +} + +void +random_harvestq_init(event_proc_f cb) +{ + int error, i; + struct harvest *np; + enum esource e; + + /* Initialise the harvest fifos */ + STAILQ_INIT(&emptyfifo.head); + emptyfifo.count = 0; + for (i = 0; i < EMPTYBUFFERS; i++) { + np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); + STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); + } + for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { + STAILQ_INIT(&harvestfifo[e].head); + harvestfifo[e].count = 0; + } + + mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); + + + /* Start the hash/reseed thread */ + error = kproc_create(random_kthread, cb, + &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */ + + if (error != 0) + panic("Cannot create entropy maintenance thread."); +} + +void +random_harvestq_deinit(void) +{ + struct harvest *np; + enum esource e; + + /* Destroy the harvest fifos */ + while (!STAILQ_EMPTY(&emptyfifo.head)) { + np = STAILQ_FIRST(&emptyfifo.head); + STAILQ_REMOVE_HEAD(&emptyfifo.head, next); + free(np, M_ENTROPY); + } + for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { + while (!STAILQ_EMPTY(&harvestfifo[e].head)) { + np = STAILQ_FIRST(&harvestfifo[e].head); + STAILQ_REMOVE_HEAD(&harvestfifo[e].head, next); + free(np, M_ENTROPY); + } + } + + mtx_destroy(&harvest_mtx); +} + +/* + * Entropy harvesting routine. This is supposed to be fast; do + * not do anything slow in here! + */ +void +random_harvestq_internal(u_int64_t somecounter, const void *entropy, + u_int count, u_int bits, u_int frac, enum esource origin) +{ + struct harvest *event; + + KASSERT(origin >= RANDOM_START && origin <= RANDOM_PURE, + ("random_harvest_internal: origin %d invalid\n", origin)); + + /* Lockless read to avoid lock operations if fifo is full. */ + if (harvestfifo[origin].count >= RANDOM_FIFO_MAX) + return; + + mtx_lock_spin(&harvest_mtx); + + /* + * Don't make the harvest queues too big - help to prevent low-grade + * entropy swamping + */ + if (harvestfifo[origin].count < RANDOM_FIFO_MAX) { + event = STAILQ_FIRST(&emptyfifo.head); + if (event != NULL) { + /* Add the harvested data to the fifo */ + STAILQ_REMOVE_HEAD(&emptyfifo.head, next); + harvestfifo[origin].count++; + event->somecounter = somecounter; + event->size = count; + event->bits = bits; + event->frac = frac; + event->source = origin; + + /* XXXX Come back and make this dynamic! */ + count = MIN(count, HARVESTSIZE); + memcpy(event->entropy, entropy, count); + +#if 0 + { + int i; + printf("Harvest:%16jX ", event->somecounter); + for (i = 0; i < event->size; i++) + printf("%02X", event->entropy[i]); + for (; i < 16; i++) + printf(" "); + printf(" %2d 0x%2X.%03X %02X\n", event->size, event->bits, event->frac, event->source); + } +#endif + + STAILQ_INSERT_TAIL(&harvestfifo[origin].head, + event, next); + } + } + mtx_unlock_spin(&harvest_mtx); +} + diff --git a/sys/dev/random/probe.c b/sys/dev/random/random_harvestq.h similarity index 61% rename from sys/dev/random/probe.c rename to sys/dev/random/random_harvestq.h index 7039b92606eb..9766c7728c44 100644 --- a/sys/dev/random/probe.c +++ b/sys/dev/random/random_harvestq.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004 Mark R V Murray + * Copyright (c) 2013 Arthur Mesh * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,40 +23,19 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * $FreeBSD$ */ -#include -__FBSDID("$FreeBSD$"); +#ifndef __RANDOM_HARVEST_H__ +#define __RANDOM_HARVEST_H__ -#if defined(__amd64__) || defined(__i386__) -#include "opt_cpu.h" -#endif +typedef void (*event_proc_f)(struct harvest *event); -#include -#include -#include -#include +void random_harvestq_init(event_proc_f); +void random_harvestq_deinit(void); +void random_harvestq_internal(u_int64_t, const void *, + u_int, u_int, u_int, enum esource); -#include -#include +extern int random_kthread_control; -void -random_ident_hardware(struct random_adaptor **adaptor) -{ - struct random_adaptor *tmp; - int enable; - - /* Set default to software (yarrow) */ - *adaptor = random_adaptor_get("yarrow"); - - /* Then go looking for hardware */ - enable = 1; - TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable); - if (enable && (tmp = random_adaptor_get("nehemiah"))) - *adaptor = tmp; - - enable = 1; - TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable); - if (enable && (tmp = random_adaptor_get("rdrand"))) - *adaptor = tmp; -} +#endif /* __RANDOM_HARVEST_H__ */ diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index d18641fe3098..850948ee9627 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #define RANDOM_MINOR 0 @@ -85,6 +86,13 @@ random_null_func(void) { } +struct random_adaptor * +random_get_active_adaptor(void) +{ + + return (random_adaptor); +} + /* ARGSUSED */ static int random_close(struct cdev *dev __unused, int flags, int fmt __unused, @@ -215,7 +223,7 @@ random_modevent(module_t mod __unused, int type, void *data __unused) switch (type) { case MOD_LOAD: - random_ident_hardware(&random_adaptor); + random_adaptor_choose(&random_adaptor); if (random_adaptor == NULL) { printf( diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index 75b2c1980901..aeb47531ae72 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -53,3 +53,4 @@ struct random_adaptor { extern void random_ident_hardware(struct random_adaptor **); extern void random_null_func(void); +struct random_adaptor *random_get_active_adaptor(void); diff --git a/sys/dev/random/randomdev_soft.c b/sys/dev/random/randomdev_soft.c index 7e537fe0a0da..7d14cc669c1a 100644 --- a/sys/dev/random/randomdev_soft.c +++ b/sys/dev/random/randomdev_soft.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2009 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * Copyright (c) 2004 Robert N. M. Watson * All rights reserved. * @@ -26,22 +26,24 @@ * */ +#if !defined(YARROW_RNG) && !defined(FORTUNA_RNG) +#define YARROW_RNG +#elif defined(YARROW_RNG) && defined(FORTUNA_RNG) +#error "Must define either YARROW_RNG or FORTUNA_RNG" +#endif + #include __FBSDID("$FreeBSD$"); #include #include -#include -#include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -54,55 +56,51 @@ __FBSDID("$FreeBSD$"); #include #include #include +#if defined(YARROW_RNG) +#include +#endif +#if defined(FORTUNA_RNG) +#include +#endif -#define RANDOM_FIFO_MAX 256 /* How many events to queue up */ +#include "random_harvestq.h" -static void random_kthread(void *); -static void -random_harvest_internal(u_int64_t, const void *, u_int, - u_int, u_int, enum esource); -static int random_yarrow_poll(int event,struct thread *td); -static int random_yarrow_block(int flag); -static void random_yarrow_flush_reseed(void); +static int randomdev_poll(int event, struct thread *td); +static int randomdev_block(int flag); +static void randomdev_flush_reseed(void); -struct random_adaptor random_yarrow = { +#if defined(YARROW_RNG) +static struct random_adaptor random_context = { .ident = "Software, Yarrow", - .init = random_yarrow_init, - .deinit = random_yarrow_deinit, - .block = random_yarrow_block, + .init = randomdev_init, + .deinit = randomdev_deinit, + .block = randomdev_block, .read = random_yarrow_read, - .write = random_yarrow_write, - .poll = random_yarrow_poll, - .reseed = random_yarrow_flush_reseed, - .seeded = 1, + .write = randomdev_write, + .poll = randomdev_poll, + .reseed = randomdev_flush_reseed, + .seeded = 0, }; +#define RANDOM_MODULE_NAME yarrow +#define RANDOM_CSPRNG_NAME "yarrow" +#endif -MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers"); - -/* - * The harvest mutex protects the consistency of the entropy fifos and - * empty fifo. - */ -struct mtx harvest_mtx; - -/* Lockable FIFO queue holding entropy buffers */ -struct entropyfifo { - int count; - STAILQ_HEAD(harvestlist, harvest) head; +#if defined(FORTUNA_RNG) +static struct random_adaptor random_context = { + .ident = "Software, Fortuna", + .init = randomdev_init, + .deinit = randomdev_deinit, + .block = randomdev_block, + .read = random_fortuna_read, + .write = randomdev_write, + .poll = randomdev_poll, + .reseed = randomdev_flush_reseed, + .seeded = 0, }; +#define RANDOM_MODULE_NAME fortuna +#define RANDOM_CSPRNG_NAME "fortuna" -/* Empty entropy buffers */ -static struct entropyfifo emptyfifo; - -#define EMPTYBUFFERS 1024 - -/* Harvested entropy */ -static struct entropyfifo harvestfifo[ENTROPYSOURCE]; - -/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */ -static int random_kthread_control = 0; - -static struct proc *random_kthread_proc; +#endif /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; @@ -116,16 +114,17 @@ random_check_boolean(SYSCTL_HANDLER_ARGS) return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); } -/* ARGSUSED */ void -random_yarrow_init(void) +randomdev_init(void) { - int error, i; - struct harvest *np; struct sysctl_oid *random_sys_o, *random_sys_harvest_o; - enum esource e; +#if defined(YARROW_RNG) random_yarrow_init_alg(&random_clist); +#endif +#if defined(FORTUNA_RNG) + random_fortuna_init_alg(&random_clist); +#endif random_sys_o = SYSCTL_ADD_NODE(&random_clist, SYSCTL_STATIC_CHILDREN(_kern_random), @@ -135,7 +134,7 @@ random_yarrow_init(void) SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW, - &random_yarrow.seeded, 1, random_check_boolean, "I", + &random_context.seeded, 1, random_check_boolean, "I", "Seeded State"); random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist, @@ -156,7 +155,7 @@ random_yarrow_init(void) SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_harvest_o), OID_AUTO, "interrupt", CTLTYPE_INT | CTLFLAG_RW, - &harvest.interrupt, 1, random_check_boolean, "I", + &harvest.interrupt, 0, random_check_boolean, "I", "Harvest IRQ entropy"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_harvest_o), @@ -164,40 +163,18 @@ random_yarrow_init(void) &harvest.swi, 0, random_check_boolean, "I", "Harvest SWI entropy"); - /* Initialise the harvest fifos */ - STAILQ_INIT(&emptyfifo.head); - emptyfifo.count = 0; - for (i = 0; i < EMPTYBUFFERS; i++) { - np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); - STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); - } - for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { - STAILQ_INIT(&harvestfifo[e].head); - harvestfifo[e].count = 0; - } - - mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); - - /* Start the hash/reseed thread */ - error = kproc_create(random_kthread, NULL, - &random_kthread_proc, RFHIGHPID, 0, "yarrow"); - if (error != 0) - panic("Cannot create entropy maintenance thread."); + random_harvestq_init(random_process_event); /* Register the randomness harvesting routine */ - random_yarrow_init_harvester(random_harvest_internal, - random_yarrow_read); + randomdev_init_harvester(random_harvestq_internal, + random_context.read); } -/* ARGSUSED */ void -random_yarrow_deinit(void) +randomdev_deinit(void) { - struct harvest *np; - enum esource e; - /* Deregister the randomness harvesting routine */ - random_yarrow_deinit_harvester(); + randomdev_deinit_harvester(); /* * Command the hash/reseed thread to end and wait for it to finish @@ -205,140 +182,18 @@ random_yarrow_deinit(void) random_kthread_control = -1; tsleep((void *)&random_kthread_control, 0, "term", 0); - /* Destroy the harvest fifos */ - while (!STAILQ_EMPTY(&emptyfifo.head)) { - np = STAILQ_FIRST(&emptyfifo.head); - STAILQ_REMOVE_HEAD(&emptyfifo.head, next); - free(np, M_ENTROPY); - } - for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { - while (!STAILQ_EMPTY(&harvestfifo[e].head)) { - np = STAILQ_FIRST(&harvestfifo[e].head); - STAILQ_REMOVE_HEAD(&harvestfifo[e].head, next); - free(np, M_ENTROPY); - } - } - +#if defined(YARROW_RNG) random_yarrow_deinit_alg(); - - mtx_destroy(&harvest_mtx); +#endif +#if defined(FORTUNA_RNG) + random_fortuna_deinit_alg(); +#endif sysctl_ctx_free(&random_clist); } -/* ARGSUSED */ -static void -random_kthread(void *arg __unused) -{ - STAILQ_HEAD(, harvest) local_queue; - struct harvest *event = NULL; - int local_count; - enum esource source; - - STAILQ_INIT(&local_queue); - local_count = 0; - - /* Process until told to stop */ - mtx_lock_spin(&harvest_mtx); - for (; random_kthread_control >= 0;) { - - /* Cycle through all the entropy sources */ - for (source = RANDOM_START; source < ENTROPYSOURCE; source++) { - /* - * Drain entropy source records into a thread-local - * queue for processing while not holding the mutex. - */ - STAILQ_CONCAT(&local_queue, &harvestfifo[source].head); - local_count += harvestfifo[source].count; - harvestfifo[source].count = 0; - } - - /* - * Deal with events, if any, dropping the mutex as we process - * each event. Then push the events back into the empty - * fifo. - */ - if (!STAILQ_EMPTY(&local_queue)) { - mtx_unlock_spin(&harvest_mtx); - STAILQ_FOREACH(event, &local_queue, next) - random_process_event(event); - mtx_lock_spin(&harvest_mtx); - STAILQ_CONCAT(&emptyfifo.head, &local_queue); - emptyfifo.count += local_count; - local_count = 0; - } - - KASSERT(local_count == 0, ("random_kthread: local_count %d", - local_count)); - - /* - * If a queue flush was commanded, it has now happened, - * and we can mark this by resetting the command. - */ - if (random_kthread_control == 1) - random_kthread_control = 0; - - /* Work done, so don't belabour the issue */ - msleep_spin_sbt(&random_kthread_control, &harvest_mtx, - "-", SBT_1S / 10, 0, C_PREL(1)); - - } - mtx_unlock_spin(&harvest_mtx); - - random_set_wakeup_exit(&random_kthread_control); - /* NOTREACHED */ -} - -/* Entropy harvesting routine. This is supposed to be fast; do - * not do anything slow in here! - */ -static void -random_harvest_internal(u_int64_t somecounter, const void *entropy, - u_int count, u_int bits, u_int frac, enum esource origin) -{ - struct harvest *event; - - KASSERT(origin == RANDOM_START || origin == RANDOM_WRITE || - origin == RANDOM_KEYBOARD || origin == RANDOM_MOUSE || - origin == RANDOM_NET || origin == RANDOM_INTERRUPT || - origin == RANDOM_PURE, - ("random_harvest_internal: origin %d invalid\n", origin)); - - /* Lockless read to avoid lock operations if fifo is full. */ - if (harvestfifo[origin].count >= RANDOM_FIFO_MAX) - return; - - mtx_lock_spin(&harvest_mtx); - - /* - * Don't make the harvest queues too big - help to prevent low-grade - * entropy swamping - */ - if (harvestfifo[origin].count < RANDOM_FIFO_MAX) { - event = STAILQ_FIRST(&emptyfifo.head); - if (event != NULL) { - /* Add the harvested data to the fifo */ - STAILQ_REMOVE_HEAD(&emptyfifo.head, next); - harvestfifo[origin].count++; - event->somecounter = somecounter; - event->size = count; - event->bits = bits; - event->frac = frac; - event->source = origin; - - /* XXXX Come back and make this dynamic! */ - count = MIN(count, HARVESTSIZE); - memcpy(event->entropy, entropy, count); - - STAILQ_INSERT_TAIL(&harvestfifo[origin].head, - event, next); - } - } - mtx_unlock_spin(&harvest_mtx); -} - void -random_yarrow_write(void *buf, int count) +randomdev_write(void *buf, int count) { int i; u_int chunk; @@ -351,52 +206,52 @@ random_yarrow_write(void *buf, int count) chunk = HARVESTSIZE; if (i + chunk >= count) chunk = (u_int)(count - i); - random_harvest_internal(get_cyclecount(), (char *)buf + i, + random_harvestq_internal(get_cyclecount(), (char *)buf + i, chunk, 0, 0, RANDOM_WRITE); } } void -random_yarrow_unblock(void) +randomdev_unblock(void) { - if (!random_yarrow.seeded) { - random_yarrow.seeded = 1; - selwakeuppri(&random_yarrow.rsel, PUSER); - wakeup(&random_yarrow); + if (!random_context.seeded) { + random_context.seeded = 1; + selwakeuppri(&random_context.rsel, PUSER); + wakeup(&random_context); } (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); } static int -random_yarrow_poll(int events, struct thread *td) +randomdev_poll(int events, struct thread *td) { int revents = 0; mtx_lock(&random_reseed_mtx); - if (random_yarrow.seeded) + if (random_context.seeded) revents = events & (POLLIN | POLLRDNORM); else - selrecord(td, &random_yarrow.rsel); + selrecord(td, &random_context.rsel); mtx_unlock(&random_reseed_mtx); return revents; } static int -random_yarrow_block(int flag) +randomdev_block(int flag) { int error = 0; mtx_lock(&random_reseed_mtx); /* Blocking logic */ - while (!random_yarrow.seeded && !error) { + while (!random_context.seeded && !error) { if (flag & O_NONBLOCK) error = EWOULDBLOCK; else { printf("Entropy device is blocking.\n"); - error = msleep(&random_yarrow, + error = msleep(&random_context, &random_reseed_mtx, PUSER | PCATCH, "block", 0); } @@ -408,23 +263,28 @@ random_yarrow_block(int flag) /* Helper routine to perform explicit reseeds */ static void -random_yarrow_flush_reseed(void) +randomdev_flush_reseed(void) { /* Command a entropy queue flush and wait for it to finish */ random_kthread_control = 1; while (random_kthread_control) pause("-", hz / 10); +#if defined(YARROW_RNG) random_yarrow_reseed(); +#endif +#if defined(FORTUNA_RNG) + random_fortuna_reseed(); +#endif } static int -yarrow_modevent(module_t mod, int type, void *unused) +randomdev_modevent(module_t mod, int type, void *unused) { switch (type) { case MOD_LOAD: - random_adaptor_register("yarrow", &random_yarrow); + random_adaptor_register(RANDOM_CSPRNG_NAME, &random_context); /* * For statically built kernels that contain both device * random and options PADLOCK_RNG/RDRAND_RNG/etc.., @@ -437,11 +297,11 @@ yarrow_modevent(module_t mod, int type, void *unused) * (by dependency). This event handler is there to delay * creation of /dev/{u,}random and attachment of this *_rng.ko. */ - EVENTHANDLER_INVOKE(random_adaptor_attach, &random_yarrow); + EVENTHANDLER_INVOKE(random_adaptor_attach, &random_context); return (0); } return (EINVAL); } -RANDOM_ADAPTOR_MODULE(yarrow, yarrow_modevent, 1); +RANDOM_ADAPTOR_MODULE(RANDOM_MODULE_NAME, randomdev_modevent, 1); diff --git a/sys/dev/random/randomdev_soft.h b/sys/dev/random/randomdev_soft.h index 2007694c50a2..c92a5a8e0725 100644 --- a/sys/dev/random/randomdev_soft.h +++ b/sys/dev/random/randomdev_soft.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2004 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,9 +35,6 @@ * an enum in sys/random.h */ -/* Cryptographic block size in bits */ -#define BLOCKSIZE 256 - /* The ring size _MUST_ be a power of 2 */ #define HARVEST_RING_SIZE 1024 /* harvest ring buffer size */ #define HARVEST_RING_MASK (HARVEST_RING_SIZE - 1) @@ -51,34 +48,28 @@ MALLOC_DECLARE(M_ENTROPY); */ struct harvest { uintmax_t somecounter; /* fast counter for clock jitter */ - u_char entropy[HARVESTSIZE]; /* the harvested entropy */ + uint8_t entropy[HARVESTSIZE]; /* the harvested entropy */ u_int size, bits, frac; /* stats about the entropy */ enum esource source; /* stats about the entropy */ STAILQ_ENTRY(harvest) next; /* next item on the list */ }; -void random_yarrow_init(void); -void random_yarrow_deinit(void); +void randomdev_init(void); +void randomdev_deinit(void); -int random_yarrow_read(void *, int); -void random_yarrow_write(void *, int); +void randomdev_write(void *, int); -void random_yarrow_init_harvester(void (*)(u_int64_t, const void *, u_int, +void randomdev_init_harvester(void (*)(u_int64_t, const void *, u_int, u_int, u_int, enum esource), int (*)(void *, int)); -void random_yarrow_deinit_harvester(void); +void randomdev_deinit_harvester(void); void random_set_wakeup_exit(void *); void random_process_event(struct harvest *event); -void random_yarrow_reseed(void); -void random_yarrow_unblock(void); +void randomdev_unblock(void); -void random_yarrow_init_alg(struct sysctl_ctx_list *); -void random_yarrow_deinit_alg(void); - -extern struct random_adaptor random_yarrow; extern struct mtx random_reseed_mtx; -/* If this was c++, this would be a template */ +/* If this was C++, the macro below would be a template */ #define RANDOM_CHECK_UINT(name, min, max) \ static int \ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c index 09f079afa728..21913f924f66 100644 --- a/sys/dev/random/yarrow.c +++ b/sys/dev/random/yarrow.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2004 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,21 +45,68 @@ __FBSDID("$FreeBSD$"); #include #include +#define TIMEBIN 16 /* max value for Pt/t */ + +#define FAST 0 +#define SLOW 1 + +/* This is the beastie that needs protecting. It contains all of the + * state that we are excited about. + * Exactly one is instantiated. + */ +static struct random_state { + union { + uint8_t byte[BLOCKSIZE]; + uint64_t qword[BLOCKSIZE/sizeof(uint64_t)]; + } counter; /* C */ + struct randomdev_key key; /* K */ + u_int gengateinterval; /* Pg */ + u_int bins; /* Pt/t */ + u_int outputblocks; /* count output blocks for gates */ + u_int slowoverthresh; /* slow pool overthreshhold reseed count */ + struct pool { + struct source { + u_int bits; /* estimated bits of entropy */ + u_int frac; /* fractional bits of entropy + (given as 1024/n) */ + } source[ENTROPYSOURCE]; + u_int thresh; /* pool reseed threshhold */ + struct randomdev_hash hash; /* accumulated entropy */ + } pool[2]; /* pool[0] is fast, pool[1] is slow */ + u_int which; /* toggle - sets the current insertion pool */ +} random_state; + RANDOM_CHECK_UINT(gengateinterval, 4, 64); RANDOM_CHECK_UINT(bins, 2, 16); -RANDOM_CHECK_UINT(fastthresh, BLOCKSIZE/4, BLOCKSIZE); -RANDOM_CHECK_UINT(slowthresh, BLOCKSIZE/4, BLOCKSIZE); +RANDOM_CHECK_UINT(fastthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */ +RANDOM_CHECK_UINT(slowthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */ RANDOM_CHECK_UINT(slowoverthresh, 1, 5); -/* Structure holding the entropy state */ -static struct random_state random_state; - static void generator_gate(void); static void reseed(u_int); /* The reseed thread mutex */ struct mtx random_reseed_mtx; +/* 128-bit C = 0 */ +/* Nothing to see here, folks, just an ugly mess. */ +static void +clear_counter(void) +{ + random_state.counter.qword[0] = 0UL; + random_state.counter.qword[1] = 0UL; +} + +/* 128-bit C = C + 1 */ +/* Nothing to see here, folks, just an ugly mess. */ +static void +increment_counter(void) +{ + random_state.counter.qword[0]++; + if (!random_state.counter.qword[0]) + random_state.counter.qword[1]++; +} + /* Process a single stochastic event off the harvest queue */ void random_process_event(struct harvest *event) @@ -71,13 +118,13 @@ random_process_event(struct harvest *event) /* Unpack the event into the appropriate source accumulator */ pl = random_state.which; source = &random_state.pool[pl].source[event->source]; - yarrow_hash_iterate(&random_state.pool[pl].hash, event->entropy, + randomdev_hash_iterate(&random_state.pool[pl].hash, event->entropy, sizeof(event->entropy)); - yarrow_hash_iterate(&random_state.pool[pl].hash, &event->somecounter, + randomdev_hash_iterate(&random_state.pool[pl].hash, &event->somecounter, sizeof(event->somecounter)); source->frac += event->frac; - source->bits += event->bits + source->frac/1024; - source->frac %= 1024; + source->bits += event->bits + (source->frac >> 12); /* bits + frac/0x1000 */ + source->frac &= 0xFFF; /* Keep the fractional bits */ /* Count the over-threshold sources in each pool */ for (pl = 0; pl < 2; pl++) { @@ -132,14 +179,14 @@ random_yarrow_init_alg(struct sysctl_ctx_list *clist) SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, "fastthresh", CTLTYPE_INT|CTLFLAG_RW, - &random_state.pool[0].thresh, (3*BLOCKSIZE)/4, + &random_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4, random_check_uint_fastthresh, "I", "Fast reseed threshold"); SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, "slowthresh", CTLTYPE_INT|CTLFLAG_RW, - &random_state.pool[1].thresh, BLOCKSIZE, + &random_state.pool[1].thresh, (BLOCKSIZE*8), random_check_uint_slowthresh, "I", "Slow reseed threshold"); @@ -152,21 +199,20 @@ random_yarrow_init_alg(struct sysctl_ctx_list *clist) random_state.gengateinterval = 10; random_state.bins = 10; - random_state.pool[0].thresh = (3*BLOCKSIZE)/4; - random_state.pool[1].thresh = BLOCKSIZE; + random_state.pool[0].thresh = (3*(BLOCKSIZE*8))/4; + random_state.pool[1].thresh = (BLOCKSIZE*8); random_state.slowoverthresh = 2; random_state.which = FAST; /* Initialise the fast and slow entropy pools */ for (i = 0; i < 2; i++) - yarrow_hash_init(&random_state.pool[i].hash); + randomdev_hash_init(&random_state.pool[i].hash); /* Clear the counter */ - for (i = 0; i < 4; i++) - random_state.counter[i] = 0; + clear_counter(); /* Set up a lock for the reseed process */ - mtx_init(&random_reseed_mtx, "random reseed", NULL, MTX_DEF); + mtx_init(&random_reseed_mtx, "Yarrow reseed", NULL, MTX_DEF); } void @@ -181,10 +227,10 @@ reseed(u_int fastslow) /* Interrupt-context stack is a limited resource; make large * structures static. */ - static u_char v[TIMEBIN][KEYSIZE]; /* v[i] */ - static struct yarrowhash context; - u_char hash[KEYSIZE]; /* h' */ - u_char temp[KEYSIZE]; + static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */ + static struct randomdev_hash context; + uint8_t hash[KEYSIZE]; /* h' */ + uint8_t temp[KEYSIZE]; u_int i; enum esource j; @@ -193,15 +239,15 @@ reseed(u_int fastslow) /* 1. Hash the accumulated entropy into v[0] */ - yarrow_hash_init(&context); + randomdev_hash_init(&context); /* Feed the slow pool hash in if slow */ if (fastslow == SLOW) - yarrow_hash_iterate(&context, + randomdev_hash_iterate(&context, &random_state.pool[SLOW].hash, - sizeof(struct yarrowhash)); - yarrow_hash_iterate(&context, - &random_state.pool[FAST].hash, sizeof(struct yarrowhash)); - yarrow_hash_finish(&context, v[0]); + sizeof(struct randomdev_hash)); + randomdev_hash_iterate(&context, + &random_state.pool[FAST].hash, sizeof(struct randomdev_hash)); + randomdev_hash_finish(&context, v[0]); /* 2. Compute hash values for all v. _Supposed_ to be computationally * intensive. @@ -210,34 +256,33 @@ reseed(u_int fastslow) if (random_state.bins > TIMEBIN) random_state.bins = TIMEBIN; for (i = 1; i < random_state.bins; i++) { - yarrow_hash_init(&context); + randomdev_hash_init(&context); /* v[i] #= h(v[i - 1]) */ - yarrow_hash_iterate(&context, v[i - 1], KEYSIZE); + randomdev_hash_iterate(&context, v[i - 1], KEYSIZE); /* v[i] #= h(v[0]) */ - yarrow_hash_iterate(&context, v[0], KEYSIZE); + randomdev_hash_iterate(&context, v[0], KEYSIZE); /* v[i] #= h(i) */ - yarrow_hash_iterate(&context, &i, sizeof(u_int)); + randomdev_hash_iterate(&context, &i, sizeof(u_int)); /* Return the hashval */ - yarrow_hash_finish(&context, v[i]); + randomdev_hash_finish(&context, v[i]); } /* 3. Compute a new key; h' is the identity function here; * it is not being ignored! */ - yarrow_hash_init(&context); - yarrow_hash_iterate(&context, &random_state.key, KEYSIZE); + randomdev_hash_init(&context); + randomdev_hash_iterate(&context, &random_state.key, KEYSIZE); for (i = 1; i < random_state.bins; i++) - yarrow_hash_iterate(&context, &v[i], KEYSIZE); - yarrow_hash_finish(&context, temp); - yarrow_encrypt_init(&random_state.key, temp); + randomdev_hash_iterate(&context, &v[i], KEYSIZE); + randomdev_hash_finish(&context, temp); + randomdev_encrypt_init(&random_state.key, temp); /* 4. Recompute the counter */ - for (i = 0; i < 4; i++) - random_state.counter[i] = 0; - yarrow_encrypt(&random_state.key, random_state.counter, temp); - memcpy(random_state.counter, temp, sizeof(random_state.counter)); + clear_counter(); + randomdev_encrypt(&random_state.key, random_state.counter.byte, temp, BLOCKSIZE); + memcpy(random_state.counter.byte, temp, BLOCKSIZE); /* 5. Reset entropy estimate accumulators to zero */ @@ -258,7 +303,7 @@ reseed(u_int fastslow) /* XXX Not done here yet */ /* Unblock the device if it was blocked due to being unseeded */ - random_yarrow_unblock(); + randomdev_unblock(); /* Release the reseed mutex */ mtx_unlock(&random_reseed_mtx); @@ -270,7 +315,7 @@ random_yarrow_read(void *buf, int count) { static int cur = 0; static int gate = 1; - static u_char genval[KEYSIZE]; + static uint8_t genval[KEYSIZE]; size_t tomove; int i; int retval; @@ -283,16 +328,14 @@ random_yarrow_read(void *buf, int count) random_state.outputblocks = 0; gate = 0; } - if (count > 0 && (size_t)count >= sizeof(random_state.counter)) { + if (count > 0 && (size_t)count >= BLOCKSIZE) { retval = 0; - for (i = 0; i < count; i += (int)sizeof(random_state.counter)) { - random_state.counter[0]++; - yarrow_encrypt(&random_state.key, random_state.counter, - genval); - tomove = min(count - i, sizeof(random_state.counter)); + for (i = 0; i < count; i += BLOCKSIZE) { + increment_counter(); + randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE); + tomove = MIN(count - i, BLOCKSIZE); memcpy((char *)buf + i, genval, tomove); - if (++random_state.outputblocks >= - random_state.gengateinterval) { + if (++random_state.outputblocks >= random_state.gengateinterval) { generator_gate(); random_state.outputblocks = 0; } @@ -302,13 +345,11 @@ random_yarrow_read(void *buf, int count) } else { if (!cur) { - random_state.counter[0]++; - yarrow_encrypt(&random_state.key, random_state.counter, - genval); + increment_counter(); + randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE); memcpy(buf, genval, (size_t)count); - cur = (int)sizeof(random_state.counter) - count; - if (++random_state.outputblocks >= - random_state.gengateinterval) { + cur = BLOCKSIZE - count; + if (++random_state.outputblocks >= random_state.gengateinterval) { generator_gate(); random_state.outputblocks = 0; } @@ -316,9 +357,7 @@ random_yarrow_read(void *buf, int count) } else { retval = MIN(cur, count); - memcpy(buf, - &genval[(int)sizeof(random_state.counter) - cur], - (size_t)retval); + memcpy(buf, &genval[BLOCKSIZE - cur], (size_t)retval); cur -= retval; } } @@ -330,17 +369,15 @@ static void generator_gate(void) { u_int i; - u_char temp[KEYSIZE]; + uint8_t temp[KEYSIZE]; - for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) { - random_state.counter[0]++; - yarrow_encrypt(&random_state.key, random_state.counter, - &(temp[i])); + for (i = 0; i < KEYSIZE; i += BLOCKSIZE) { + increment_counter(); + randomdev_encrypt(&random_state.key, random_state.counter.byte, temp + i, BLOCKSIZE); } - yarrow_encrypt_init(&random_state.key, temp); + randomdev_encrypt_init(&random_state.key, temp); memset((void *)temp, 0, KEYSIZE); - } /* Helper routine to perform explicit reseeds */ diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h index 558354d27f73..0bde5b582d32 100644 --- a/sys/dev/random/yarrow.h +++ b/sys/dev/random/yarrow.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2004 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,34 +26,7 @@ * $FreeBSD$ */ -/* This contains Yarrow-specific declarations. - * See http://www.counterpane.com/yarrow.html - */ - -#define TIMEBIN 16 /* max value for Pt/t */ - -#define FAST 0 -#define SLOW 1 - -/* This is the beastie that needs protecting. It contains all of the - * state that we are excited about. - * Exactly one will be instantiated. - */ -struct random_state { - u_int64_t counter[4]; /* C - 256 bits */ - struct yarrowkey key; /* K */ - u_int gengateinterval; /* Pg */ - u_int bins; /* Pt/t */ - u_int outputblocks; /* count output blocks for gates */ - u_int slowoverthresh; /* slow pool overthreshhold reseed count */ - struct pool { - struct source { - u_int bits; /* estimated bits of entropy */ - u_int frac; /* fractional bits of entropy - (given as 1024/n) */ - } source[ENTROPYSOURCE]; - u_int thresh; /* pool reseed threshhold */ - struct yarrowhash hash; /* accumulated entropy */ - } pool[2]; /* pool[0] is fast, pool[1] is slow */ - u_int which; /* toggle - sets the current insertion pool */ -}; +void random_yarrow_init_alg(struct sysctl_ctx_list *); +void random_yarrow_deinit_alg(void); +int random_yarrow_read(void *, int); +void random_yarrow_reseed(void); diff --git a/sys/dev/rndtest/rndtest.c b/sys/dev/rndtest/rndtest.c index 13ecdd6b0105..3c42972c36f7 100644 --- a/sys/dev/rndtest/rndtest.c +++ b/sys/dev/rndtest/rndtest.c @@ -152,7 +152,7 @@ rndtest_harvest(struct rndtest_state *rsp, void *buf, u_int len) for (len /= sizeof (u_int32_t); len; len--) add_true_randomness(*p++); #else - random_harvest(buf, len, len*NBBY, 0, RANDOM_PURE); + random_harvest(buf, len, len*NBBY/2, 0, RANDOM_PURE); #endif } } diff --git a/sys/dev/safe/safe.c b/sys/dev/safe/safe.c index 6bfcf26032f4..721b9f4b2b60 100644 --- a/sys/dev/safe/safe.c +++ b/sys/dev/safe/safe.c @@ -211,7 +211,7 @@ safe_partname(struct safe_softc *sc) static void default_harvest(struct rndtest_state *rsp, void *buf, u_int count) { - random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE); + random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE); } #endif /* SAFE_NO_RNG */ diff --git a/sys/dev/ubsec/ubsec.c b/sys/dev/ubsec/ubsec.c index 2c0fad4fa93f..0e1b7cb5df67 100644 --- a/sys/dev/ubsec/ubsec.c +++ b/sys/dev/ubsec/ubsec.c @@ -259,7 +259,7 @@ ubsec_partname(struct ubsec_softc *sc) static void default_harvest(struct rndtest_state *rsp, void *buf, u_int count) { - random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE); + random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE); } static int diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index 63d84694a560..f4b04c3f71b4 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -1147,7 +1147,7 @@ swi_sched(void *cookie, int flags) entropy.event = (uintptr_t)ih; entropy.td = curthread; random_harvest(&entropy, sizeof(entropy), 1, 0, - RANDOM_INTERRUPT); + RANDOM_SWI); } /* diff --git a/sys/mips/cavium/octeon_rnd.c b/sys/mips/cavium/octeon_rnd.c index 634a4fa86f04..298f06aee1dd 100644 --- a/sys/mips/cavium/octeon_rnd.c +++ b/sys/mips/cavium/octeon_rnd.c @@ -131,7 +131,7 @@ octeon_rnd_harvest(void *arg) for (i = 0; i < OCTEON_RND_WORDS; i++) sc->sc_entropy[i] = cvmx_rng_get_random64(); random_harvest(sc->sc_entropy, sizeof sc->sc_entropy, - sizeof sc->sc_entropy * 8, 0, RANDOM_PURE); + (sizeof(sc->sc_entropy)*8)/2, 0, RANDOM_PURE); callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc); } diff --git a/sys/modules/random/Makefile b/sys/modules/random/Makefile index ad14899e7efc..60b62afde1d9 100644 --- a/sys/modules/random/Makefile +++ b/sys/modules/random/Makefile @@ -5,7 +5,7 @@ .PATH: ${.CURDIR}/../../crypto/sha2 KMOD= random -SRCS= randomdev.c probe.c +SRCS= randomdev.c .if ${MACHINE} == "amd64" || ${MACHINE} == "i386" SRCS+= nehemiah.c SRCS+= ivy.c diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index e8d395ad46cb..638b3647f6ba 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -638,9 +638,8 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m) m->m_flags |= M_PROMISC; } - /* First chunk of an mbuf contains good entropy */ if (harvest.ethernet) - random_harvest(m, 16, 3, 0, RANDOM_NET); + random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_ETHER); ether_demux(ifp, m); CURVNET_RESTORE(); diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index fba423dc5d2f..e67b213e636f 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -920,9 +920,8 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag) m_freem(m); return (EAFNOSUPPORT); } - /* First chunk of an mbuf contains good junk */ if (harvest.point_to_point) - random_harvest(m, 16, 3, 0, RANDOM_NET); + random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_TUN); ifp->if_ibytes += m->m_pkthdr.len; ifp->if_ipackets++; CURVNET_SET(ifp->if_vnet); diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c index e6ac5085368d..72fc16201df9 100644 --- a/sys/netgraph/ng_iface.c +++ b/sys/netgraph/ng_iface.c @@ -774,9 +774,8 @@ ng_iface_rcvdata(hook_p hook, item_p item) m_freem(m); return (EAFNOSUPPORT); } - /* First chunk of an mbuf contains good junk */ if (harvest.point_to_point) - random_harvest(m, 16, 3, 0, RANDOM_NET); + random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_NG); M_SETFIB(m, ifp->if_fib); netisr_dispatch(isr, m); return (0); diff --git a/sys/sys/random.h b/sys/sys/random.h index 5cf1611e359c..2f86c82e854a 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 Mark R. V. Murray + * Copyright (c) 2000-2013 Mark R. V. Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,8 +42,11 @@ enum esource { RANDOM_WRITE = 0, RANDOM_KEYBOARD, RANDOM_MOUSE, - RANDOM_NET, + RANDOM_NET_TUN, + RANDOM_NET_ETHER, + RANDOM_NET_NG, RANDOM_INTERRUPT, + RANDOM_SWI, RANDOM_PURE, ENTROPYSOURCE }; @@ -57,6 +60,7 @@ struct harvest_select { int point_to_point; int interrupt; int swi; + int namei; }; extern struct harvest_select harvest;