Index: head/UPDATING =================================================================== --- head/UPDATING +++ head/UPDATING @@ -31,6 +31,21 @@ disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20150817: + Kernel-loadable modules for the random(4) device are back. To use + them, the kernel must have + + device random + options RANDOM_LOADABLE + + kldload(8) can then be used to load random_fortuna.ko + or random_yarrow.ko. Please note that due to the indirect + function calls that the loadable modules need to provide, + the build-in variants will be slightly more efficient. + + The random(4) kernel option RANDOM_DUMMY has been retired due to + unpopularity. It was not all that useful anyway. + 20150813: The WITHOUT_ELFTOOLCHAIN_TOOLS src.conf(5) knob has been retired. Control over building the ELF Tool Chain tools is now provided by Index: head/share/man/man4/random.4 =================================================================== --- head/share/man/man4/random.4 +++ head/share/man/man4/random.4 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 30, 2015 +.Dd August 17, 2015 .Dt RANDOM 4 .Os .Sh NAME @@ -31,6 +31,7 @@ .Nd the entropy device .Sh SYNOPSIS .Cd "device random" +.Cd "options RANDOM_LOADABLE" .Sh DESCRIPTION The .Nm @@ -133,15 +134,49 @@ .Va kern.random.harvest.mask_bin and .Va kern.random.harvest.mask_symbolic -sysctl -can be used confirm -that your choices are correct. +sysctls +can be used to confirm +that the choices are correct. Note that disabled items in the latter item are listed in square brackets. See .Xr random_harvest 9 for more on the harvesting of entropy. +.Pp +When +.Cd "options RANDOM_LOADABLE" +is used, +the +.Pa /dev/random +device is not created +until an "algorithm module" +is loaded. +Two of these modules +are built by default, +.Em random_fortuna +and +.Em random_yarrow . +The +.Em random_yarrow +module is deprecated, +and will be removed in +.Fx 12. +Use of the Yarrow algorithm +is not encouraged, +but while still present +in the kernel source, +it can be selected with the +.Cd "options RANDOM_YARROW" +kernel option. +Note that these loadable modules +are slightly less efficient +than their compiled-in equivalents. +This is because some functions +must be locked against +load and unload events, +and also must be indirect calls +to allow for removal. .Sh RANDOMNESS The use of randomness in the field of computing is a rather subtle issue because randomness means @@ -294,7 +329,7 @@ implementation, introduced in .Fx 5.0 . -The older -.Em Yarrow -algorithm remains available -as a compile-time fallback. +The Yarrow algorithm +is no longer supported +by its authors, +and is therefore deprecated. Index: head/sys/conf/NOTES =================================================================== --- head/sys/conf/NOTES +++ head/sys/conf/NOTES @@ -2981,9 +2981,10 @@ # Random number generator # Only ONE of the below two may be used; they are mutually exclusive. -# If neither is present, then the Fortuna algorithm is used. -options RANDOM_YARROW # Yarrow CSPRNG (old default) -#options RANDOM_DUMMY # Dummy CSPRNG that always blocks +# If neither is present, then the Fortuna algorithm is selected. +#options RANDOM_YARROW # Yarrow CSPRNG (old default) +#options RANDOM_LOADABLE # Allow the algorithm to be loaded as + # a module. # For developers. options RANDOM_DEBUG # Extra debugging messages Index: head/sys/conf/files =================================================================== --- head/sys/conf/files +++ head/sys/conf/files @@ -550,14 +550,14 @@ crypto/des/des_setkey.c optional crypto | ipsec | netsmb crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi crypto/rijndael/rijndael-alg-fst.c optional crypto | geom_bde | \ - ipsec | random random_yarrow | random !random_yarrow !random_dummy | wlan_ccmp -crypto/rijndael/rijndael-api-fst.c optional geom_bde | random random_yarrow | random !random_yarrow !random_dummy + ipsec | random !random_loadable | wlan_ccmp +crypto/rijndael/rijndael-api-fst.c optional geom_bde | random !random_loadable crypto/rijndael/rijndael-api.c optional crypto | ipsec | wlan_ccmp crypto/sha1.c optional carp | crypto | ipsec | \ netgraph_mppc_encryption | sctp -crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \ +crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random !random_loadable | \ sctp | zfs -crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \ +crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random !random_loadable | \ sctp | zfs crypto/siphash/siphash.c optional inet | inet6 crypto/siphash/siphash_test.c optional inet | inet6 @@ -2314,12 +2314,14 @@ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2860.fw" -dev/random/randomdev_none.c optional !random -dev/random/randomdev.c optional random -dev/random/random_harvestq.c optional random random_yarrow | random !random_dummy +dev/random/random_infra.c optional random +dev/random/random_harvestq.c optional random +dev/random/randomdev.c optional random random_yarrow | \ + random !random_yarrow !random_loadable dev/random/yarrow.c optional random random_yarrow -dev/random/fortuna.c optional random !random_yarrow !random_dummy -dev/random/hash.c optional random random_yarrow | random !random_dummy +dev/random/fortuna.c optional random !random_yarrow !random_loadable +dev/random/hash.c optional random random_yarrow | \ + random !random_yarrow !random_loadable dev/rc/rc.c optional rc dev/re/if_re.c optional re dev/rl/if_rl.c optional rl pci Index: head/sys/conf/options =================================================================== --- head/sys/conf/options +++ head/sys/conf/options @@ -711,6 +711,7 @@ DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h +DEV_RANDOM opt_global.h DEV_SPLASH opt_splash.h DEV_VLAN opt_vlan.h @@ -946,13 +947,14 @@ # The DEBUG option is in global.h as the random harvesting # puts probes all over the place, and it makes little sense # to pollute these headers with an extra include. -# the DUMMY option is in global.h because it is used to -# turn off harvesting all over the kernel. -RANDOM_DEBUG opt_global.h +RANDOM_DEBUG opt_random.h # Which CSPRNG hashes we get. -# These are mutually exclusive. With neither, Fortuna is selected. -RANDOM_DUMMY opt_global.h +# If Yarrow is not chosen, Fortuna is selected. RANDOM_YARROW opt_random.h +# With this, no entropy processor is loaded, but the entropy +# harvesting infrastructure is present. This means an entropy +# processor may be loaded as a module. +RANDOM_LOADABLE opt_random.h # Intel em(4) driver EM_MULTIQUEUE opt_em.h Index: head/sys/dev/random/fortuna.c =================================================================== --- head/sys/dev/random/fortuna.c +++ head/sys/dev/random/fortuna.c @@ -58,6 +58,7 @@ #include #else /* !_KERNEL */ #include +#include #include #include #include @@ -124,9 +125,7 @@ static void random_fortuna_pre_read(void); static void random_fortuna_read(uint8_t *, u_int); -static void random_fortuna_write(uint8_t *, u_int); -static void random_fortuna_reseed(void); -static int random_fortuna_seeded(void); +static bool random_fortuna_seeded(void); static void random_fortuna_process_event(struct harvest_event *); static void random_fortuna_init_alg(void *); static void random_fortuna_deinit_alg(void *); @@ -139,8 +138,6 @@ .ra_deinit_alg = random_fortuna_deinit_alg, .ra_pre_read = random_fortuna_pre_read, .ra_read = random_fortuna_read, - .ra_write = random_fortuna_write, - .ra_reseed = random_fortuna_reseed, .ra_seeded = random_fortuna_seeded, .ra_event_processor = random_fortuna_process_event, .ra_poolcount = RANDOM_FORTUNA_NPOOLS, @@ -420,43 +417,7 @@ RANDOM_RESEED_UNLOCK(); } -/* Internal function to hand external entropy to the PRNG. */ -void -random_fortuna_write(uint8_t *buf, u_int count) -{ - static u_int destination = 0; - struct harvest_event event; - struct randomdev_hash hash; - uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp; - int i; - - /* Extra timing here is helpful to scrape scheduler timing entropy */ - randomdev_hash_init(&hash); - timestamp = (uint32_t)get_cyclecount(); - randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); - randomdev_hash_iterate(&hash, buf, count); - timestamp = (uint32_t)get_cyclecount(); - randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); - randomdev_hash_finish(&hash, entropy_data); - explicit_bzero(&hash, sizeof(hash)); - for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { - event.he_somecounter = (uint32_t)get_cyclecount(); - event.he_size = sizeof(event.he_entropy); - event.he_bits = event.he_size/8; - event.he_source = RANDOM_CACHED; - event.he_destination = destination++; /* Harmless cheating */ - memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy)); - random_fortuna_process_event(&event); - } - explicit_bzero(entropy_data, sizeof(entropy_data)); -} - -void -random_fortuna_reseed(void) -{ -} - -int +bool random_fortuna_seeded(void) { Index: head/sys/dev/random/other_algorithm.h =================================================================== --- head/sys/dev/random/other_algorithm.h +++ head/sys/dev/random/other_algorithm.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2015 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$ + */ + +/*- + * This is a skeleton for folks who wish to build a loadable module + * containing an alternative entropy-processing algorithm for random(4). + * + * The functions below should be completed with the appropriate code, + * and the nearby yarrow.c and fortuna.c may be consulted for examples + * of working code. + * + * The author is willing to provide reasonable help to those wishing to + * write such a module for themselves. Please use the markm@ FreeBSD + * email address, and ensure that you are developing this on a suitably + * supported branch (This is currently 11-CURRENT, and will be no + * older than 11-STABLE in the future). + */ + +#ifndef SYS_DEV_RANDOM_OTHER_H_INCLUDED +#define SYS_DEV_RANDOM_OTHER_H_INCLUDED + +#ifdef _KERNEL +typedef struct mtx mtx_t; +#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&other_mtx, "reseed mutex", NULL, MTX_DEF) +#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&other_mtx) +#define RANDOM_RESEED_LOCK(x) mtx_lock(&other_mtx) +#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&other_mtx) +#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) mtx_assert(&other_mtx, MA_OWNED) +#else +#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&other_mtx, mtx_plain) +#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&other_mtx) +#define RANDOM_RESEED_LOCK(x) mtx_lock(&other_mtx) +#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&other_mtx) +#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) +#endif + +#endif /* SYS_DEV_RANDOM_OTHER_H_INCLUDED */ Index: head/sys/dev/random/other_algorithm.c =================================================================== --- head/sys/dev/random/other_algorithm.c +++ head/sys/dev/random/other_algorithm.c @@ -0,0 +1,209 @@ +/*- + * Copyright (c) 2015 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. + * + */ + +/*- + * This is a skeleton for folks who wish to build a loadable module + * containing an alternative entropy-processing algorithm for random(4). + * + * The functions below should be completed with the appropriate code, + * and the nearby yarrow.c and fortuna.c may be consulted for examples + * of working code. + * + * The author is willing to provide reasonable help to those wishing to + * write such a module for themselves. Please use the markm@ FreeBSD + * email address, and ensure that you are developing this on a suitably + * supported branch (This is currently 11-CURRENT, and will be no + * older than 11-STABLE in the future). + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +static void random_other_pre_read(void); +static void random_other_read(uint8_t *, u_int); +static bool random_other_seeded(void); +static void random_other_process_event(struct harvest_event *); +static void random_other_init_alg(void *); +static void random_other_deinit_alg(void *); + +/* + * RANDOM_OTHER_NPOOLS is used when reading hardware random + * number sources to ensure that each pool gets one read sample + * per loop iteration. Yarrow has 2 such pools (FAST and SLOW), + * and fortuna has 32 (0-31). The RNG used prior to Yarrow and + * ported from Linux had just 1 pool. + */ +#define RANDOM_OTHER_NPOOLS 1 + +struct random_algorithm random_alg_context = { + .ra_ident = "other", + .ra_init_alg = random_other_init_alg, + .ra_deinit_alg = random_other_deinit_alg, + .ra_pre_read = random_other_pre_read, + .ra_read = random_other_read, + .ra_seeded = random_other_seeded, + .ra_event_processor = random_other_process_event, + .ra_poolcount = RANDOM_OTHER_NPOOLS, +}; + +/* Use a mutex to protect your reseed variables? */ +static mtx_t other_mtx; + +/* + * void random_other_init_alg(void *unused __unused) + * + * Do algorithm-specific initialisation here. + */ +void +random_other_init_alg(void *unused __unused) +{ + + RANDOM_RESEED_INIT_LOCK(); + /* + * Do set-up work here! + */ +} + +/* + * void random_other_deinit_alg(void *unused __unused) + * + * Do algorithm-specific deinitialisation here. + */ +static void +random_other_deinit_alg(void *unused __unused) +{ + + /* + * Do tear-down work here! + */ + RANDOM_RESEED_DEINIT_LOCK(); +} + +/* + * void random_other_pre_read(void) + * + * Do any pre-read preparation you need to. This will be called + * before >=1 calls to random_other_read() corresponding to one + * read(2). + * + * This routine will be called periodically while the generator is + * still blocked and a read is being attempted, giving you an + * opportunity to unblock. + */ +static void +random_other_pre_read(void) +{ + + RANDOM_RESEED_LOCK(); + /* + * Do pre-read housekeeping work here! + * You may use this as a chance to unblock the generator. + */ + RANDOM_RESEED_UNLOCK(); +} + +/* + * void random_other_read(uint8_t *buf, u_int count) + * + * Generate bytes of output into <*buf>. + * You may use the fact that will be a multiple of + * RANDOM_BLOCKSIZE for optimization purposes. + * + * This function will always be called with your generator + * unblocked and ready. If you are not ready to generate + * output here, then feel free to KASSERT() or panic(). + */ +static void +random_other_read(uint8_t *buf, u_int count) +{ + + RANDOM_RESEED_LOCK(); + /* + * Do random-number generation work here! + */ + RANDOM_RESEED_UNLOCK(); +} + +/* + * bool random_other_seeded(void) + * + * Return true if your generator is ready to generate + * output, and false otherwise. + */ +static bool +random_other_seeded(void) +{ + bool seeded = false; + + /* + * Find out if your generator is seeded here! + */ + return (seeded); +} + +/* + * void random_other_process_event(struct harvest_event *event) + * + * Process one stochastic event <*event> into your entropy + * processor. + * + * The structure of the event may change, so it is easier to + * just grab the whole thing into your accumulation system. + * You may pick-and-choose bits, but please don't complain + * when/if these change. + */ +static void +random_other_process_event(struct harvest_event *event) +{ + + RANDOM_RESEED_LOCK(); + /* + * Do entropy accumulation work here! + * You may use this as a chance to unblock the generator. + */ + RANDOM_RESEED_UNLOCK(); +} Index: head/sys/dev/random/random_harvestq.h =================================================================== --- head/sys/dev/random/random_harvestq.h +++ head/sys/dev/random/random_harvestq.h @@ -43,6 +43,8 @@ uint8_t he_source; /* origin of the entropy */ } __packed; +void read_rate_increment(u_int); + #define RANDOM_HARVESTQ_BOOT_ENTROPY_FILE "/boot/entropy" #define RANDOM_HARVEST_INIT_LOCK(x) mtx_init(&harvest_context.hc_mtx, "entropy harvest mutex", NULL, MTX_SPIN) Index: head/sys/dev/random/random_harvestq.c =================================================================== --- head/sys/dev/random/random_harvestq.c +++ head/sys/dev/random/random_harvestq.c @@ -47,12 +47,21 @@ #include #include +#if defined(RANDOM_LOADABLE) +#include +#include +#endif + +#include #include #include #include static void random_kthread(void); +static void random_sources_feed(void); + +static u_int read_rate; /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; @@ -66,7 +75,7 @@ #define RANDOM_RING_MAX 1024 #define RANDOM_ACCUM_MAX 8 -/* 1 to let the kernel thread run, 0 to terminate */ +/* 1 to let the kernel thread run, 0 to terminate, -1 to mark completion */ volatile int random_kthread_control; /* @@ -123,13 +132,18 @@ &harvest_context.hc_kthread_proc, }; - /* Pass the given event straight through to Fortuna/Yarrow/Whatever. */ static __inline void random_harvestq_fast_process_event(struct harvest_event *event) { - if (random_alg_context.ra_event_processor) - random_alg_context.ra_event_processor(event); +#if defined(RANDOM_LOADABLE) + RANDOM_CONFIG_S_LOCK(); + if (p_random_alg_context) +#endif + p_random_alg_context->ra_event_processor(event); +#if defined(RANDOM_LOADABLE) + RANDOM_CONFIG_S_UNLOCK(); +#endif } static void @@ -163,12 +177,58 @@ /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */ tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1)); } + random_kthread_control = -1; wakeup(&harvest_context.hc_kthread_proc); kproc_exit(0); /* NOTREACHED */ } +/* This happens well after SI_SUB_RANDOM */ SYSINIT(random_device_h_proc, SI_SUB_CREATE_INIT, SI_ORDER_ANY, kproc_start, &random_proc_kp); +/* + * Run through all fast sources reading entropy for the given + * number of rounds, which should be a multiple of the number + * of entropy accumulation pools in use; 2 for Yarrow and 32 + * for Fortuna. + */ +static void +random_sources_feed(void) +{ + uint32_t entropy[HARVESTSIZE]; + struct random_sources *rrs; + u_int i, n, local_read_rate; + + /* + * Step over all of live entropy sources, and feed their output + * to the system-wide RNG. + */ +#if defined(RANDOM_LOADABLE) + RANDOM_CONFIG_S_LOCK(); + if (p_random_alg_context) { + /* It's an indenting error. Yeah, Yeah. */ +#endif + local_read_rate = atomic_readandclear_32(&read_rate); + LIST_FOREACH(rrs, &source_list, rrs_entries) { + for (i = 0; i < p_random_alg_context->ra_poolcount*(local_read_rate + 1); i++) { + n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); + KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__)); + random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); + } + } + explicit_bzero(entropy, sizeof(entropy)); +#if defined(RANDOM_LOADABLE) + } + RANDOM_CONFIG_S_UNLOCK(); +#endif +} + +void +read_rate_increment(u_int chunk) +{ + + atomic_add_32(&read_rate, chunk); +} + /* ARGSUSED */ RANDOM_CHECK_UINT(harvestmask, 0, RANDOM_HARVEST_EVERYTHING_MASK); @@ -317,7 +377,8 @@ /* Command the hash/reseed thread to end and wait for it to finish */ random_kthread_control = 0; - tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", 0); + while (random_kthread_control >= 0) + tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", hz/5); sysctl_ctx_free(&random_clist); } SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL); @@ -412,3 +473,5 @@ random_harvestq_fast_process_event(&event); explicit_bzero(&event, sizeof(event)); } + +MODULE_VERSION(random_harvestq, 1); Index: head/sys/dev/random/random_infra.c =================================================================== --- head/sys/dev/random/random_infra.c +++ head/sys/dev/random/random_infra.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2015 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#if defined(RANDOM_LOADABLE) +#include +#include +#endif + +#include + +/* Set up the sysctl root node for the entropy device */ +SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); + +MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); + +struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); + +#if defined(RANDOM_LOADABLE) +struct random_algorithm *p_random_alg_context = NULL; +#else /* !defined(RANDOM_LOADABLE) */ +struct random_algorithm *p_random_alg_context = &random_alg_context; +#endif /* defined(RANDOM_LOADABLE) */ + +#if defined(RANDOM_LOADABLE) + +struct random_readers { + int (*read_random_uio)(struct uio *, bool); + u_int (*read_random)(void *, u_int); +} random_reader_context = { + (int (*)(struct uio *, bool))nullop, + (u_int (*)(void *, u_int))nullop, +}; + +struct sx randomdev_config_lock; + +static void +random_infra_sysinit(void *dummy __unused) +{ + + RANDOM_CONFIG_INIT_LOCK(); +} +SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL); + +void +random_infra_init(int (*p_random_read_uio)(struct uio *, bool), u_int (*p_random_read)(void *, u_int)) +{ + + RANDOM_CONFIG_X_LOCK(); + random_reader_context.read_random_uio = p_random_read_uio; + random_reader_context.read_random = p_random_read; + RANDOM_CONFIG_X_UNLOCK(); +} + +void +random_infra_uninit(void) +{ + + RANDOM_CONFIG_X_LOCK(); + random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop; + random_reader_context.read_random = (u_int (*)(void *, u_int))nullop; + RANDOM_CONFIG_X_UNLOCK(); +} + +static void +random_infra_sysuninit(void *dummy __unused) +{ + + RANDOM_CONFIG_DEINIT_LOCK(); +} +SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysuninit, NULL); + +int +read_random_uio(struct uio *uio, bool nonblock) +{ + int retval; + + RANDOM_CONFIG_S_LOCK(); + retval = random_reader_context.read_random_uio(uio, nonblock); + RANDOM_CONFIG_S_UNLOCK(); + return (retval); +} + +u_int +read_random(void *buf, u_int len) +{ + u_int retval; + + RANDOM_CONFIG_S_LOCK(); + retval = random_reader_context.read_random(buf, len); + RANDOM_CONFIG_S_UNLOCK(); + return (retval); +} + +#endif /* defined(RANDOM_LOADABLE) */ Index: head/sys/dev/random/randomdev.h =================================================================== --- head/sys/dev/random/randomdev.h +++ head/sys/dev/random/randomdev.h @@ -55,16 +55,15 @@ MALLOC_DECLARE(M_ENTROPY); -#define RANDOM_ALG_READ_RATE_MINIMUM 32 - #endif /* _KERNEL */ struct harvest_event; +typedef void random_alg_init_t(void *); +typedef void random_alg_deinit_t(void *); typedef void random_alg_pre_read_t(void); typedef void random_alg_read_t(uint8_t *, u_int); -typedef void random_alg_write_t(uint8_t *, u_int); -typedef int random_alg_seeded_t(void); +typedef bool random_alg_seeded_t(void); typedef void random_alg_reseed_t(void); typedef void random_alg_eventprocessor_t(struct harvest_event *); @@ -81,13 +80,11 @@ void (*ra_deinit_alg)(void *); random_alg_pre_read_t *ra_pre_read; random_alg_read_t *ra_read; - random_alg_write_t *ra_write; - random_alg_reseed_t *ra_reseed; random_alg_seeded_t *ra_seeded; random_alg_eventprocessor_t *ra_event_processor; }; -extern struct random_algorithm random_alg_context; +extern struct random_algorithm random_alg_context, *p_random_alg_context; #ifdef _KERNEL @@ -97,22 +94,33 @@ * upon request. */ struct random_source { - const char *rs_ident; - enum random_entropy_source rs_source; - random_source_read_t *rs_read; + const char *rs_ident; + enum random_entropy_source rs_source; + random_source_read_t *rs_read; }; -#if !defined(RANDOM_DUMMY) struct random_sources { - LIST_ENTRY(random_sources) rrs_entries; - struct random_source *rrs_source; + LIST_ENTRY(random_sources) rrs_entries; + struct random_source *rrs_source; }; -#endif /* !defined(RANDOM_DUMMY) */ + +LIST_HEAD(sources_head, random_sources); +extern struct sources_head source_list; void random_source_register(struct random_source *); void random_source_deregister(struct random_source *); -void random_sources_feed(void); +#if defined(RANDOM_LOADABLE) +extern struct sx randomdev_config_lock; +#define RANDOM_CONFIG_INIT_LOCK(x) sx_init(&randomdev_config_lock, "configuration change lock") +#define RANDOM_CONFIG_X_LOCK(x) sx_xlock(&randomdev_config_lock) +#define RANDOM_CONFIG_X_UNLOCK(x) sx_xunlock(&randomdev_config_lock) +#define RANDOM_CONFIG_S_LOCK(x) sx_slock(&randomdev_config_lock) +#define RANDOM_CONFIG_S_UNLOCK(x) sx_sunlock(&randomdev_config_lock) +#define RANDOM_CONFIG_DEINIT_LOCK(x) sx_destroy(&randomdev_config_lock) +void random_infra_init(int (*)(struct uio *, bool), u_int (*)(void *, u_int)); +void random_infra_uninit(void); +#endif #endif /* _KERNEL */ Index: head/sys/dev/random/randomdev.c =================================================================== --- head/sys/dev/random/randomdev.c +++ head/sys/dev/random/randomdev.c @@ -56,14 +56,18 @@ #include #include -#include "opt_random.h" +#define RANDOM_UNIT 0 -#if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW) -#error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW" +#if defined(RANDOM_LOADABLE) +#define READ_RANDOM_UIO _read_random_uio +#define READ_RANDOM _read_random +static int READ_RANDOM_UIO(struct uio *, bool); +static u_int READ_RANDOM(void *, u_int); +#else +#define READ_RANDOM_UIO read_random_uio +#define READ_RANDOM read_random #endif -#define RANDOM_UNIT 0 - /* Return the largest number >= x that is a multiple of m */ #define CEIL_TO_MULTIPLE(x, m) ((((x) + (m) - 1)/(m))*(m)) @@ -84,68 +88,31 @@ /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; -/* Set up the sysctl root node for the entropy device */ -SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); - -MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); - -#if defined(RANDOM_DUMMY) - -/*- - * Dummy "always block" pseudo algorithm, used when there is no real - * random(4) driver to provide a CSPRNG. - */ - -static u_int -dummy_random_zero(void) -{ - - return (0); -} - -static void -dummy_random(void) -{ -} - -struct random_algorithm random_alg_context = { - .ra_ident = "Dummy", - .ra_init_alg = NULL, - .ra_deinit_alg = NULL, - .ra_pre_read = dummy_random, - .ra_read = (random_alg_read_t *)dummy_random_zero, - .ra_write = (random_alg_write_t *)dummy_random_zero, - .ra_reseed = dummy_random, - .ra_seeded = (random_alg_seeded_t *)dummy_random_zero, - .ra_event_processor = NULL, - .ra_poolcount = 0, -}; - -#else /* !defined(RANDOM_DUMMY) */ - -LIST_HEAD(sources_head, random_sources); -static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); -static u_int read_rate; - static void random_alg_context_ra_init_alg(void *data) { - random_alg_context.ra_init_alg(data); + p_random_alg_context = &random_alg_context; + p_random_alg_context->ra_init_alg(data); +#if defined(RANDOM_LOADABLE) + random_infra_init(READ_RANDOM_UIO, READ_RANDOM); +#endif } static void random_alg_context_ra_deinit_alg(void *data) { - random_alg_context.ra_deinit_alg(data); +#if defined(RANDOM_LOADABLE) + random_infra_uninit(); +#endif + p_random_alg_context->ra_deinit_alg(data); + p_random_alg_context = NULL; } SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL); SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL); -#endif /* defined(RANDOM_DUMMY) */ - static struct selinfo rsel; /* @@ -156,28 +123,28 @@ randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags) { - return (read_random_uio(uio, (flags & O_NONBLOCK) != 0)); + return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0)); } int -read_random_uio(struct uio *uio, bool nonblock) +READ_RANDOM_UIO(struct uio *uio, bool nonblock) { uint8_t *random_buf; int error, spamcount; ssize_t read_len, total_read, c; random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); error = 0; spamcount = 0; /* (Un)Blocking logic */ - while (!random_alg_context.ra_seeded()) { + while (!p_random_alg_context->ra_seeded()) { if (nonblock) { error = EWOULDBLOCK; break; } /* keep tapping away at the pre-read until we seed/unblock. */ - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); /* Only bother the console every 10 seconds or so */ if (spamcount == 0) printf("random: %s unblock wait\n", __func__); @@ -187,10 +154,7 @@ break; } if (error == 0) { -#if !defined(RANDOM_DUMMY) - /* XXX: FIX!! Next line as an atomic operation? */ - read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t); -#endif + read_rate_increment((uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t)); total_read = 0; while (uio->uio_resid && !error) { read_len = uio->uio_resid; @@ -203,7 +167,7 @@ read_len = CEIL_TO_MULTIPLE(read_len, RANDOM_BLOCKSIZE); /* Work in chunks page-sized or less */ read_len = MIN(read_len, PAGE_SIZE); - random_alg_context.ra_read(random_buf, read_len); + p_random_alg_context->ra_read(random_buf, read_len); c = MIN(uio->uio_resid, read_len); error = uiomove(random_buf, c, uio); total_read += c; @@ -224,19 +188,16 @@ * RANDOM_BLOCKSIZE bytes. */ u_int -read_random(void *random_buf, u_int len) +READ_RANDOM(void *random_buf, u_int len) { u_int read_len; uint8_t local_buf[len + RANDOM_BLOCKSIZE]; KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); /* (Un)Blocking logic; if not seeded, return nothing. */ - if (random_alg_context.ra_seeded()) { -#if !defined(RANDOM_DUMMY) - /* XXX: FIX!! Next line as an atomic operation? */ - read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t); -#endif + if (p_random_alg_context->ra_seeded()) { + read_rate_increment((len + sizeof(uint32_t))/sizeof(uint32_t)); if (len > 0) { /* * Belt-and-braces. @@ -244,7 +205,7 @@ * which is what the underlying generator is expecting. */ read_len = CEIL_TO_MULTIPLE(len, RANDOM_BLOCKSIZE); - random_alg_context.ra_read(local_buf, read_len); + p_random_alg_context->ra_read(local_buf, read_len); memcpy(random_buf, local_buf, len); } } else @@ -252,6 +213,37 @@ return (len); } +static __inline void +randomdev_accumulate(uint8_t *buf, u_int count) +{ + static u_int destination = 0; + static struct harvest_event event; + static struct randomdev_hash hash; + static uint32_t entropy_data[RANDOM_KEYSIZE_WORDS]; + uint32_t timestamp; + int i; + + /* Extra timing here is helpful to scrape scheduler jitter entropy */ + randomdev_hash_init(&hash); + timestamp = (uint32_t)get_cyclecount(); + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_iterate(&hash, buf, count); + timestamp = (uint32_t)get_cyclecount(); + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_finish(&hash, entropy_data); + explicit_bzero(&hash, sizeof(hash)); + for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { + event.he_somecounter = (uint32_t)get_cyclecount(); + event.he_size = sizeof(event.he_entropy); + event.he_bits = event.he_size/8; + event.he_source = RANDOM_CACHED; + event.he_destination = destination++; /* Harmless cheating */ + memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy)); + p_random_alg_context->ra_event_processor(&event); + } + explicit_bzero(entropy_data, sizeof(entropy_data)); +} + /* ARGSUSED */ static int randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) @@ -267,7 +259,7 @@ error = uiomove(random_buf, c, uio); if (error) break; - random_alg_context.ra_write(random_buf, c); + randomdev_accumulate(random_buf, c); tsleep(&random_alg_context, 0, "randwr", hz/10); } if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR)) @@ -283,7 +275,7 @@ { if (events & (POLLIN | POLLRDNORM)) { - if (random_alg_context.ra_seeded()) + if (p_random_alg_context->ra_seeded()) events &= (POLLIN | POLLRDNORM); else selrecord(td, &rsel); @@ -325,9 +317,6 @@ void random_source_register(struct random_source *rsource) { -#if defined(RANDOM_DUMMY) - (void)rsource; -#else /* !defined(RANDOM_DUMMY) */ struct random_sources *rrs; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); @@ -337,15 +326,11 @@ printf("random: registering fast source %s\n", rsource->rs_ident); LIST_INSERT_HEAD(&source_list, rrs, rrs_entries); -#endif /* defined(RANDOM_DUMMY) */ } void random_source_deregister(struct random_source *rsource) { -#if defined(RANDOM_DUMMY) - (void)rsource; -#else /* !defined(RANDOM_DUMMY) */ struct random_sources *rrs = NULL; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); @@ -356,41 +341,6 @@ } if (rrs != NULL) free(rrs, M_ENTROPY); -#endif /* defined(RANDOM_DUMMY) */ -} - -#if !defined(RANDOM_DUMMY) -/* - * Run through all fast sources reading entropy for the given - * number of rounds, which should be a multiple of the number - * of entropy accumulation pools in use; 2 for Yarrow and 32 - * for Fortuna. - * - * BEWARE!!! - * This function runs inside the RNG thread! Don't do anything silly! - */ -void -random_sources_feed(void) -{ - uint32_t entropy[HARVESTSIZE]; - struct random_sources *rrs; - u_int i, n, local_read_rate; - - /* - * Step over all of live entropy sources, and feed their output - * to the system-wide RNG. - */ - /* XXX: FIX!! Next lines as an atomic operation? */ - local_read_rate = read_rate; - read_rate = RANDOM_ALG_READ_RATE_MINIMUM; - LIST_FOREACH(rrs, &source_list, rrs_entries) { - for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) { - n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); - KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__)); - random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); - } - } - explicit_bzero(entropy, sizeof(entropy)); } static int @@ -414,7 +364,6 @@ SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, random_source_handler, "A", "List of active fast entropy sources."); -#endif /* !defined(RANDOM_DUMMY) */ /* ARGSUSED */ static int @@ -449,3 +398,5 @@ DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); MODULE_VERSION(random_device, 1); +MODULE_DEPEND(random_device, crypto, 1, 1, 1); +MODULE_DEPEND(random_device, random_harvestq, 1, 1, 1); Index: head/sys/dev/random/randomdev_none.c =================================================================== --- head/sys/dev/random/randomdev_none.c +++ head/sys/dev/random/randomdev_none.c @@ -1,72 +0,0 @@ -/*- - * Copyright (c) 2015 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include - -#include "opt_random.h" - -#if defined(RANDOM_DUMMY) || defined(RANDOM_YARROW) -#error "Cannot define any of RANDOM_DUMMY and RANDOM_YARROW without 'device random'" -#endif - -/*- - * Dummy "not even here" device. Stub out all routines that the kernel would need. - */ - -/* ARGSUSED */ -u_int -read_random(void *random_buf __unused, u_int len __unused) -{ - - return (0); -} - -/* ARGSUSED */ -void -random_harvest_direct(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused) -{ -} - -/* ARGSUSED */ -void -random_harvest_queue(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused) -{ -} - -/* ARGSUSED */ -void -random_harvest_fast(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused) -{ -} Index: head/sys/dev/random/unit_test.c =================================================================== --- head/sys/dev/random/unit_test.c +++ head/sys/dev/random/unit_test.c @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -172,35 +173,6 @@ } static int -WriteCSPRNG(void *threadid) -{ - uint8_t *buf; - int i; - - printf("Thread #1 starts\n"); - - for (i = 0; ; i++) { - if (stopseeding) - break; - buf = malloc(4096); - if (i % 1000 == 0) - printf("Thread write 1 - %d\n", i); - if (buf != NULL) { - printf("Thread 1 writing.\n"); - random_alg_context.ra_write(buf, i); - free(buf); - } - usleep(1000000); - } - - printf("Thread #1 ends\n"); - - thrd_exit(0); - - return (0); -} - -static int ReadCSPRNG(void *threadid) { size_t tid, zsize; @@ -271,7 +243,7 @@ for (t = 0; t < NUM_THREADS; t++) { printf("In main: creating thread %ld\n", t); - rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), NULL); + rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : ReadCSPRNG), NULL); if (rc != thrd_success) { printf("ERROR; return code from thrd_create() is %d\n", rc); exit(-1); Index: head/sys/dev/random/yarrow.c =================================================================== --- head/sys/dev/random/yarrow.c +++ head/sys/dev/random/yarrow.c @@ -49,6 +49,7 @@ #include #else /* !_KERNEL */ #include +#include #include #include #include @@ -92,7 +93,7 @@ u_int ysp_thresh; /* pool reseed threshhold */ struct randomdev_hash ysp_hash; /* accumulated entropy */ } ys_pool[RANDOM_YARROW_NPOOLS];/* pool[0] is fast, pool[1] is slow */ - int ys_seeded; + bool ys_seeded; /* Reseed lock */ mtx_t ys_mtx; } yarrow_state; @@ -108,9 +109,7 @@ static void random_yarrow_pre_read(void); static void random_yarrow_read(uint8_t *, u_int); -static void random_yarrow_write(uint8_t *, u_int); -static void random_yarrow_reseed(void); -static int random_yarrow_seeded(void); +static bool random_yarrow_seeded(void); static void random_yarrow_process_event(struct harvest_event *); static void random_yarrow_init_alg(void *); static void random_yarrow_deinit_alg(void *); @@ -123,8 +122,6 @@ .ra_deinit_alg = random_yarrow_deinit_alg, .ra_pre_read = random_yarrow_pre_read, .ra_read = random_yarrow_read, - .ra_write = random_yarrow_write, - .ra_reseed = random_yarrow_reseed, .ra_seeded = random_yarrow_seeded, .ra_event_processor = random_yarrow_process_event, .ra_poolcount = RANDOM_YARROW_NPOOLS, @@ -141,7 +138,7 @@ RANDOM_RESEED_INIT_LOCK(); /* Start unseeded, therefore blocked. */ - yarrow_state.ys_seeded = 0; + yarrow_state.ys_seeded = false; #ifdef _KERNEL /* * Yarrow parameters. Do not adjust these unless you have @@ -266,12 +263,14 @@ RANDOM_RESEED_ASSERT_LOCK_OWNED(); #ifdef RANDOM_DEBUG /* WARNING! This is dangerously tedious to do with mutexes held! */ - printf("random: %s %s seeded = %d\n", __func__, (fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW"), yarrow_state.ys_seeded); - printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh); + printf("random: %s ", __func__); + printf("type/pool = %s ", fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW"); + printf("seeded = %s\n", yarrow_state.ys_seeded ? "true" : "false"); + printf("random: fast - thresh %d,1 - ", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh); for (i = RANDOM_START; i < ENTROPYSOURCE; i++) printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_source_bits[i]); printf("\n"); - printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh); + printf("random: slow - thresh %d,%d - ", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh); for (i = RANDOM_START; i < ENTROPYSOURCE; i++) printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_source_bits[i]); printf("\n"); @@ -338,7 +337,7 @@ #endif /* Unblock the device if it was blocked due to being unseeded */ if (!yarrow_state.ys_seeded) { - yarrow_state.ys_seeded = 1; + yarrow_state.ys_seeded = true; randomdev_unblock(); } } @@ -395,47 +394,7 @@ RANDOM_RESEED_UNLOCK(); } -/* Internal function to hand external entropy to the PRNG. */ -void -random_yarrow_write(uint8_t *buf, u_int count) -{ - static u_int destination = 0; - static struct harvest_event event; - struct randomdev_hash hash; - uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp; - int i; - - /* Extra timing here is helpful to scrape scheduler timing entropy */ - randomdev_hash_init(&hash); - timestamp = (uint32_t)get_cyclecount(); - randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); - randomdev_hash_iterate(&hash, buf, count); - timestamp = (uint32_t)get_cyclecount(); - randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); - randomdev_hash_finish(&hash, entropy_data); - explicit_bzero(&hash, sizeof(hash)); - for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { - event.he_somecounter = (uint32_t)get_cyclecount(); - event.he_size = sizeof(event.he_entropy); - event.he_bits = event.he_size/8; - event.he_source = RANDOM_CACHED; - event.he_destination = destination++; /* Harmless cheating */ - memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy)); - random_yarrow_process_event(&event); - } - explicit_bzero(entropy_data, sizeof(entropy_data)); -} - -void -random_yarrow_reseed(void) -{ - - RANDOM_RESEED_LOCK(); - random_yarrow_reseed_internal(RANDOM_YARROW_SLOW); - RANDOM_RESEED_UNLOCK(); -} - -int +bool random_yarrow_seeded(void) { Index: head/sys/modules/Makefile =================================================================== --- head/sys/modules/Makefile +++ head/sys/modules/Makefile @@ -296,6 +296,9 @@ ${_qlxgbe} \ ral \ ${_ralfw} \ + ${_random_fortuna} \ + ${_random_yarrow} \ + ${_random_other} \ rc4 \ ${_rdma} \ ${_rdrand_rng} \ @@ -398,6 +401,9 @@ .if exists(${.CURDIR}/../opencrypto) _crypto= crypto _cryptodev= cryptodev +_random_fortuna=random_fortuna +_random_yarrow= random_yarrow +_random_other= random_other .endif .endif Index: head/sys/modules/random_fortuna/Makefile =================================================================== --- head/sys/modules/random_fortuna/Makefile +++ head/sys/modules/random_fortuna/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/random + +KMOD = random_fortuna +SRCS = randomdev.c hash.c fortuna.c +SRCS += opt_param.h bus_if.h device_if.h +SRCS += opt_ddb.h +CFLAGS += -DRANDOM_LOADABLE + +.include Index: head/sys/modules/random_other/Makefile =================================================================== --- head/sys/modules/random_other/Makefile +++ head/sys/modules/random_other/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/random + +KMOD = random_OTHER +SRCS = randomdev.c hash.c other_algorithm.c +SRCS += opt_param.h bus_if.h device_if.h +SRCS += opt_ddb.h +CFLAGS += -DRANDOM_LOADABLE + +.include Index: head/sys/modules/random_yarrow/Makefile =================================================================== --- head/sys/modules/random_yarrow/Makefile +++ head/sys/modules/random_yarrow/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/random + +KMOD = random_yarrow +SRCS = randomdev.c hash.c yarrow.c +SRCS += opt_param.h bus_if.h device_if.h +SRCS += opt_ddb.h +CFLAGS += -DRANDOM_LOADABLE + +.include Index: head/sys/sys/random.h =================================================================== --- head/sys/sys/random.h +++ head/sys/sys/random.h @@ -33,10 +33,29 @@ #include +#include "opt_random.h" + +#if defined(RANDOM_LOADABLE) && defined(RANDOM_YARROW) +#error "Cannot define both RANDOM_LOADABLE and RANDOM_YARROW" +#endif + struct uio; +#if defined(DEV_RANDOM) u_int read_random(void *, u_int); int read_random_uio(struct uio *, bool); +#else +static __inline int +read_random_uio(void *a __unused, u_int b __unused) +{ + return (0); +} +static __inline u_int +read_random(void *a __unused, u_int b __unused) +{ + return (0); +} +#endif /* * Note: if you add or remove members of random_entropy_source, remember to also update the @@ -76,15 +95,15 @@ #define RANDOM_HARVEST_EVERYTHING_MASK ((1 << (RANDOM_ENVIRONMENTAL_END + 1)) - 1) -#if defined(RANDOM_DUMMY) -#define random_harvest_queue(a, b, c, d) do {} while (0) -#define random_harvest_fast(a, b, c, d) do {} while (0) -#define random_harvest_direct(a, b, c, d) do {} while (0) -#else /* !defined(RANDOM_DUMMY) */ +#if defined(DEV_RANDOM) void random_harvest_queue(const void *, u_int, u_int, enum random_entropy_source); void random_harvest_fast(const void *, u_int, u_int, enum random_entropy_source); void random_harvest_direct(const void *, u_int, u_int, enum random_entropy_source); -#endif /* defined(RANDOM_DUMMY) */ +#else +#define random_harvest_queue(a, b, c, d) do {} while (0) +#define random_harvest_fast(a, b, c, d) do {} while (0) +#define random_harvest_direct(a, b, c, d) do {} while (0) +#endif #endif /* _KERNEL */