diff --git a/bsd/sys/dev/random/dummy_rng.c b/bsd/sys/dev/random/dummy_rng.c new file mode 100644 index 0000000000000000000000000000000000000000..810a784a3b1fdce5aae2416ae82a1a29bae4ad40 --- /dev/null +++ b/bsd/sys/dev/random/dummy_rng.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/systm.h> +#include <sys/time.h> + +#include <dev/random/random_adaptors.h> +#include <dev/random/randomdev.h> + +static struct mtx dummy_random_mtx; + +/* Used to fake out unused random calls in random_adaptor */ +static void +random_null_func(void) +{ +} + +static int +dummy_random_poll(int events __unused, struct thread *td __unused) +{ + + return (0); +} + +static int +dummy_random_block(int flag) +{ + int error = 0; + + mtx_lock(&dummy_random_mtx); + + /* Blocking logic */ + while (!error) { + if (flag & O_NONBLOCK) + error = EWOULDBLOCK; + else { + printf("random: dummy device blocking on read.\n"); + error = msleep(&dummy_random_block, + &dummy_random_mtx, + PUSER | PCATCH, "block", 0); + } + } + mtx_unlock(&dummy_random_mtx); + + return (error); +} + +static void +dummy_random_init(void) +{ + + mtx_init(&dummy_random_mtx, "sleep mtx for dummy_random", + NULL, MTX_DEF); +} + +static void +dummy_random_deinit(void) +{ + + mtx_destroy(&dummy_random_mtx); +} + +struct random_adaptor dummy_random = { + .ident = "Dummy entropy device that always blocks", + .init = dummy_random_init, + .deinit = dummy_random_deinit, + .block = dummy_random_block, + .poll = dummy_random_poll, + .read = (random_read_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 0, /* This device can never be seeded */ + .priority = 1, /* Bottom priority, so goes to last position */ +}; + +static int +dummy_random_modevent(module_t mod __unused, int type, void *unused __unused) +{ + + switch (type) { + case MOD_LOAD: + random_adaptor_register("dummy", &dummy_random); + EVENTHANDLER_INVOKE(random_adaptor_attach, + &dummy_random); + + return (0); + } + + return (EINVAL); +} + +RANDOM_ADAPTOR_MODULE(dummy, dummy_random_modevent, 1); diff --git a/bsd/sys/dev/random/harvest.c b/bsd/sys/dev/random/harvest.c new file mode 100644 index 0000000000000000000000000000000000000000..9dbae8449b35fa8e174268a5947b6afd5e92bd0e --- /dev/null +++ b/bsd/sys/dev/random/harvest.c @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/poll.h> +#include <sys/queue.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/syslog.h> +#include <sys/systm.h> +#include <sys/sysctl.h> + +#include <machine/cpu.h> + +#include <dev/random/randomdev_soft.h> + +static int read_random_phony(void *, int); + +/* Structure holding the desired entropy sources */ +struct harvest_select harvest = { 1, 1, 1, 1 }; +static int warned = 0; + +/* hold the address of the routine which is actually called if + * the randomdev is loaded + */ +static void (*reap_func)(u_int64_t, const void *, u_int, u_int, + enum esource) = NULL; +static int (*read_func)(void *, int) = read_random_phony; + +/* Initialise the harvester at load time */ +void +randomdev_init_harvester(void (*reaper)(u_int64_t, const void *, u_int, + u_int, enum esource), int (*reader)(void *, int)) +{ + reap_func = reaper; + read_func = reader; +} + +/* Deinitialise the harvester at unload time */ +void +randomdev_deinit_harvester(void) +{ + reap_func = NULL; + read_func = read_random_phony; + warned = 0; +} + +/* Entropy harvesting routine. This is supposed to be fast; do + * not do anything slow in here! + * Implemented as in indirect call to allow non-inclusion of + * the entropy device. + * + * XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle + * counters are built in, but on older hardware it will do a real time clock + * read which can be quite expensive. + */ +void +random_harvest(const void *entropy, u_int count, u_int bits, enum esource origin) +{ + if (reap_func) + (*reap_func)(get_cyclecount(), entropy, count, bits, origin); +} + +/* Userland-visible version of read_random */ +int +read_random(void *buf, int count) +{ + return ((*read_func)(buf, count)); +} + +/* If the entropy device is not loaded, make a token effort to + * provide _some_ kind of randomness. This should only be used + * inside other RNG's, like arc4random(9). + */ +static int +read_random_phony(void *buf, int count) +{ + u_long randval; + int size, i; + + if (!warned) { + log(LOG_WARNING, "random device not loaded; using insecure entropy\n"); + warned = 1; + } + + /* srandom() is called in kern/init_main.c:proc0_post() */ + + /* Fill buf[] with random(9) output */ + for (i = 0; i < count; i+= (int)sizeof(u_long)) { + randval = random(); + size = MIN(count - i, sizeof(u_long)); + memcpy(&((char *)buf)[i], &randval, (size_t)size); + } + + return (count); +} + +/* Helper routine to enable kproc_exit() to work while the module is + * being (or has been) unloaded. + * This routine is in this file because it is always linked into the kernel, + * and will thus never be unloaded. This is critical for unloadable modules + * that have threads. + */ +void +random_set_wakeup_exit(void *control) +{ + wakeup(control); + kproc_exit(0); + /* NOTREACHED */ +} diff --git a/bsd/sys/dev/random/hash.c b/bsd/sys/dev/random/hash.c new file mode 100644 index 0000000000000000000000000000000000000000..cf0feaa66ef9ebe6cd4a0c8a93957ae5f3705bd5 --- /dev/null +++ b/bsd/sys/dev/random/hash.c @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> + +#include <crypto/rijndael/rijndael-api-fst.h> +#include <crypto/sha2/sha2.h> + +#include <dev/random/hash.h> + +/* Initialise the hash */ +void +randomdev_hash_init(struct randomdev_hash *context) +{ + SHA256_Init(&context->sha); +} + +/* Iterate the hash */ +void +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 + * KEYSIZE bytes long. + */ +void +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. Use CBC mode for better avalanche. + */ +void +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. + * <length> bytes are encrypted from <*d_in> to <*d_out>. <length> must be + * a multiple of BLOCKSIZE. + */ +void +randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, unsigned length) +{ + rijndael_blockEncrypt(&context->cipher, &context->key, d_in, length*8, d_out); +} diff --git a/bsd/sys/dev/random/hash.h b/bsd/sys/dev/random/hash.h new file mode 100644 index 0000000000000000000000000000000000000000..4e6a4a0db831c4a7f9cf5728701839a77a398a9f --- /dev/null +++ b/bsd/sys/dev/random/hash.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_HASH_H_INCLUDED +#define SYS_DEV_RANDOM_HASH_H_INCLUDED + +#define KEYSIZE 32 /* (in bytes) == 256 bits */ +#define BLOCKSIZE 16 /* (in bytes) == 128 bits */ + +struct randomdev_hash { /* Big! Make static! */ + SHA256_CTX sha; +}; + +struct randomdev_key { /* Big! Make static! */ + keyInstance key; /* Key schedule */ + cipherInstance cipher; /* Rijndael internal */ +}; + +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); + +#endif diff --git a/bsd/sys/dev/random/ivy.c b/bsd/sys/dev/random/ivy.c new file mode 100644 index 0000000000000000000000000000000000000000..9b4001692adaaa4c663afeff2311518d0a4e0f1e --- /dev/null +++ b/bsd/sys/dev/random/ivy.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org> + * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org> + * All rights reserved. + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/systm.h> + +#include <machine/md_var.h> +#include <machine/specialreg.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> +#include <dev/random/random_adaptors.h> + +#define RETRY_COUNT 10 + +static int random_ivy_read(void *, int); + +static struct random_hardware_source random_ivy = { + .ident = "Hardware, Intel IvyBridge+ RNG", + .source = RANDOM_PURE_RDRAND, + .read = random_ivy_read +}; + +static inline int +ivy_rng_store(long *buf) +{ +#ifdef __GNUCLIKE_ASM + long tmp; + int retry; + + retry = RETRY_COUNT; + __asm __volatile( + "1:\n\t" + "rdrand %2\n\t" /* read randomness into tmp */ + "jb 2f\n\t" /* CF is set on success, exit retry loop */ + "dec %0\n\t" /* otherwise, retry-- */ + "jne 1b\n\t" /* and loop if retries are not exhausted */ + "jmp 3f\n" /* failure, retry is 0, used as return value */ + "2:\n\t" + "mov %2,%1\n\t" /* *buf = tmp */ + "3:" + : "+q" (retry), "=m" (*buf), "=q" (tmp) : : "cc"); + return (retry); +#else /* __GNUCLIKE_ASM */ + return (0); +#endif +} + +static int +random_ivy_read(void *buf, int c) +{ + long *b; + int count; + + KASSERT(c % sizeof(long) == 0, ("partial read %d", c)); + for (b = buf, count = c; count > 0; count -= sizeof(long), b++) { + if (ivy_rng_store(b) == 0) + break; + } + return (c - count); +} + +static int +rdrand_modevent(module_t mod, int type, void *unused) +{ + int error = 0; + + switch (type) { + case MOD_LOAD: + if (cpu_feature2 & CPUID2_RDRAND) + live_entropy_source_register(&random_ivy); + else +#ifndef KLD_MODULE + if (bootverbose) +#endif + printf("%s: RDRAND is not present\n", + random_ivy.ident); + break; + + case MOD_UNLOAD: + if (cpu_feature2 & CPUID2_RDRAND) + live_entropy_source_deregister(&random_ivy); + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + + } + + return (error); +} + +LIVE_ENTROPY_SRC_MODULE(random_rdrand, rdrand_modevent, 1); diff --git a/bsd/sys/dev/random/live_entropy_sources.c b/bsd/sys/dev/random/live_entropy_sources.c new file mode 100644 index 0000000000000000000000000000000000000000..d406ebd20861bf3da0178391db70928a4bea6b6b --- /dev/null +++ b/bsd/sys/dev/random/live_entropy_sources.c @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * Copyright (c) 2013 Mark R V Murray + * 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 <sys/param.h> +__FBSDID("$FreeBSD$"); + +#include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/sx.h> +#include <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/unistd.h> + +#include <machine/cpu.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/random_harvestq.h> + +#include "live_entropy_sources.h" + +LIST_HEAD(les_head, live_entropy_sources); +static struct les_head sources = LIST_HEAD_INITIALIZER(sources); + +/* + * The live_lock protects the consistency of the "struct les_head sources" + */ +static struct sx les_lock; /* need a sleepable lock */ + +void +live_entropy_source_register(struct random_hardware_source *rsource) +{ + struct live_entropy_sources *les; + + KASSERT(rsource != NULL, ("invalid input to %s", __func__)); + + les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK); + les->rsource = rsource; + + sx_xlock(&les_lock); + LIST_INSERT_HEAD(&sources, les, entries); + sx_xunlock(&les_lock); +} + +void +live_entropy_source_deregister(struct random_hardware_source *rsource) +{ + struct live_entropy_sources *les = NULL; + + KASSERT(rsource != NULL, ("invalid input to %s", __func__)); + + sx_xlock(&les_lock); + LIST_FOREACH(les, &sources, entries) + if (les->rsource == rsource) { + LIST_REMOVE(les, entries); + break; + } + sx_xunlock(&les_lock); + if (les != NULL) + free(les, M_ENTROPY); +} + +static int +live_entropy_source_handler(SYSCTL_HANDLER_ARGS) +{ + struct live_entropy_sources *les; + int error, count; + + count = error = 0; + + sx_slock(&les_lock); + + if (LIST_EMPTY(&sources)) + error = SYSCTL_OUT(req, "", 0); + else { + LIST_FOREACH(les, &sources, entries) { + + error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); + if (error) + break; + + error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident)); + if (error) + break; + } + } + + sx_sunlock(&les_lock); + + return (error); +} + +static void +live_entropy_sources_init(void *unused) +{ + + SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, live_entropy_source_handler, "", + "List of Active Live Entropy Sources"); + + sx_init(&les_lock, "live_entropy_sources"); +} + +/* + * Run through all "live" 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! + * Remember that we are NOT holding harvest_mtx on entry! + */ +void +live_entropy_sources_feed(int rounds, event_proc_f entropy_processor) +{ + static struct harvest event; + static uint8_t buf[HARVESTSIZE]; + struct live_entropy_sources *les; + int i, n; + + sx_slock(&les_lock); + + /* + * Walk over all of live entropy sources, and feed their output + * to the system-wide RNG. + */ + LIST_FOREACH(les, &sources, entries) { + + for (i = 0; i < rounds; i++) { + /* + * This should be quick, since it's a live entropy + * source. + */ + /* FIXME: Whine loudly if this didn't work. */ + n = les->rsource->read(buf, sizeof(buf)); + n = MIN(n, HARVESTSIZE); + + event.somecounter = get_cyclecount(); + event.size = n; + event.bits = (n*8)/2; + event.source = les->rsource->source; + memcpy(event.entropy, buf, n); + + /* Do the actual entropy insertion */ + entropy_processor(&event); + } + + } + + sx_sunlock(&les_lock); +} + +static void +live_entropy_sources_deinit(void *unused) +{ + + sx_destroy(&les_lock); +} + +SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, + live_entropy_sources_init, NULL); +SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, + live_entropy_sources_deinit, NULL); diff --git a/bsd/sys/dev/random/live_entropy_sources.h b/bsd/sys/dev/random/live_entropy_sources.h new file mode 100644 index 0000000000000000000000000000000000000000..9a23070fa6379240f4bd002548cd04902165dfbe --- /dev/null +++ b/bsd/sys/dev/random/live_entropy_sources.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * Copyright (c) 2013 Mark R V Murray + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED +#define SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED + +/* + * Live entropy source is a source of entropy that can provide + * specified or approximate amount of entropy immediately upon request or within + * an acceptable amount of time. + */ +struct live_entropy_sources { + LIST_ENTRY(live_entropy_sources) entries; /* list of providers */ + struct random_hardware_source *rsource; /* associated random adaptor */ +}; + +extern struct mtx live_mtx; + +void live_entropy_source_register(struct random_hardware_source *); +void live_entropy_source_deregister(struct random_hardware_source *); +void live_entropy_sources_feed(int, event_proc_f); + +#define LIVE_ENTROPY_SRC_MODULE(name, modevent, ver) \ + static moduledata_t name##_mod = { \ + #name, \ + modevent, \ + 0 \ + }; \ + DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \ + SI_ORDER_SECOND); \ + MODULE_VERSION(name, ver); \ + MODULE_DEPEND(name, random, 1, 1, 1); + +#endif /* SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED */ diff --git a/bsd/sys/dev/random/nehemiah.c b/bsd/sys/dev/random/nehemiah.c new file mode 100644 index 0000000000000000000000000000000000000000..b60689e2bc64c782a4415d73b09c4b38b536e40a --- /dev/null +++ b/bsd/sys/dev/random/nehemiah.c @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 2013 Mark R V Murray + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/systm.h> + +#include <machine/segments.h> +#include <machine/pcb.h> +#include <machine/md_var.h> +#include <machine/specialreg.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> +#include <dev/random/random_adaptors.h> + +static void random_nehemiah_init(void); +static void random_nehemiah_deinit(void); +static int random_nehemiah_read(void *, int); + +static struct random_hardware_source random_nehemiah = { + .ident = "Hardware, VIA Nehemiah Padlock RNG", + .source = RANDOM_PURE_NEHEMIAH, + .read = random_nehemiah_read +}; + +/* TODO: now that the Davies-Meyer hash is gone and we only use + * the 'xstore' instruction, do we still need to preserve the + * FPU state with fpu_kern_(enter|leave)() ? + */ +static struct fpu_kern_ctx *fpu_ctx_save; + +/* This H/W source never stores more than 8 bytes in one go */ +/* ARGSUSED */ +static __inline size_t +VIA_RNG_store(void *buf) +{ + uint32_t retval = 0; + uint32_t rate = 0; + +#ifdef __GNUCLIKE_ASM + __asm __volatile( + "movl $0,%%edx\n\t" + ".byte 0x0f, 0xa7, 0xc0" /* xstore */ + : "=a" (retval), "+d" (rate), "+D" (buf) + : + : "memory" + ); +#endif + if (rate == 0) + return (retval&0x1f); + return (0); +} + +static void +random_nehemiah_init(void) +{ + + fpu_ctx_save = fpu_kern_alloc_ctx(FPU_KERN_NORMAL); +} + +static void +random_nehemiah_deinit(void) +{ + + fpu_kern_free_ctx(fpu_ctx_save); +} + +static int +random_nehemiah_read(void *buf, int c) +{ + uint8_t *b; + size_t count, ret; + uint64_t tmp; + + if ((fpu_kern_enter(curthread, fpu_ctx_save, FPU_KERN_NORMAL) == 0)) { + b = buf; + for (count = c; count > 0; count -= ret) { + ret = MIN(VIA_RNG_store(&tmp), count); + memcpy(b, &tmp, ret); + b += ret; + } + fpu_kern_leave(curthread, fpu_ctx_save); + } + else + c = 0; + + return (c); +} + +static int +nehemiah_modevent(module_t mod, int type, void *unused) +{ + int error = 0; + + switch (type) { + case MOD_LOAD: + if (via_feature_rng & VIA_HAS_RNG) { + live_entropy_source_register(&random_nehemiah); + random_nehemiah_init(); + } else +#ifndef KLD_MODULE + if (bootverbose) +#endif + printf("%s: VIA Padlock RNG not present\n", + random_nehemiah.ident); + break; + + case MOD_UNLOAD: + if (via_feature_rng & VIA_HAS_RNG) + random_nehemiah_deinit(); + live_entropy_source_deregister(&random_nehemiah); + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + + } + + return (error); +} + +LIVE_ENTROPY_SRC_MODULE(nehemiah, nehemiah_modevent, 1); diff --git a/bsd/sys/dev/random/random_adaptors.c b/bsd/sys/dev/random/random_adaptors.c new file mode 100644 index 0000000000000000000000000000000000000000..4f5ad2c1ebe166011aa85d81a073698827d2b572 --- /dev/null +++ b/bsd/sys/dev/random/random_adaptors.c @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org> + * Copyright (c) 2013 Mark R V Murray + * 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 <sys/param.h> +__FBSDID("$FreeBSD$"); + +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/libkern.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/sx.h> +#include <sys/sysctl.h> +#include <sys/unistd.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> + +LIST_HEAD(adaptors_head, random_adaptors); +static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors); +static struct sx adaptors_lock; /* need a sleepable lock */ + +/* List for the dynamic sysctls */ +static struct sysctl_ctx_list random_clist; + +struct random_adaptor *random_adaptor; + +MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); + +int +random_adaptor_register(const char *name, struct random_adaptor *rsp) +{ + struct random_adaptors *rpp; + + KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__)); + + rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK); + rpp->name = name; + rpp->rsp = rsp; + + sx_xlock(&adaptors_lock); + LIST_INSERT_HEAD(&adaptors, rpp, entries); + sx_xunlock(&adaptors_lock); + + return (0); +} + +struct random_adaptor * +random_adaptor_get(const char *name) +{ + struct random_adaptors *rpp; + struct random_adaptor *rsp; + + rsp = NULL; + + sx_slock(&adaptors_lock); + + LIST_FOREACH(rpp, &adaptors, entries) + if (strcmp(rpp->name, name) == 0) + rsp = rpp->rsp; + + sx_sunlock(&adaptors_lock); + + return (rsp); +} + +/* + * 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 *rppi, *ramax; + unsigned primax; + + KASSERT(adaptor != NULL, ("pre-conditions failed")); + + *adaptor = NULL; + if (TUNABLE_STR_FETCH("kern.random.active_adaptor", 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); + } + + primax = 0U; + if (*adaptor == NULL) { + /* + * Fall back to the highest priority item on the available + * RNG list. + */ + sx_slock(&adaptors_lock); + + ramax = NULL; + LIST_FOREACH(rppi, &adaptors, entries) { + if (rppi->rsp->priority >= primax) { + ramax = rppi; + primax = rppi->rsp->priority; + } + } + if (ramax != NULL) + *adaptor = ramax->rsp; + + sx_sunlock(&adaptors_lock); + + if (bootverbose && *adaptor) + printf("Falling back to <%s> random adaptor\n", + (*adaptor)->ident); + } +} + +static void +random_adaptors_deinit(void *unused) +{ + + sx_destroy(&adaptors_lock); + sysctl_ctx_free(&random_clist); +} + +static int +random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) +{ + struct random_adaptors *rpp; + int error, count; + + count = error = 0; + + sx_slock(&adaptors_lock); + + if (LIST_EMPTY(&adaptors)) + error = SYSCTL_OUT(req, "", 0); + else { + 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); + + 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_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) +{ + + SYSCTL_PROC(_kern_random, OID_AUTO, adaptors, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + 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"); +} + +SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator"); + +SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, random_adaptors_init, + NULL); +SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, + random_adaptors_deinit, NULL); + +static void +random_adaptors_reseed(void *unused) +{ + + (void)unused; + if (random_adaptor != NULL) + (*random_adaptor->reseed)(); + arc4rand(NULL, 0, 1); +} +SYSINIT(random_reseed, SI_SUB_INTRINSIC_POST, SI_ORDER_SECOND, + random_adaptors_reseed, NULL); diff --git a/bsd/sys/dev/random/random_adaptors.h b/bsd/sys/dev/random/random_adaptors.h new file mode 100644 index 0000000000000000000000000000000000000000..4765694a4526a7dce1007f4671bd70d62d7988be --- /dev/null +++ b/bsd/sys/dev/random/random_adaptors.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED + +#include <sys/eventhandler.h> + +MALLOC_DECLARE(M_ENTROPY); + +struct random_adaptors { + LIST_ENTRY(random_adaptors) entries; /* list of providers */ + const char *name; /* name of random adaptor */ + struct random_adaptor *rsp; +}; + +struct random_adaptor *random_adaptor_get(const char *); +int random_adaptor_register(const char *, struct random_adaptor *); +void random_adaptor_choose(struct random_adaptor **); + +extern struct random_adaptor *random_adaptor; + +/* + * random_adaptor's should be registered prior to + * random module (SI_SUB_DRIVERS/SI_ORDER_MIDDLE) + */ +#define RANDOM_ADAPTOR_MODULE(name, modevent, ver) \ + static moduledata_t name##_mod = { \ + #name, \ + modevent, \ + 0 \ + }; \ + DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \ + SI_ORDER_SECOND); \ + MODULE_VERSION(name, ver); \ + MODULE_DEPEND(name, random, 1, 1, 1); + +typedef void (*random_adaptor_attach_hook)(void *, struct random_adaptor *); +EVENTHANDLER_DECLARE(random_adaptor_attach, random_adaptor_attach_hook); + +/* kern.random sysctls */ +#ifdef SYSCTL_DECL /* from sysctl.h */ +SYSCTL_DECL(_kern_random); +#endif /* SYSCTL_DECL */ + +#endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */ diff --git a/bsd/sys/dev/random/random_harvestq.c b/bsd/sys/dev/random/random_harvestq.c new file mode 100644 index 0000000000000000000000000000000000000000..b7b8381c8eb528ffae0a50332fa0c4ac8871f6f4 --- /dev/null +++ b/bsd/sys/dev/random/random_harvestq.c @@ -0,0 +1,322 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * Copyright (c) 2013 Arthur Mesh + * 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_random.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/eventhandler.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/linker.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/sysctl.h> +#include <sys/unistd.h> + +#include <machine/cpu.h> +#include <machine/vmparam.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> +#include <dev/random/rwfile.h> + +#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */ + +/* + * The harvest mutex protects the consistency of the entropy fifos and + * empty fifo and other associated structures. + */ +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; + +/* Harvested entropy */ +static struct entropyfifo harvestfifo; + +/* <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; + +#ifdef RANDOM_RWFILE +static const char *entropy_files[] = { + "/entropy", + NULL +}; +#endif + +/* Deal with entropy cached externally if this is present. + * Lots of policy may eventually arrive in this function. + * Called after / is mounted. + */ +static void +random_harvestq_cache(void *arg __unused) +{ + uint8_t *keyfile, *data; + size_t size, i; +#ifdef RANDOM_RWFILE + const char **entropy_file; + uint8_t *zbuf; + int error; +#endif + + /* Get stuff that may have been preloaded by loader(8) */ + keyfile = preload_search_by_type("/boot/entropy"); + if (keyfile != NULL) { + data = preload_fetch_addr(keyfile); + size = preload_fetch_size(keyfile); + if (data != NULL && size != 0) { + for (i = 0; i < size; i += 16) + random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); + printf("random: read %zu bytes from preloaded cache\n", size); + bzero(data, size); + } + else + printf("random: no preloaded entropy cache available\n"); + } + +#ifdef RANDOM_RWFILE + /* Read and attempt to overwrite the entropy cache files. + * If the file exists, can be read and then overwritten, + * then use it. Ignore it otherwise, but print out what is + * going on. + */ + data = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); + zbuf = __DECONST(void *, zero_region); + for (entropy_file = entropy_files; *entropy_file; entropy_file++) { + error = randomdev_read_file(*entropy_file, data, PAGE_SIZE); + if (error == 0) { + printf("random: entropy cache '%s' provides %ld bytes\n", *entropy_file, (long)PAGE_SIZE); + error = randomdev_write_file(*entropy_file, zbuf, PAGE_SIZE); + if (error == 0) { + printf("random: entropy cache '%s' contents used and successfully overwritten\n", *entropy_file); + for (i = 0; i < PAGE_SIZE; i += 16) + random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); + } + else + printf("random: entropy cache '%s' not overwritten and therefore not used; error = %d\n", *entropy_file, error); + } + else + printf("random: entropy cache '%s' not present or unreadable; error = %d\n", *entropy_file, error); + } + bzero(data, PAGE_SIZE); + free(data, M_ENTROPY); +#endif +} +EVENTHANDLER_DEFINE(mountroot, random_harvestq_cache, NULL, 0); + +static void +random_kthread(void *arg) +{ + STAILQ_HEAD(, harvest) local_queue; + struct harvest *event = NULL; + int local_count; + event_proc_f entropy_processor = arg; + + STAILQ_INIT(&local_queue); + local_count = 0; + + /* Process until told to stop */ + mtx_lock_spin(&harvest_mtx); + for (; random_kthread_control >= 0;) { + + /* + * Grab all the entropy events. + * Drain entropy source records into a thread-local + * queue for processing while not holding the mutex. + */ + STAILQ_CONCAT(&local_queue, &harvestfifo.head); + local_count += harvestfifo.count; + harvestfifo.count = 0; + + /* + * Deal with events, if any. + * Then transfer the used events back into the empty fifo. + */ + if (!STAILQ_EMPTY(&local_queue)) { + mtx_unlock_spin(&harvest_mtx); + STAILQ_FOREACH(event, &local_queue, next) + entropy_processor(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)); + + /* + * Do only one round of the hardware sources for now. + * Later we'll need to make it rate-adaptive. + */ + mtx_unlock_spin(&harvest_mtx); + live_entropy_sources_feed(1, entropy_processor); + mtx_lock_spin(&harvest_mtx); + + /* + * 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; + + /* Initialise the harvest fifos */ + + /* Contains the currently unused event structs. */ + STAILQ_INIT(&emptyfifo.head); + for (i = 0; i < RANDOM_FIFO_MAX; i++) { + np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); + STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); + } + emptyfifo.count = RANDOM_FIFO_MAX; + + /* Will contain the queued-up events. */ + STAILQ_INIT(&harvestfifo.head); + harvestfifo.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; + + /* Destroy the harvest fifos */ + while (!STAILQ_EMPTY(&emptyfifo.head)) { + np = STAILQ_FIRST(&emptyfifo.head); + STAILQ_REMOVE_HEAD(&emptyfifo.head, next); + free(np, M_ENTROPY); + } + emptyfifo.count = 0; + while (!STAILQ_EMPTY(&harvestfifo.head)) { + np = STAILQ_FIRST(&harvestfifo.head); + STAILQ_REMOVE_HEAD(&harvestfifo.head, next); + free(np, M_ENTROPY); + } + harvestfifo.count = 0; + + mtx_destroy(&harvest_mtx); +} + +/* + * Entropy harvesting routine. + * This is supposed to be fast; do not do anything slow in here! + * + * It is also illegal (and morally reprehensible) to insert any + * high-rate data here. "High-rate" is define as a data source + * that will usually cause lots of failures of the "Lockless read" + * check a few lines below. This includes the "always-on" sources + * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. + */ +void +random_harvestq_internal(u_int64_t somecounter, const void *entropy, + u_int count, u_int bits, enum esource origin) +{ + struct harvest *event; + + KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, + ("random_harvest_internal: origin %d invalid\n", origin)); + + /* Lockless read to avoid lock operations if fifo is full. */ + if (harvestfifo.count >= RANDOM_FIFO_MAX) + return; + + mtx_lock_spin(&harvest_mtx); + + /* + * On't overfill the harvest queue; this could steal all + * our memory. + */ + if (harvestfifo.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); + emptyfifo.count--; + event->somecounter = somecounter; + event->size = count; + event->bits = bits; + event->source = origin; + + /* XXXX Come back and make this dynamic! */ + count = MIN(count, HARVESTSIZE); + memcpy(event->entropy, entropy, count); + + STAILQ_INSERT_TAIL(&harvestfifo.head, + event, next); + harvestfifo.count++; + } + } + + mtx_unlock_spin(&harvest_mtx); +} diff --git a/bsd/sys/dev/random/random_harvestq.h b/bsd/sys/dev/random/random_harvestq.h new file mode 100644 index 0000000000000000000000000000000000000000..a2ac3d1f91bc4bed753ba88e97e8275fd5052a58 --- /dev/null +++ b/bsd/sys/dev/random/random_harvestq.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED + +typedef void (*event_proc_f)(struct harvest *event); + +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, enum esource); + +extern int random_kthread_control; +extern struct mtx harvest_mtx; + +#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */ diff --git a/bsd/sys/dev/random/randomdev.c b/bsd/sys/dev/random/randomdev.c new file mode 100644 index 0000000000000000000000000000000000000000..b76cb839a02cf171249142c4f369bf74bf821855 --- /dev/null +++ b/bsd/sys/dev/random/randomdev.c @@ -0,0 +1,233 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/fcntl.h> +#include <sys/filio.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/poll.h> +#include <sys/priv.h> +#include <sys/proc.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/uio.h> +#include <sys/unistd.h> + +#include <machine/bus.h> +#include <machine/cpu.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> + +#define RANDOM_MINOR 0 + +static d_read_t random_read; +static d_write_t random_write; +static d_ioctl_t random_ioctl; +static d_poll_t random_poll; + +static struct cdevsw random_cdevsw = { + .d_version = D_VERSION, + .d_read = random_read, + .d_write = random_write, + .d_ioctl = random_ioctl, + .d_poll = random_poll, + .d_name = "random", +}; + +/* For use with make_dev(9)/destroy_dev(9). */ +static struct cdev *random_dev; + +/* ARGSUSED */ +static int +random_read(struct cdev *dev __unused, struct uio *uio, int flag) +{ + int c, error = 0; + void *random_buf; + + /* Blocking logic */ + if (!random_adaptor->seeded) + error = (*random_adaptor->block)(flag); + + /* The actual read */ + if (!error) { + + random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); + + while (uio->uio_resid > 0 && !error) { + c = MIN(uio->uio_resid, PAGE_SIZE); + c = (*random_adaptor->read)(random_buf, c); + error = uiomove(random_buf, c, uio); + } + /* Finished reading; let the source know so it can do some + * optional housekeeping */ + (*random_adaptor->read)(NULL, 0); + + free(random_buf, M_ENTROPY); + + } + + return (error); +} + +/* ARGSUSED */ +static int +random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) +{ + + /* We used to allow this to insert userland entropy. + * We don't any more because (1) this so-called entropy + * is usually lousy and (b) its vaguely possible to + * mess with entropy harvesting by overdoing a write. + * Now we just ignore input like /dev/null does. + */ + uio->uio_resid = 0; + + return (0); +} + +/* ARGSUSED */ +static int +random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, + int flags __unused, struct thread *td __unused) +{ + int error = 0; + + switch (cmd) { + /* Really handled in upper layer */ + case FIOASYNC: + case FIONBIO: + break; + default: + error = ENOTTY; + } + return (error); +} + +/* ARGSUSED */ +static int +random_poll(struct cdev *dev __unused, int events, struct thread *td) +{ + int revents = 0; + + if (events & (POLLIN | POLLRDNORM)) { + if (random_adaptor->seeded) + revents = events & (POLLIN | POLLRDNORM); + else + revents = (*random_adaptor->poll)(events, td); + } + return (revents); +} + +static void +random_initialize(void *p, struct random_adaptor *s) +{ + static int random_inited = 0; + + if (random_inited) { + printf("random: <%s> already initialized\n", + random_adaptor->ident); + return; + } + + random_adaptor = s; + + (s->init)(); + + printf("random: <%s> initialized\n", s->ident); + + /* Use an appropriately evil mode for those who are concerned + * with daemons */ + random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, + RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random"); + make_dev_alias(random_dev, "urandom"); /* compatibility */ + + /* mark random(4) as initialized, to avoid being called again */ + random_inited = 1; +} + +/* ARGSUSED */ +static int +random_modevent(module_t mod __unused, int type, void *data __unused) +{ + static eventhandler_tag attach_tag = NULL; + int error = 0; + + switch (type) { + case MOD_LOAD: + random_adaptor_choose(&random_adaptor); + + if (random_adaptor == NULL) { + printf("random: No random adaptor attached, " + "postponing initialization\n"); + attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach, + random_initialize, NULL, EVENTHANDLER_PRI_ANY); + } else + random_initialize(NULL, random_adaptor); + + break; + + case MOD_UNLOAD: + if (random_adaptor != NULL) { + (*random_adaptor->deinit)(); + destroy_dev(random_dev); + } + /* Unregister the event handler */ + if (attach_tag != NULL) + EVENTHANDLER_DEREGISTER(random_adaptor_attach, + attach_tag); + + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + + } + return (error); +} + +DEV_MODULE(random, random_modevent, NULL); +MODULE_VERSION(random, 1); diff --git a/bsd/sys/dev/random/randomdev.h b/bsd/sys/dev/random/randomdev.h new file mode 100644 index 0000000000000000000000000000000000000000..b87789f0834fb9c0b215a8421213924f88b39969 --- /dev/null +++ b/bsd/sys/dev/random/randomdev.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED + +/* This header contains only those definitions that are global + * and non algorithm-specific for the entropy processor + */ + +typedef void random_init_func_t(void); +typedef void random_deinit_func_t(void); +typedef int random_block_func_t(int); +typedef int random_read_func_t(void *, int); +typedef int random_poll_func_t(int, struct thread *); +typedef void random_reseed_func_t(void); + +struct random_adaptor { + struct selinfo rsel; + const char *ident; + int seeded; + unsigned priority; + random_init_func_t *init; + random_deinit_func_t *deinit; + random_block_func_t *block; + random_read_func_t *read; + random_poll_func_t *poll; + random_reseed_func_t *reseed; +}; + +struct random_hardware_source { + const char *ident; + enum esource source; + random_read_func_t *read; +}; + +#endif diff --git a/bsd/sys/dev/random/randomdev_soft.c b/bsd/sys/dev/random/randomdev_soft.c new file mode 100644 index 0000000000000000000000000000000000000000..0929704da896b2b5b154d8cf55a93f4152e82fe2 --- /dev/null +++ b/bsd/sys/dev/random/randomdev_soft.c @@ -0,0 +1,299 @@ +/*- + * Copyright (c) 2000-2013 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. + * + */ + +#include "opt_random.h" + +#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA) +#define RANDOM_YARROW +#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA) +#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA" +#endif +#if defined(RANDOM_FORTUNA) +#error "Fortuna is not yet implemented" +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/fcntl.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/poll.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/sysctl.h> +#include <sys/uio.h> +#include <sys/unistd.h> + +#include <machine/bus.h> +#include <machine/cpu.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/random_adaptors.h> +#if defined(RANDOM_YARROW) +#include <dev/random/yarrow.h> +#endif +#if defined(RANDOM_FORTUNA) +#include <dev/random/fortuna.h> +#endif + + +static int randomdev_poll(int event, struct thread *td); +static int randomdev_block(int flag); +static void randomdev_flush_reseed(void); + +#if defined(RANDOM_YARROW) +static struct random_adaptor random_context = { + .ident = "Software, Yarrow", + .init = randomdev_init, + .deinit = randomdev_deinit, + .block = randomdev_block, + .read = random_yarrow_read, + .poll = randomdev_poll, + .reseed = randomdev_flush_reseed, + .seeded = 0, /* This will be seeded during entropy processing */ + .priority = 90, /* High priority, so top of the list. Fortuna may still win. */ +}; +#define RANDOM_MODULE_NAME yarrow +#define RANDOM_CSPRNG_NAME "yarrow" +#endif + +#if defined(RANDOM_FORTUNA) +static struct random_adaptor random_context = { + .ident = "Software, Fortuna", + .init = randomdev_init, + .deinit = randomdev_deinit, + .block = randomdev_block, + .read = random_fortuna_read, + .poll = randomdev_poll, + .reseed = randomdev_flush_reseed, + .seeded = 0, /* This will be excplicitly seeded at startup when secured */ + .priority = 100, /* High priority, so top of the list. Beat Yarrow. */ +}; +#define RANDOM_MODULE_NAME fortuna +#define RANDOM_CSPRNG_NAME "fortuna" +#endif + +TUNABLE_INT("kern.random.sys.seeded", &random_context.seeded); + +/* List for the dynamic sysctls */ +static struct sysctl_ctx_list random_clist; + +/* ARGSUSED */ +static int +random_check_boolean(SYSCTL_HANDLER_ARGS) +{ + if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) + *(u_int *)(oidp->oid_arg1) = 1; + return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req)); +} + +void +randomdev_init(void) +{ + struct sysctl_oid *random_sys_o, *random_sys_harvest_o; + +#if defined(RANDOM_YARROW) + random_yarrow_init_alg(&random_clist); +#endif +#if defined(RANDOM_FORTUNA) + random_fortuna_init_alg(&random_clist); +#endif + + random_sys_o = SYSCTL_ADD_NODE(&random_clist, + SYSCTL_STATIC_CHILDREN(_kern_random), + OID_AUTO, "sys", CTLFLAG_RW, 0, + "Entropy Device Parameters"); + + SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_o), + OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW, + &random_context.seeded, 0, random_check_boolean, "I", + "Seeded State"); + + random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist, + SYSCTL_CHILDREN(random_sys_o), + OID_AUTO, "harvest", CTLFLAG_RW, 0, + "Entropy Sources"); + + SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_harvest_o), + OID_AUTO, "ethernet", CTLTYPE_INT | CTLFLAG_RW, + &harvest.ethernet, 1, random_check_boolean, "I", + "Harvest NIC entropy"); + SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_harvest_o), + OID_AUTO, "point_to_point", CTLTYPE_INT | CTLFLAG_RW, + &harvest.point_to_point, 1, random_check_boolean, "I", + "Harvest serial net entropy"); + 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 IRQ entropy"); + SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_harvest_o), + OID_AUTO, "swi", CTLTYPE_INT | CTLFLAG_RW, + &harvest.swi, 1, random_check_boolean, "I", + "Harvest SWI entropy"); + + random_harvestq_init(random_process_event); + + /* Register the randomness harvesting routine */ + randomdev_init_harvester(random_harvestq_internal, + random_context.read); +} + +void +randomdev_deinit(void) +{ + /* Deregister the randomness harvesting routine */ + randomdev_deinit_harvester(); + + /* + * Command the hash/reseed thread to end and wait for it to finish + */ + random_kthread_control = -1; + tsleep((void *)&random_kthread_control, 0, "term", 0); + +#if defined(RANDOM_YARROW) + random_yarrow_deinit_alg(); +#endif +#if defined(RANDOM_FORTUNA) + random_fortuna_deinit_alg(); +#endif + + sysctl_ctx_free(&random_clist); +} + +void +randomdev_unblock(void) +{ + if (!random_context.seeded) { + selwakeuppri(&random_context.rsel, PUSER); + wakeup(&random_context); + printf("random: unblocking device.\n"); + random_context.seeded = 1; + } + /* Do arc4random(9) a favour while we are about it. */ + (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, + ARC4_ENTR_HAVE); +} + +static int +randomdev_poll(int events, struct thread *td) +{ + int revents = 0; + + mtx_lock(&random_reseed_mtx); + + if (random_context.seeded) + revents = events & (POLLIN | POLLRDNORM); + else + selrecord(td, &random_context.rsel); + + mtx_unlock(&random_reseed_mtx); + return (revents); +} + +static int +randomdev_block(int flag) +{ + int error = 0; + + mtx_lock(&random_reseed_mtx); + + /* Blocking logic */ + while (!random_context.seeded && !error) { + if (flag & O_NONBLOCK) + error = EWOULDBLOCK; + else { + printf("random: blocking on read.\n"); + error = msleep(&random_context, + &random_reseed_mtx, + PUSER | PCATCH, "block", 0); + } + } + mtx_unlock(&random_reseed_mtx); + + return (error); +} + +/* Helper routine to perform explicit reseeds */ +static 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(RANDOM_YARROW) + /* This ultimately calls randomdev_unblock() */ + random_yarrow_reseed(); +#endif +#if defined(RANDOM_FORTUNA) + /* This ultimately calls randomdev_unblock() */ + random_fortuna_reseed(); +#endif +} + +static int +randomdev_modevent(module_t mod __unused, int type, void *unused __unused) +{ + + switch (type) { + case MOD_LOAD: + random_adaptor_register(RANDOM_CSPRNG_NAME, &random_context); + /* + * For statically built kernels that contain both device + * random and options PADLOCK_RNG/RDRAND_RNG/etc.., + * this event handler will do nothing, since the random + * driver-specific handlers are loaded after these HW + * consumers, and hence hasn't yet registered for this event. + * + * In case where both the random driver and RNG's are built + * as seperate modules, random.ko is loaded prior to *_rng.ko's + * (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_context); + return (0); + } + + return (EINVAL); +} + +RANDOM_ADAPTOR_MODULE(RANDOM_MODULE_NAME, randomdev_modevent, 1); diff --git a/bsd/sys/dev/random/randomdev_soft.h b/bsd/sys/dev/random/randomdev_soft.h new file mode 100644 index 0000000000000000000000000000000000000000..cbee779a7d05c92f0a6ba21593f266d4cad47d30 --- /dev/null +++ b/bsd/sys/dev/random/randomdev_soft.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED + +/* This header contains only those definitions that are global + * and harvester-specific for the entropy processor + */ + +/* #define ENTROPYSOURCE nn entropy sources (actually classes) + * This is properly defined in + * an enum in sys/random.h + */ + +/* 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) + +#define HARVESTSIZE 16 /* max size of each harvested entropy unit */ + +/* These are used to queue harvested packets of entropy. The entropy + * buffer size is pretty arbitrary. + */ +struct harvest { + uintmax_t somecounter; /* fast counter for clock jitter */ + uint8_t entropy[HARVESTSIZE]; /* the harvested entropy */ + u_int size, bits; /* stats about the entropy */ + enum esource source; /* origin of the entropy */ + STAILQ_ENTRY(harvest) next; /* next item on the list */ +}; + +void randomdev_init(void); +void randomdev_deinit(void); + +void randomdev_init_harvester(void (*)(u_int64_t, const void *, u_int, + u_int, enum esource), int (*)(void *, int)); +void randomdev_deinit_harvester(void); + +void random_set_wakeup_exit(void *); +void random_process_event(struct harvest *event); +void randomdev_unblock(void); + +extern struct mtx random_reseed_mtx; + +/* 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) \ +{ \ + if (oidp->oid_arg1 != NULL) { \ + if (*(u_int *)(oidp->oid_arg1) <= (min)) \ + *(u_int *)(oidp->oid_arg1) = (min); \ + else if (*(u_int *)(oidp->oid_arg1) > (max)) \ + *(u_int *)(oidp->oid_arg1) = (max); \ + } \ + return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ + req)); \ +} + +#endif diff --git a/bsd/sys/dev/random/rwfile.c b/bsd/sys/dev/random/rwfile.c new file mode 100644 index 0000000000000000000000000000000000000000..9b3895791690f56f4655ec37e773b16049820b52 --- /dev/null +++ b/bsd/sys/dev/random/rwfile.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 2013 Mark R V Murray + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_random.h" + +#ifdef RANDOM_RWFILE + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/namei.h> +#include <sys/fcntl.h> +#include <sys/vnode.h> + +#include <dev/random/rwfile.h> + +int +randomdev_read_file(const char *filename, void *buf, size_t length) +{ + struct nameidata nd; + struct thread* td = curthread; + int error; + ssize_t resid; + int flags; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); + flags = FREAD; + error = vn_open(&nd, &flags, 0, NULL); + if (error == 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + if (nd.ni_vp->v_type != VREG) + error = ENOEXEC; + else + error = vn_rdwr(UIO_READ, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); + VOP_UNLOCK(nd.ni_vp, 0); + vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + } + + return (error); +} + +int +randomdev_write_file(const char *filename, void *buf, size_t length) +{ + struct nameidata nd; + struct thread* td = curthread; + int error; + ssize_t resid; + int flags; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); + flags = FWRITE | O_CREAT | O_TRUNC; + error = vn_open(&nd, &flags, 0, NULL); + if (error == 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + if (nd.ni_vp->v_type != VREG) + error = ENOEXEC; + else + error = vn_rdwr(UIO_WRITE, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); + + VOP_UNLOCK(nd.ni_vp, 0); + vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + } + + return (error); +} + +#endif diff --git a/bsd/sys/dev/random/rwfile.h b/bsd/sys/dev/random/rwfile.h new file mode 100644 index 0000000000000000000000000000000000000000..f14fd7b7e9636c1bd1c1b98b928ecaea4f396b0f --- /dev/null +++ b/bsd/sys/dev/random/rwfile.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2013 Mark R V Murray + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_RWFILE_H_INCLUDED +#define SYS_DEV_RANDOM_RWFILE_H_INCLUDED + +#ifdef RANDOM_RWFILE + +int randomdev_read_file(const char *filename, void *buf, size_t); +int randomdev_write_file(const char *filename, void *buf, size_t); + +#endif + +#endif diff --git a/bsd/sys/dev/random/yarrow.c b/bsd/sys/dev/random/yarrow.c new file mode 100644 index 0000000000000000000000000000000000000000..1cfa37372ed8d1ca2b0a460f4d7d7616b770af55 --- /dev/null +++ b/bsd/sys/dev/random/yarrow.c @@ -0,0 +1,416 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_random.h" + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/random.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + +#include <crypto/rijndael/rijndael-api-fst.h> +#include <crypto/sha2/sha2.h> + +#include <dev/random/hash.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/yarrow.h> + +#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 */ + } 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*8)/4, (BLOCKSIZE*8)); /* Bit counts */ +RANDOM_CHECK_UINT(slowthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */ +RANDOM_CHECK_UINT(slowoverthresh, 1, 5); + +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. */ +/* TODO: Make a Galois counter instead? */ +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) +{ + u_int pl, overthreshhold[2]; + struct source *source; + enum esource src; + +#if 0 + /* Do this better with DTrace */ + { + 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 %2d %02X\n", event->size, event->bits, event->source); + } +#endif + + /* Accumulate the event into the appropriate pool */ + pl = random_state.which; + source = &random_state.pool[pl].source[event->source]; + randomdev_hash_iterate(&random_state.pool[pl].hash, event, + sizeof(*event)); + source->bits += event->bits; + + /* Count the over-threshold sources in each pool */ + for (pl = 0; pl < 2; pl++) { + overthreshhold[pl] = 0; + for (src = RANDOM_START; src < ENTROPYSOURCE; src++) { + if (random_state.pool[pl].source[src].bits + > random_state.pool[pl].thresh) + overthreshhold[pl]++; + } + } + + /* if any fast source over threshhold, reseed */ + if (overthreshhold[FAST]) + reseed(FAST); + + /* if enough slow sources are over threshhold, reseed */ + if (overthreshhold[SLOW] >= random_state.slowoverthresh) + reseed(SLOW); + + /* Invert the fast/slow pool selector bit */ + random_state.which = !random_state.which; +} + +void +random_yarrow_init_alg(struct sysctl_ctx_list *clist) +{ + int i; + struct sysctl_oid *random_yarrow_o; + + /* Yarrow parameters. Do not adjust these unless you have + * have a very good clue about what they do! + */ + random_yarrow_o = SYSCTL_ADD_NODE(clist, + SYSCTL_STATIC_CHILDREN(_kern_random), + OID_AUTO, "yarrow", CTLFLAG_RW, 0, + "Yarrow Parameters"); + + SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "gengateinterval", CTLTYPE_INT|CTLFLAG_RW, + &random_state.gengateinterval, 10, + random_check_uint_gengateinterval, "I", + "Generation gate interval"); + + SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "bins", CTLTYPE_INT|CTLFLAG_RW, + &random_state.bins, 10, + random_check_uint_bins, "I", + "Execution time tuner"); + + SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "fastthresh", CTLTYPE_INT|CTLFLAG_RW, + &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*8), + random_check_uint_slowthresh, "I", + "Slow reseed threshold"); + + SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "slowoverthresh", CTLTYPE_INT|CTLFLAG_RW, + &random_state.slowoverthresh, 2, + random_check_uint_slowoverthresh, "I", + "Slow over-threshold reseed"); + + random_state.gengateinterval = 10; + random_state.bins = 10; + 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++) + randomdev_hash_init(&random_state.pool[i].hash); + + /* Clear the counter */ + clear_counter(); + + /* Set up a lock for the reseed process */ + mtx_init(&random_reseed_mtx, "Yarrow reseed", NULL, MTX_DEF); +} + +void +random_yarrow_deinit_alg(void) +{ + mtx_destroy(&random_reseed_mtx); +} + +static void +reseed(u_int fastslow) +{ + /* Interrupt-context stack is a limited resource; make large + * structures static. + */ + 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; + +#if 0 + printf("Yarrow: %s reseed\n", fastslow == FAST ? "fast" : "slow"); +#endif + + /* The reseed task must not be jumped on */ + mtx_lock(&random_reseed_mtx); + + /* 1. Hash the accumulated entropy into v[0] */ + + randomdev_hash_init(&context); + /* Feed the slow pool hash in if slow */ + if (fastslow == SLOW) + randomdev_hash_iterate(&context, + &random_state.pool[SLOW].hash, + 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. + */ + + if (random_state.bins > TIMEBIN) + random_state.bins = TIMEBIN; + for (i = 1; i < random_state.bins; i++) { + randomdev_hash_init(&context); + /* v[i] #= h(v[i - 1]) */ + randomdev_hash_iterate(&context, v[i - 1], KEYSIZE); + /* v[i] #= h(v[0]) */ + randomdev_hash_iterate(&context, v[0], KEYSIZE); + /* v[i] #= h(i) */ + randomdev_hash_iterate(&context, &i, sizeof(u_int)); + /* Return the hashval */ + randomdev_hash_finish(&context, v[i]); + } + + /* 3. Compute a new key; h' is the identity function here; + * it is not being ignored! + */ + + randomdev_hash_init(&context); + randomdev_hash_iterate(&context, &random_state.key, KEYSIZE); + for (i = 1; i < random_state.bins; i++) + randomdev_hash_iterate(&context, &v[i], KEYSIZE); + randomdev_hash_finish(&context, temp); + randomdev_encrypt_init(&random_state.key, temp); + + /* 4. Recompute the 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 */ + + for (i = 0; i <= fastslow; i++) + for (j = RANDOM_START; j < ENTROPYSOURCE; j++) + random_state.pool[i].source[j].bits = 0; + + /* 6. Wipe memory of intermediate values */ + + memset((void *)v, 0, sizeof(v)); + memset((void *)temp, 0, sizeof(temp)); + memset((void *)hash, 0, sizeof(hash)); + + /* 7. Dump to seed file */ + /* XXX Not done here yet */ + + /* Unblock the device if it was blocked due to being unseeded */ + randomdev_unblock(); + + /* Release the reseed mutex */ + mtx_unlock(&random_reseed_mtx); +} + +/* Internal function to return processed entropy from the PRNG */ +int +random_yarrow_read(void *buf, int count) +{ + static int cur = 0; + static int gate = 1; + static uint8_t genval[KEYSIZE]; + size_t tomove; + int i; + int retval; + + /* Check for final read request */ + if (buf == NULL && count == 0) + return (0); + + /* The reseed task must not be jumped on */ + mtx_lock(&random_reseed_mtx); + + if (gate) { + generator_gate(); + random_state.outputblocks = 0; + gate = 0; + } + if (count > 0 && (size_t)count >= BLOCKSIZE) { + retval = 0; + 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) { + generator_gate(); + random_state.outputblocks = 0; + } + retval += (int)tomove; + cur = 0; + } + } + else { + if (!cur) { + increment_counter(); + randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE); + memcpy(buf, genval, (size_t)count); + cur = BLOCKSIZE - count; + if (++random_state.outputblocks >= random_state.gengateinterval) { + generator_gate(); + random_state.outputblocks = 0; + } + retval = count; + } + else { + retval = MIN(cur, count); + memcpy(buf, &genval[BLOCKSIZE - cur], (size_t)retval); + cur -= retval; + } + } + mtx_unlock(&random_reseed_mtx); + return (retval); +} + +static void +generator_gate(void) +{ + u_int i; + uint8_t temp[KEYSIZE]; + + for (i = 0; i < KEYSIZE; i += BLOCKSIZE) { + increment_counter(); + randomdev_encrypt(&random_state.key, random_state.counter.byte, temp + i, BLOCKSIZE); + } + + randomdev_encrypt_init(&random_state.key, temp); + memset((void *)temp, 0, KEYSIZE); +} + +/* Helper routine to perform explicit reseeds */ +void +random_yarrow_reseed(void) +{ +#ifdef RANDOM_DEBUG + int i; + + printf("%s(): fast:", __func__); + for (i = RANDOM_START; i < ENTROPYSOURCE; ++i) + printf(" %d", random_state.pool[FAST].source[i].bits); + printf("\n"); + printf("%s(): slow:", __func__); + for (i = RANDOM_START; i < ENTROPYSOURCE; ++i) + printf(" %d", random_state.pool[SLOW].source[i].bits); + printf("\n"); +#endif + reseed(SLOW); +} diff --git a/bsd/sys/dev/random/yarrow.h b/bsd/sys/dev/random/yarrow.h new file mode 100644 index 0000000000000000000000000000000000000000..f32313ee5773aa8b8cab3ae5278fc4bbe55c63c5 --- /dev/null +++ b/bsd/sys/dev/random/yarrow.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2000-2013 Mark R V Murray + * 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$ + */ + +#ifndef SYS_DEV_RANDOM_YARROW_H_INCLUDED +#define SYS_DEV_RANDOM_YARROW_H_INCLUDED + +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); + +#endif