1*00b67f09SDavid van Moolenbroek /* $NetBSD: entropy.c,v 1.5 2014/12/10 04:37:59 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004-2007, 2009, 2010, 2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 2000-2003 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: entropy.c,v 1.22 2010/08/10 23:48:19 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file
23*00b67f09SDavid van Moolenbroek * \brief
24*00b67f09SDavid van Moolenbroek * This is the system independent part of the entropy module. It is
25*00b67f09SDavid van Moolenbroek * compiled via inclusion from the relevant OS source file, ie,
26*00b67f09SDavid van Moolenbroek * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
27*00b67f09SDavid van Moolenbroek *
28*00b67f09SDavid van Moolenbroek * \author Much of this code is modeled after the NetBSD /dev/random implementation,
29*00b67f09SDavid van Moolenbroek * written by Michael Graff <explorer@netbsd.org>.
30*00b67f09SDavid van Moolenbroek */
31*00b67f09SDavid van Moolenbroek
32*00b67f09SDavid van Moolenbroek #include <errno.h>
33*00b67f09SDavid van Moolenbroek #include <fcntl.h>
34*00b67f09SDavid van Moolenbroek #include <stdio.h>
35*00b67f09SDavid van Moolenbroek
36*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
37*00b67f09SDavid van Moolenbroek #include <isc/entropy.h>
38*00b67f09SDavid van Moolenbroek #include <isc/keyboard.h>
39*00b67f09SDavid van Moolenbroek #include <isc/list.h>
40*00b67f09SDavid van Moolenbroek #include <isc/magic.h>
41*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
42*00b67f09SDavid van Moolenbroek #include <isc/msgs.h>
43*00b67f09SDavid van Moolenbroek #include <isc/mutex.h>
44*00b67f09SDavid van Moolenbroek #include <isc/platform.h>
45*00b67f09SDavid van Moolenbroek #include <isc/region.h>
46*00b67f09SDavid van Moolenbroek #include <isc/sha1.h>
47*00b67f09SDavid van Moolenbroek #include <isc/string.h>
48*00b67f09SDavid van Moolenbroek #include <isc/time.h>
49*00b67f09SDavid van Moolenbroek #include <isc/util.h>
50*00b67f09SDavid van Moolenbroek
51*00b67f09SDavid van Moolenbroek #ifdef PKCS11CRYPTO
52*00b67f09SDavid van Moolenbroek #include <pk11/pk11.h>
53*00b67f09SDavid van Moolenbroek #endif
54*00b67f09SDavid van Moolenbroek
55*00b67f09SDavid van Moolenbroek #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
56*00b67f09SDavid van Moolenbroek #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
57*00b67f09SDavid van Moolenbroek
58*00b67f09SDavid van Moolenbroek #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
59*00b67f09SDavid van Moolenbroek #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
60*00b67f09SDavid van Moolenbroek
61*00b67f09SDavid van Moolenbroek /***
62*00b67f09SDavid van Moolenbroek *** "constants." Do not change these unless you _really_ know what
63*00b67f09SDavid van Moolenbroek *** you are doing.
64*00b67f09SDavid van Moolenbroek ***/
65*00b67f09SDavid van Moolenbroek
66*00b67f09SDavid van Moolenbroek /*%
67*00b67f09SDavid van Moolenbroek * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
68*00b67f09SDavid van Moolenbroek */
69*00b67f09SDavid van Moolenbroek #define RND_POOLWORDS 128
70*00b67f09SDavid van Moolenbroek /*% Pool in bytes. */
71*00b67f09SDavid van Moolenbroek #define RND_POOLBYTES (RND_POOLWORDS * 4)
72*00b67f09SDavid van Moolenbroek /*% Pool in bits. */
73*00b67f09SDavid van Moolenbroek #define RND_POOLBITS (RND_POOLWORDS * 32)
74*00b67f09SDavid van Moolenbroek
75*00b67f09SDavid van Moolenbroek /*%
76*00b67f09SDavid van Moolenbroek * Number of bytes returned per hash. This must be true:
77*00b67f09SDavid van Moolenbroek * threshold * 2 <= digest_size_in_bytes
78*00b67f09SDavid van Moolenbroek */
79*00b67f09SDavid van Moolenbroek #define RND_ENTROPY_THRESHOLD 10
80*00b67f09SDavid van Moolenbroek #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
81*00b67f09SDavid van Moolenbroek
82*00b67f09SDavid van Moolenbroek /*%
83*00b67f09SDavid van Moolenbroek * Size of the input event queue in samples.
84*00b67f09SDavid van Moolenbroek */
85*00b67f09SDavid van Moolenbroek #define RND_EVENTQSIZE 32
86*00b67f09SDavid van Moolenbroek
87*00b67f09SDavid van Moolenbroek /*%
88*00b67f09SDavid van Moolenbroek * The number of times we'll "reseed" for pseudorandom seeds. This is an
89*00b67f09SDavid van Moolenbroek * extremely weak pseudorandom seed. If the caller is using lots of
90*00b67f09SDavid van Moolenbroek * pseudorandom data and they cannot provide a stronger random source,
91*00b67f09SDavid van Moolenbroek * there is little we can do other than hope they're smart enough to
92*00b67f09SDavid van Moolenbroek * call _adddata() with something better than we can come up with.
93*00b67f09SDavid van Moolenbroek */
94*00b67f09SDavid van Moolenbroek #define RND_INITIALIZE 128
95*00b67f09SDavid van Moolenbroek
96*00b67f09SDavid van Moolenbroek /*% Entropy Pool */
97*00b67f09SDavid van Moolenbroek typedef struct {
98*00b67f09SDavid van Moolenbroek isc_uint32_t cursor; /*%< current add point in the pool */
99*00b67f09SDavid van Moolenbroek isc_uint32_t entropy; /*%< current entropy estimate in bits */
100*00b67f09SDavid van Moolenbroek isc_uint32_t pseudo; /*%< bits extracted in pseudorandom */
101*00b67f09SDavid van Moolenbroek isc_uint32_t rotate; /*%< how many bits to rotate by */
102*00b67f09SDavid van Moolenbroek isc_uint32_t pool[RND_POOLWORDS]; /*%< random pool data */
103*00b67f09SDavid van Moolenbroek } isc_entropypool_t;
104*00b67f09SDavid van Moolenbroek
105*00b67f09SDavid van Moolenbroek struct isc_entropy {
106*00b67f09SDavid van Moolenbroek unsigned int magic;
107*00b67f09SDavid van Moolenbroek isc_mem_t *mctx;
108*00b67f09SDavid van Moolenbroek isc_mutex_t lock;
109*00b67f09SDavid van Moolenbroek unsigned int refcnt;
110*00b67f09SDavid van Moolenbroek isc_uint32_t initialized;
111*00b67f09SDavid van Moolenbroek isc_uint32_t initcount;
112*00b67f09SDavid van Moolenbroek isc_entropypool_t pool;
113*00b67f09SDavid van Moolenbroek unsigned int nsources;
114*00b67f09SDavid van Moolenbroek isc_entropysource_t *nextsource;
115*00b67f09SDavid van Moolenbroek ISC_LIST(isc_entropysource_t) sources;
116*00b67f09SDavid van Moolenbroek };
117*00b67f09SDavid van Moolenbroek
118*00b67f09SDavid van Moolenbroek /*% Sample Queue */
119*00b67f09SDavid van Moolenbroek typedef struct {
120*00b67f09SDavid van Moolenbroek isc_uint32_t last_time; /*%< last time recorded */
121*00b67f09SDavid van Moolenbroek isc_uint32_t last_delta; /*%< last delta value */
122*00b67f09SDavid van Moolenbroek isc_uint32_t last_delta2; /*%< last delta2 value */
123*00b67f09SDavid van Moolenbroek isc_uint32_t nsamples; /*%< number of samples filled in */
124*00b67f09SDavid van Moolenbroek isc_uint32_t *samples; /*%< the samples */
125*00b67f09SDavid van Moolenbroek isc_uint32_t *extra; /*%< extra samples added in */
126*00b67f09SDavid van Moolenbroek } sample_queue_t;
127*00b67f09SDavid van Moolenbroek
128*00b67f09SDavid van Moolenbroek typedef struct {
129*00b67f09SDavid van Moolenbroek sample_queue_t samplequeue;
130*00b67f09SDavid van Moolenbroek } isc_entropysamplesource_t;
131*00b67f09SDavid van Moolenbroek
132*00b67f09SDavid van Moolenbroek typedef struct {
133*00b67f09SDavid van Moolenbroek isc_boolean_t start_called;
134*00b67f09SDavid van Moolenbroek isc_entropystart_t startfunc;
135*00b67f09SDavid van Moolenbroek isc_entropyget_t getfunc;
136*00b67f09SDavid van Moolenbroek isc_entropystop_t stopfunc;
137*00b67f09SDavid van Moolenbroek void *arg;
138*00b67f09SDavid van Moolenbroek sample_queue_t samplequeue;
139*00b67f09SDavid van Moolenbroek } isc_cbsource_t;
140*00b67f09SDavid van Moolenbroek
141*00b67f09SDavid van Moolenbroek typedef struct {
142*00b67f09SDavid van Moolenbroek FILESOURCE_HANDLE_TYPE handle;
143*00b67f09SDavid van Moolenbroek } isc_entropyfilesource_t;
144*00b67f09SDavid van Moolenbroek
145*00b67f09SDavid van Moolenbroek struct isc_entropysource {
146*00b67f09SDavid van Moolenbroek unsigned int magic;
147*00b67f09SDavid van Moolenbroek unsigned int type;
148*00b67f09SDavid van Moolenbroek isc_entropy_t *ent;
149*00b67f09SDavid van Moolenbroek isc_uint32_t total; /*%< entropy from this source */
150*00b67f09SDavid van Moolenbroek ISC_LINK(isc_entropysource_t) link;
151*00b67f09SDavid van Moolenbroek char name[32];
152*00b67f09SDavid van Moolenbroek isc_boolean_t bad;
153*00b67f09SDavid van Moolenbroek isc_boolean_t warn_keyboard;
154*00b67f09SDavid van Moolenbroek isc_keyboard_t kbd;
155*00b67f09SDavid van Moolenbroek union {
156*00b67f09SDavid van Moolenbroek isc_entropysamplesource_t sample;
157*00b67f09SDavid van Moolenbroek isc_entropyfilesource_t file;
158*00b67f09SDavid van Moolenbroek isc_cbsource_t callback;
159*00b67f09SDavid van Moolenbroek isc_entropyusocketsource_t usocket;
160*00b67f09SDavid van Moolenbroek } sources;
161*00b67f09SDavid van Moolenbroek };
162*00b67f09SDavid van Moolenbroek
163*00b67f09SDavid van Moolenbroek #define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
164*00b67f09SDavid van Moolenbroek #define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
165*00b67f09SDavid van Moolenbroek #define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
166*00b67f09SDavid van Moolenbroek #define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
167*00b67f09SDavid van Moolenbroek
168*00b67f09SDavid van Moolenbroek /*@{*/
169*00b67f09SDavid van Moolenbroek /*%
170*00b67f09SDavid van Moolenbroek * The random pool "taps"
171*00b67f09SDavid van Moolenbroek */
172*00b67f09SDavid van Moolenbroek #define TAP1 99
173*00b67f09SDavid van Moolenbroek #define TAP2 59
174*00b67f09SDavid van Moolenbroek #define TAP3 31
175*00b67f09SDavid van Moolenbroek #define TAP4 9
176*00b67f09SDavid van Moolenbroek #define TAP5 7
177*00b67f09SDavid van Moolenbroek /*@}*/
178*00b67f09SDavid van Moolenbroek
179*00b67f09SDavid van Moolenbroek /*@{*/
180*00b67f09SDavid van Moolenbroek /*%
181*00b67f09SDavid van Moolenbroek * Declarations for function provided by the system dependent sources that
182*00b67f09SDavid van Moolenbroek * include this file.
183*00b67f09SDavid van Moolenbroek */
184*00b67f09SDavid van Moolenbroek static void
185*00b67f09SDavid van Moolenbroek fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
186*00b67f09SDavid van Moolenbroek
187*00b67f09SDavid van Moolenbroek static int
188*00b67f09SDavid van Moolenbroek wait_for_sources(isc_entropy_t *);
189*00b67f09SDavid van Moolenbroek
190*00b67f09SDavid van Moolenbroek static void
191*00b67f09SDavid van Moolenbroek destroyfilesource(isc_entropyfilesource_t *source);
192*00b67f09SDavid van Moolenbroek
193*00b67f09SDavid van Moolenbroek static void
194*00b67f09SDavid van Moolenbroek destroyusocketsource(isc_entropyusocketsource_t *source);
195*00b67f09SDavid van Moolenbroek
196*00b67f09SDavid van Moolenbroek /*@}*/
197*00b67f09SDavid van Moolenbroek
198*00b67f09SDavid van Moolenbroek static void
samplequeue_release(isc_entropy_t * ent,sample_queue_t * sq)199*00b67f09SDavid van Moolenbroek samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
200*00b67f09SDavid van Moolenbroek REQUIRE(sq->samples != NULL);
201*00b67f09SDavid van Moolenbroek REQUIRE(sq->extra != NULL);
202*00b67f09SDavid van Moolenbroek
203*00b67f09SDavid van Moolenbroek isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
204*00b67f09SDavid van Moolenbroek isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
205*00b67f09SDavid van Moolenbroek sq->samples = NULL;
206*00b67f09SDavid van Moolenbroek sq->extra = NULL;
207*00b67f09SDavid van Moolenbroek }
208*00b67f09SDavid van Moolenbroek
209*00b67f09SDavid van Moolenbroek static isc_result_t
samplesource_allocate(isc_entropy_t * ent,sample_queue_t * sq)210*00b67f09SDavid van Moolenbroek samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
211*00b67f09SDavid van Moolenbroek sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
212*00b67f09SDavid van Moolenbroek if (sq->samples == NULL)
213*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
214*00b67f09SDavid van Moolenbroek
215*00b67f09SDavid van Moolenbroek sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
216*00b67f09SDavid van Moolenbroek if (sq->extra == NULL) {
217*00b67f09SDavid van Moolenbroek isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
218*00b67f09SDavid van Moolenbroek sq->samples = NULL;
219*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
220*00b67f09SDavid van Moolenbroek }
221*00b67f09SDavid van Moolenbroek
222*00b67f09SDavid van Moolenbroek sq->nsamples = 0;
223*00b67f09SDavid van Moolenbroek
224*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
225*00b67f09SDavid van Moolenbroek }
226*00b67f09SDavid van Moolenbroek
227*00b67f09SDavid van Moolenbroek /*%
228*00b67f09SDavid van Moolenbroek * Add in entropy, even when the value we're adding in could be
229*00b67f09SDavid van Moolenbroek * very large.
230*00b67f09SDavid van Moolenbroek */
231*00b67f09SDavid van Moolenbroek static inline void
add_entropy(isc_entropy_t * ent,isc_uint32_t entropy)232*00b67f09SDavid van Moolenbroek add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
233*00b67f09SDavid van Moolenbroek /* clamp input. Yes, this must be done. */
234*00b67f09SDavid van Moolenbroek entropy = ISC_MIN(entropy, RND_POOLBITS);
235*00b67f09SDavid van Moolenbroek /* Add in the entropy we already have. */
236*00b67f09SDavid van Moolenbroek entropy += ent->pool.entropy;
237*00b67f09SDavid van Moolenbroek /* Clamp. */
238*00b67f09SDavid van Moolenbroek ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
239*00b67f09SDavid van Moolenbroek }
240*00b67f09SDavid van Moolenbroek
241*00b67f09SDavid van Moolenbroek /*%
242*00b67f09SDavid van Moolenbroek * Decrement the amount of entropy the pool has.
243*00b67f09SDavid van Moolenbroek */
244*00b67f09SDavid van Moolenbroek static inline void
subtract_entropy(isc_entropy_t * ent,isc_uint32_t entropy)245*00b67f09SDavid van Moolenbroek subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
246*00b67f09SDavid van Moolenbroek entropy = ISC_MIN(entropy, ent->pool.entropy);
247*00b67f09SDavid van Moolenbroek ent->pool.entropy -= entropy;
248*00b67f09SDavid van Moolenbroek }
249*00b67f09SDavid van Moolenbroek
250*00b67f09SDavid van Moolenbroek /*!
251*00b67f09SDavid van Moolenbroek * Add in entropy, even when the value we're adding in could be
252*00b67f09SDavid van Moolenbroek * very large.
253*00b67f09SDavid van Moolenbroek */
254*00b67f09SDavid van Moolenbroek static inline void
add_pseudo(isc_entropy_t * ent,isc_uint32_t pseudo)255*00b67f09SDavid van Moolenbroek add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
256*00b67f09SDavid van Moolenbroek /* clamp input. Yes, this must be done. */
257*00b67f09SDavid van Moolenbroek pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
258*00b67f09SDavid van Moolenbroek /* Add in the pseudo we already have. */
259*00b67f09SDavid van Moolenbroek pseudo += ent->pool.pseudo;
260*00b67f09SDavid van Moolenbroek /* Clamp. */
261*00b67f09SDavid van Moolenbroek ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
262*00b67f09SDavid van Moolenbroek }
263*00b67f09SDavid van Moolenbroek
264*00b67f09SDavid van Moolenbroek /*!
265*00b67f09SDavid van Moolenbroek * Decrement the amount of pseudo the pool has.
266*00b67f09SDavid van Moolenbroek */
267*00b67f09SDavid van Moolenbroek static inline void
subtract_pseudo(isc_entropy_t * ent,isc_uint32_t pseudo)268*00b67f09SDavid van Moolenbroek subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
269*00b67f09SDavid van Moolenbroek pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
270*00b67f09SDavid van Moolenbroek ent->pool.pseudo -= pseudo;
271*00b67f09SDavid van Moolenbroek }
272*00b67f09SDavid van Moolenbroek
273*00b67f09SDavid van Moolenbroek /*!
274*00b67f09SDavid van Moolenbroek * Add one word to the pool, rotating the input as needed.
275*00b67f09SDavid van Moolenbroek */
276*00b67f09SDavid van Moolenbroek static inline void
entropypool_add_word(isc_entropypool_t * rp,isc_uint32_t val)277*00b67f09SDavid van Moolenbroek entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
278*00b67f09SDavid van Moolenbroek /*
279*00b67f09SDavid van Moolenbroek * Steal some values out of the pool, and xor them into the
280*00b67f09SDavid van Moolenbroek * word we were given.
281*00b67f09SDavid van Moolenbroek *
282*00b67f09SDavid van Moolenbroek * Mix the new value into the pool using xor. This will
283*00b67f09SDavid van Moolenbroek * prevent the actual values from being known to the caller
284*00b67f09SDavid van Moolenbroek * since the previous values are assumed to be unknown as well.
285*00b67f09SDavid van Moolenbroek */
286*00b67f09SDavid van Moolenbroek val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
287*00b67f09SDavid van Moolenbroek val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
288*00b67f09SDavid van Moolenbroek val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
289*00b67f09SDavid van Moolenbroek val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
290*00b67f09SDavid van Moolenbroek val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
291*00b67f09SDavid van Moolenbroek if (rp->rotate == 0)
292*00b67f09SDavid van Moolenbroek rp->pool[rp->cursor++] ^= val;
293*00b67f09SDavid van Moolenbroek else
294*00b67f09SDavid van Moolenbroek rp->pool[rp->cursor++] ^=
295*00b67f09SDavid van Moolenbroek ((val << rp->rotate) | (val >> (32 - rp->rotate)));
296*00b67f09SDavid van Moolenbroek
297*00b67f09SDavid van Moolenbroek /*
298*00b67f09SDavid van Moolenbroek * If we have looped around the pool, increment the rotate
299*00b67f09SDavid van Moolenbroek * variable so the next value will get xored in rotated to
300*00b67f09SDavid van Moolenbroek * a different position.
301*00b67f09SDavid van Moolenbroek * Increment by a value that is relatively prime to the word size
302*00b67f09SDavid van Moolenbroek * to try to spread the bits throughout the pool quickly when the
303*00b67f09SDavid van Moolenbroek * pool is empty.
304*00b67f09SDavid van Moolenbroek */
305*00b67f09SDavid van Moolenbroek if (rp->cursor == RND_POOLWORDS) {
306*00b67f09SDavid van Moolenbroek rp->cursor = 0;
307*00b67f09SDavid van Moolenbroek rp->rotate = (rp->rotate + 7) & 31;
308*00b67f09SDavid van Moolenbroek }
309*00b67f09SDavid van Moolenbroek }
310*00b67f09SDavid van Moolenbroek
311*00b67f09SDavid van Moolenbroek /*!
312*00b67f09SDavid van Moolenbroek * Add a buffer's worth of data to the pool.
313*00b67f09SDavid van Moolenbroek *
314*00b67f09SDavid van Moolenbroek * Requires that the lock is held on the entropy pool.
315*00b67f09SDavid van Moolenbroek */
316*00b67f09SDavid van Moolenbroek static void
entropypool_adddata(isc_entropy_t * ent,void * p,unsigned int len,isc_uint32_t entropy)317*00b67f09SDavid van Moolenbroek entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
318*00b67f09SDavid van Moolenbroek isc_uint32_t entropy)
319*00b67f09SDavid van Moolenbroek {
320*00b67f09SDavid van Moolenbroek isc_uint32_t val;
321*00b67f09SDavid van Moolenbroek unsigned long addr;
322*00b67f09SDavid van Moolenbroek isc_uint8_t *buf;
323*00b67f09SDavid van Moolenbroek
324*00b67f09SDavid van Moolenbroek addr = (unsigned long)p;
325*00b67f09SDavid van Moolenbroek buf = p;
326*00b67f09SDavid van Moolenbroek
327*00b67f09SDavid van Moolenbroek if ((addr & 0x03U) != 0U) {
328*00b67f09SDavid van Moolenbroek val = 0;
329*00b67f09SDavid van Moolenbroek switch (len) {
330*00b67f09SDavid van Moolenbroek case 3:
331*00b67f09SDavid van Moolenbroek val = *buf++;
332*00b67f09SDavid van Moolenbroek len--;
333*00b67f09SDavid van Moolenbroek case 2:
334*00b67f09SDavid van Moolenbroek val = val << 8 | *buf++;
335*00b67f09SDavid van Moolenbroek len--;
336*00b67f09SDavid van Moolenbroek case 1:
337*00b67f09SDavid van Moolenbroek val = val << 8 | *buf++;
338*00b67f09SDavid van Moolenbroek len--;
339*00b67f09SDavid van Moolenbroek }
340*00b67f09SDavid van Moolenbroek
341*00b67f09SDavid van Moolenbroek entropypool_add_word(&ent->pool, val);
342*00b67f09SDavid van Moolenbroek }
343*00b67f09SDavid van Moolenbroek
344*00b67f09SDavid van Moolenbroek for (; len > 3; len -= 4) {
345*00b67f09SDavid van Moolenbroek val = *((isc_uint32_t *)buf);
346*00b67f09SDavid van Moolenbroek
347*00b67f09SDavid van Moolenbroek entropypool_add_word(&ent->pool, val);
348*00b67f09SDavid van Moolenbroek buf += 4;
349*00b67f09SDavid van Moolenbroek }
350*00b67f09SDavid van Moolenbroek
351*00b67f09SDavid van Moolenbroek if (len != 0) {
352*00b67f09SDavid van Moolenbroek val = 0;
353*00b67f09SDavid van Moolenbroek switch (len) {
354*00b67f09SDavid van Moolenbroek case 3:
355*00b67f09SDavid van Moolenbroek val = *buf++;
356*00b67f09SDavid van Moolenbroek case 2:
357*00b67f09SDavid van Moolenbroek val = val << 8 | *buf++;
358*00b67f09SDavid van Moolenbroek case 1:
359*00b67f09SDavid van Moolenbroek val = val << 8 | *buf++;
360*00b67f09SDavid van Moolenbroek }
361*00b67f09SDavid van Moolenbroek
362*00b67f09SDavid van Moolenbroek entropypool_add_word(&ent->pool, val);
363*00b67f09SDavid van Moolenbroek }
364*00b67f09SDavid van Moolenbroek
365*00b67f09SDavid van Moolenbroek add_entropy(ent, entropy);
366*00b67f09SDavid van Moolenbroek subtract_pseudo(ent, entropy);
367*00b67f09SDavid van Moolenbroek }
368*00b67f09SDavid van Moolenbroek
369*00b67f09SDavid van Moolenbroek static inline void
reseed(isc_entropy_t * ent)370*00b67f09SDavid van Moolenbroek reseed(isc_entropy_t *ent) {
371*00b67f09SDavid van Moolenbroek isc_time_t t;
372*00b67f09SDavid van Moolenbroek pid_t pid;
373*00b67f09SDavid van Moolenbroek
374*00b67f09SDavid van Moolenbroek if (ent->initcount == 0) {
375*00b67f09SDavid van Moolenbroek pid = getpid();
376*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, &pid, sizeof(pid), 0);
377*00b67f09SDavid van Moolenbroek pid = getppid();
378*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, &pid, sizeof(pid), 0);
379*00b67f09SDavid van Moolenbroek }
380*00b67f09SDavid van Moolenbroek
381*00b67f09SDavid van Moolenbroek /*!
382*00b67f09SDavid van Moolenbroek * After we've reseeded 100 times, only add new timing info every
383*00b67f09SDavid van Moolenbroek * 50 requests. This will keep us from using lots and lots of
384*00b67f09SDavid van Moolenbroek * CPU just to return bad pseudorandom data anyway.
385*00b67f09SDavid van Moolenbroek */
386*00b67f09SDavid van Moolenbroek if (ent->initcount > 100)
387*00b67f09SDavid van Moolenbroek if ((ent->initcount % 50) != 0)
388*00b67f09SDavid van Moolenbroek return;
389*00b67f09SDavid van Moolenbroek
390*00b67f09SDavid van Moolenbroek TIME_NOW(&t);
391*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, &t, sizeof(t), 0);
392*00b67f09SDavid van Moolenbroek ent->initcount++;
393*00b67f09SDavid van Moolenbroek }
394*00b67f09SDavid van Moolenbroek
395*00b67f09SDavid van Moolenbroek static inline unsigned int
estimate_entropy(sample_queue_t * sq,isc_uint32_t t)396*00b67f09SDavid van Moolenbroek estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
397*00b67f09SDavid van Moolenbroek isc_int32_t delta;
398*00b67f09SDavid van Moolenbroek isc_int32_t delta2;
399*00b67f09SDavid van Moolenbroek isc_int32_t delta3;
400*00b67f09SDavid van Moolenbroek
401*00b67f09SDavid van Moolenbroek /*!
402*00b67f09SDavid van Moolenbroek * If the time counter has overflowed, calculate the real difference.
403*00b67f09SDavid van Moolenbroek * If it has not, it is simpler.
404*00b67f09SDavid van Moolenbroek */
405*00b67f09SDavid van Moolenbroek if (t < sq->last_time)
406*00b67f09SDavid van Moolenbroek delta = UINT_MAX - sq->last_time + t;
407*00b67f09SDavid van Moolenbroek else
408*00b67f09SDavid van Moolenbroek delta = sq->last_time - t;
409*00b67f09SDavid van Moolenbroek
410*00b67f09SDavid van Moolenbroek if (delta < 0)
411*00b67f09SDavid van Moolenbroek delta = -delta;
412*00b67f09SDavid van Moolenbroek
413*00b67f09SDavid van Moolenbroek /*
414*00b67f09SDavid van Moolenbroek * Calculate the second and third order differentials
415*00b67f09SDavid van Moolenbroek */
416*00b67f09SDavid van Moolenbroek delta2 = sq->last_delta - delta;
417*00b67f09SDavid van Moolenbroek if (delta2 < 0)
418*00b67f09SDavid van Moolenbroek delta2 = -delta2;
419*00b67f09SDavid van Moolenbroek
420*00b67f09SDavid van Moolenbroek delta3 = sq->last_delta2 - delta2;
421*00b67f09SDavid van Moolenbroek if (delta3 < 0)
422*00b67f09SDavid van Moolenbroek delta3 = -delta3;
423*00b67f09SDavid van Moolenbroek
424*00b67f09SDavid van Moolenbroek sq->last_time = t;
425*00b67f09SDavid van Moolenbroek sq->last_delta = delta;
426*00b67f09SDavid van Moolenbroek sq->last_delta2 = delta2;
427*00b67f09SDavid van Moolenbroek
428*00b67f09SDavid van Moolenbroek /*
429*00b67f09SDavid van Moolenbroek * If any delta is 0, we got no entropy. If all are non-zero, we
430*00b67f09SDavid van Moolenbroek * might have something.
431*00b67f09SDavid van Moolenbroek */
432*00b67f09SDavid van Moolenbroek if (delta == 0 || delta2 == 0 || delta3 == 0)
433*00b67f09SDavid van Moolenbroek return 0;
434*00b67f09SDavid van Moolenbroek
435*00b67f09SDavid van Moolenbroek /*
436*00b67f09SDavid van Moolenbroek * We could find the smallest delta and claim we got log2(delta)
437*00b67f09SDavid van Moolenbroek * bits, but for now return that we found 1 bit.
438*00b67f09SDavid van Moolenbroek */
439*00b67f09SDavid van Moolenbroek return 1;
440*00b67f09SDavid van Moolenbroek }
441*00b67f09SDavid van Moolenbroek
442*00b67f09SDavid van Moolenbroek static unsigned int
crunchsamples(isc_entropy_t * ent,sample_queue_t * sq)443*00b67f09SDavid van Moolenbroek crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
444*00b67f09SDavid van Moolenbroek unsigned int ns;
445*00b67f09SDavid van Moolenbroek unsigned int added;
446*00b67f09SDavid van Moolenbroek
447*00b67f09SDavid van Moolenbroek if (sq->nsamples < 6)
448*00b67f09SDavid van Moolenbroek return (0);
449*00b67f09SDavid van Moolenbroek
450*00b67f09SDavid van Moolenbroek added = 0;
451*00b67f09SDavid van Moolenbroek sq->last_time = sq->samples[0];
452*00b67f09SDavid van Moolenbroek sq->last_delta = 0;
453*00b67f09SDavid van Moolenbroek sq->last_delta2 = 0;
454*00b67f09SDavid van Moolenbroek
455*00b67f09SDavid van Moolenbroek /*
456*00b67f09SDavid van Moolenbroek * Prime the values by adding in the first 4 samples in. This
457*00b67f09SDavid van Moolenbroek * should completely initialize the delta calculations.
458*00b67f09SDavid van Moolenbroek */
459*00b67f09SDavid van Moolenbroek for (ns = 0; ns < 4; ns++)
460*00b67f09SDavid van Moolenbroek (void)estimate_entropy(sq, sq->samples[ns]);
461*00b67f09SDavid van Moolenbroek
462*00b67f09SDavid van Moolenbroek for (ns = 4; ns < sq->nsamples; ns++)
463*00b67f09SDavid van Moolenbroek added += estimate_entropy(sq, sq->samples[ns]);
464*00b67f09SDavid van Moolenbroek
465*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
466*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
467*00b67f09SDavid van Moolenbroek
468*00b67f09SDavid van Moolenbroek /*
469*00b67f09SDavid van Moolenbroek * Move the last 4 samples into the first 4 positions, and start
470*00b67f09SDavid van Moolenbroek * adding new samples from that point.
471*00b67f09SDavid van Moolenbroek */
472*00b67f09SDavid van Moolenbroek for (ns = 0; ns < 4; ns++) {
473*00b67f09SDavid van Moolenbroek sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
474*00b67f09SDavid van Moolenbroek sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
475*00b67f09SDavid van Moolenbroek }
476*00b67f09SDavid van Moolenbroek
477*00b67f09SDavid van Moolenbroek sq->nsamples = 4;
478*00b67f09SDavid van Moolenbroek
479*00b67f09SDavid van Moolenbroek return (added);
480*00b67f09SDavid van Moolenbroek }
481*00b67f09SDavid van Moolenbroek
482*00b67f09SDavid van Moolenbroek static unsigned int
get_from_callback(isc_entropysource_t * source,unsigned int desired,isc_boolean_t blocking)483*00b67f09SDavid van Moolenbroek get_from_callback(isc_entropysource_t *source, unsigned int desired,
484*00b67f09SDavid van Moolenbroek isc_boolean_t blocking)
485*00b67f09SDavid van Moolenbroek {
486*00b67f09SDavid van Moolenbroek isc_entropy_t *ent = source->ent;
487*00b67f09SDavid van Moolenbroek isc_cbsource_t *cbs = &source->sources.callback;
488*00b67f09SDavid van Moolenbroek unsigned int added;
489*00b67f09SDavid van Moolenbroek unsigned int got;
490*00b67f09SDavid van Moolenbroek isc_result_t result;
491*00b67f09SDavid van Moolenbroek
492*00b67f09SDavid van Moolenbroek if (desired == 0)
493*00b67f09SDavid van Moolenbroek return (0);
494*00b67f09SDavid van Moolenbroek
495*00b67f09SDavid van Moolenbroek if (source->bad)
496*00b67f09SDavid van Moolenbroek return (0);
497*00b67f09SDavid van Moolenbroek
498*00b67f09SDavid van Moolenbroek if (!cbs->start_called && cbs->startfunc != NULL) {
499*00b67f09SDavid van Moolenbroek result = cbs->startfunc(source, cbs->arg, blocking);
500*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
501*00b67f09SDavid van Moolenbroek return (0);
502*00b67f09SDavid van Moolenbroek cbs->start_called = ISC_TRUE;
503*00b67f09SDavid van Moolenbroek }
504*00b67f09SDavid van Moolenbroek
505*00b67f09SDavid van Moolenbroek added = 0;
506*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
507*00b67f09SDavid van Moolenbroek while (desired > 0 && result == ISC_R_SUCCESS) {
508*00b67f09SDavid van Moolenbroek result = cbs->getfunc(source, cbs->arg, blocking);
509*00b67f09SDavid van Moolenbroek if (result == ISC_R_QUEUEFULL) {
510*00b67f09SDavid van Moolenbroek got = crunchsamples(ent, &cbs->samplequeue);
511*00b67f09SDavid van Moolenbroek added += got;
512*00b67f09SDavid van Moolenbroek desired -= ISC_MIN(got, desired);
513*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
514*00b67f09SDavid van Moolenbroek } else if (result != ISC_R_SUCCESS &&
515*00b67f09SDavid van Moolenbroek result != ISC_R_NOTBLOCKING)
516*00b67f09SDavid van Moolenbroek source->bad = ISC_TRUE;
517*00b67f09SDavid van Moolenbroek
518*00b67f09SDavid van Moolenbroek }
519*00b67f09SDavid van Moolenbroek
520*00b67f09SDavid van Moolenbroek return (added);
521*00b67f09SDavid van Moolenbroek }
522*00b67f09SDavid van Moolenbroek
523*00b67f09SDavid van Moolenbroek /*
524*00b67f09SDavid van Moolenbroek * Extract some number of bytes from the random pool, decreasing the
525*00b67f09SDavid van Moolenbroek * estimate of randomness as each byte is extracted.
526*00b67f09SDavid van Moolenbroek *
527*00b67f09SDavid van Moolenbroek * Do this by stiring the pool and returning a part of hash as randomness.
528*00b67f09SDavid van Moolenbroek * Note that no secrets are given away here since parts of the hash are
529*00b67f09SDavid van Moolenbroek * xored together before returned.
530*00b67f09SDavid van Moolenbroek *
531*00b67f09SDavid van Moolenbroek * Honor the request from the caller to only return good data, any data,
532*00b67f09SDavid van Moolenbroek * etc.
533*00b67f09SDavid van Moolenbroek */
534*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_getdata(isc_entropy_t * ent,void * data,unsigned int length,unsigned int * returned,unsigned int flags)535*00b67f09SDavid van Moolenbroek isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
536*00b67f09SDavid van Moolenbroek unsigned int *returned, unsigned int flags)
537*00b67f09SDavid van Moolenbroek {
538*00b67f09SDavid van Moolenbroek unsigned int i;
539*00b67f09SDavid van Moolenbroek isc_sha1_t hash;
540*00b67f09SDavid van Moolenbroek unsigned char digest[ISC_SHA1_DIGESTLENGTH];
541*00b67f09SDavid van Moolenbroek isc_uint32_t remain, deltae, count, total;
542*00b67f09SDavid van Moolenbroek isc_uint8_t *buf;
543*00b67f09SDavid van Moolenbroek isc_boolean_t goodonly, partial, blocking;
544*00b67f09SDavid van Moolenbroek
545*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
546*00b67f09SDavid van Moolenbroek REQUIRE(data != NULL);
547*00b67f09SDavid van Moolenbroek REQUIRE(length > 0);
548*00b67f09SDavid van Moolenbroek
549*00b67f09SDavid van Moolenbroek goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
550*00b67f09SDavid van Moolenbroek partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
551*00b67f09SDavid van Moolenbroek blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
552*00b67f09SDavid van Moolenbroek
553*00b67f09SDavid van Moolenbroek REQUIRE(!partial || returned != NULL);
554*00b67f09SDavid van Moolenbroek
555*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
556*00b67f09SDavid van Moolenbroek
557*00b67f09SDavid van Moolenbroek remain = length;
558*00b67f09SDavid van Moolenbroek buf = data;
559*00b67f09SDavid van Moolenbroek total = 0;
560*00b67f09SDavid van Moolenbroek while (remain != 0) {
561*00b67f09SDavid van Moolenbroek count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
562*00b67f09SDavid van Moolenbroek
563*00b67f09SDavid van Moolenbroek /*
564*00b67f09SDavid van Moolenbroek * If we are extracting good data only, make certain we
565*00b67f09SDavid van Moolenbroek * have enough data in our pool for this pass. If we don't,
566*00b67f09SDavid van Moolenbroek * get some, and fail if we can't, and partial returns
567*00b67f09SDavid van Moolenbroek * are not ok.
568*00b67f09SDavid van Moolenbroek */
569*00b67f09SDavid van Moolenbroek if (goodonly) {
570*00b67f09SDavid van Moolenbroek unsigned int fillcount;
571*00b67f09SDavid van Moolenbroek
572*00b67f09SDavid van Moolenbroek fillcount = ISC_MAX(remain * 8, count * 8);
573*00b67f09SDavid van Moolenbroek
574*00b67f09SDavid van Moolenbroek /*
575*00b67f09SDavid van Moolenbroek * If, however, we have at least THRESHOLD_BITS
576*00b67f09SDavid van Moolenbroek * of entropy in the pool, don't block here. It is
577*00b67f09SDavid van Moolenbroek * better to drain the pool once in a while and
578*00b67f09SDavid van Moolenbroek * then refill it than it is to constantly keep the
579*00b67f09SDavid van Moolenbroek * pool full.
580*00b67f09SDavid van Moolenbroek */
581*00b67f09SDavid van Moolenbroek if (ent->pool.entropy >= THRESHOLD_BITS)
582*00b67f09SDavid van Moolenbroek fillpool(ent, fillcount, ISC_FALSE);
583*00b67f09SDavid van Moolenbroek else
584*00b67f09SDavid van Moolenbroek fillpool(ent, fillcount, blocking);
585*00b67f09SDavid van Moolenbroek
586*00b67f09SDavid van Moolenbroek /*
587*00b67f09SDavid van Moolenbroek * Verify that we got enough entropy to do one
588*00b67f09SDavid van Moolenbroek * extraction. If we didn't, bail.
589*00b67f09SDavid van Moolenbroek */
590*00b67f09SDavid van Moolenbroek if (ent->pool.entropy < THRESHOLD_BITS) {
591*00b67f09SDavid van Moolenbroek if (!partial)
592*00b67f09SDavid van Moolenbroek goto zeroize;
593*00b67f09SDavid van Moolenbroek else
594*00b67f09SDavid van Moolenbroek goto partial_output;
595*00b67f09SDavid van Moolenbroek }
596*00b67f09SDavid van Moolenbroek } else {
597*00b67f09SDavid van Moolenbroek /*
598*00b67f09SDavid van Moolenbroek * If we've extracted half our pool size in bits
599*00b67f09SDavid van Moolenbroek * since the last refresh, try to refresh here.
600*00b67f09SDavid van Moolenbroek */
601*00b67f09SDavid van Moolenbroek if (ent->initialized < THRESHOLD_BITS)
602*00b67f09SDavid van Moolenbroek fillpool(ent, THRESHOLD_BITS, blocking);
603*00b67f09SDavid van Moolenbroek else
604*00b67f09SDavid van Moolenbroek fillpool(ent, 0, ISC_FALSE);
605*00b67f09SDavid van Moolenbroek
606*00b67f09SDavid van Moolenbroek /*
607*00b67f09SDavid van Moolenbroek * If we've not initialized with enough good random
608*00b67f09SDavid van Moolenbroek * data, seed with our crappy code.
609*00b67f09SDavid van Moolenbroek */
610*00b67f09SDavid van Moolenbroek if (ent->initialized < THRESHOLD_BITS)
611*00b67f09SDavid van Moolenbroek reseed(ent);
612*00b67f09SDavid van Moolenbroek }
613*00b67f09SDavid van Moolenbroek
614*00b67f09SDavid van Moolenbroek isc_sha1_init(&hash);
615*00b67f09SDavid van Moolenbroek isc_sha1_update(&hash, (void *)(ent->pool.pool),
616*00b67f09SDavid van Moolenbroek RND_POOLBYTES);
617*00b67f09SDavid van Moolenbroek isc_sha1_final(&hash, digest);
618*00b67f09SDavid van Moolenbroek
619*00b67f09SDavid van Moolenbroek /*
620*00b67f09SDavid van Moolenbroek * Stir the extracted data (all of it) back into the pool.
621*00b67f09SDavid van Moolenbroek */
622*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
623*00b67f09SDavid van Moolenbroek
624*00b67f09SDavid van Moolenbroek for (i = 0; i < count; i++)
625*00b67f09SDavid van Moolenbroek buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
626*00b67f09SDavid van Moolenbroek
627*00b67f09SDavid van Moolenbroek buf += count;
628*00b67f09SDavid van Moolenbroek remain -= count;
629*00b67f09SDavid van Moolenbroek
630*00b67f09SDavid van Moolenbroek deltae = count * 8;
631*00b67f09SDavid van Moolenbroek deltae = ISC_MIN(deltae, ent->pool.entropy);
632*00b67f09SDavid van Moolenbroek total += deltae;
633*00b67f09SDavid van Moolenbroek subtract_entropy(ent, deltae);
634*00b67f09SDavid van Moolenbroek add_pseudo(ent, count * 8);
635*00b67f09SDavid van Moolenbroek }
636*00b67f09SDavid van Moolenbroek
637*00b67f09SDavid van Moolenbroek partial_output:
638*00b67f09SDavid van Moolenbroek memset(digest, 0, sizeof(digest));
639*00b67f09SDavid van Moolenbroek
640*00b67f09SDavid van Moolenbroek if (returned != NULL)
641*00b67f09SDavid van Moolenbroek *returned = (length - remain);
642*00b67f09SDavid van Moolenbroek
643*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
644*00b67f09SDavid van Moolenbroek
645*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
646*00b67f09SDavid van Moolenbroek
647*00b67f09SDavid van Moolenbroek zeroize:
648*00b67f09SDavid van Moolenbroek /* put the entropy we almost extracted back */
649*00b67f09SDavid van Moolenbroek add_entropy(ent, total);
650*00b67f09SDavid van Moolenbroek memset(data, 0, length);
651*00b67f09SDavid van Moolenbroek memset(digest, 0, sizeof(digest));
652*00b67f09SDavid van Moolenbroek if (returned != NULL)
653*00b67f09SDavid van Moolenbroek *returned = 0;
654*00b67f09SDavid van Moolenbroek
655*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
656*00b67f09SDavid van Moolenbroek
657*00b67f09SDavid van Moolenbroek return (ISC_R_NOENTROPY);
658*00b67f09SDavid van Moolenbroek }
659*00b67f09SDavid van Moolenbroek
660*00b67f09SDavid van Moolenbroek static void
isc_entropypool_init(isc_entropypool_t * pool)661*00b67f09SDavid van Moolenbroek isc_entropypool_init(isc_entropypool_t *pool) {
662*00b67f09SDavid van Moolenbroek pool->cursor = RND_POOLWORDS - 1;
663*00b67f09SDavid van Moolenbroek pool->entropy = 0;
664*00b67f09SDavid van Moolenbroek pool->pseudo = 0;
665*00b67f09SDavid van Moolenbroek pool->rotate = 0;
666*00b67f09SDavid van Moolenbroek memset(pool->pool, 0, RND_POOLBYTES);
667*00b67f09SDavid van Moolenbroek }
668*00b67f09SDavid van Moolenbroek
669*00b67f09SDavid van Moolenbroek static void
isc_entropypool_invalidate(isc_entropypool_t * pool)670*00b67f09SDavid van Moolenbroek isc_entropypool_invalidate(isc_entropypool_t *pool) {
671*00b67f09SDavid van Moolenbroek pool->cursor = 0;
672*00b67f09SDavid van Moolenbroek pool->entropy = 0;
673*00b67f09SDavid van Moolenbroek pool->pseudo = 0;
674*00b67f09SDavid van Moolenbroek pool->rotate = 0;
675*00b67f09SDavid van Moolenbroek memset(pool->pool, 0, RND_POOLBYTES);
676*00b67f09SDavid van Moolenbroek }
677*00b67f09SDavid van Moolenbroek
678*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_create(isc_mem_t * mctx,isc_entropy_t ** entp)679*00b67f09SDavid van Moolenbroek isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
680*00b67f09SDavid van Moolenbroek isc_result_t result;
681*00b67f09SDavid van Moolenbroek isc_entropy_t *ent;
682*00b67f09SDavid van Moolenbroek
683*00b67f09SDavid van Moolenbroek REQUIRE(mctx != NULL);
684*00b67f09SDavid van Moolenbroek REQUIRE(entp != NULL && *entp == NULL);
685*00b67f09SDavid van Moolenbroek
686*00b67f09SDavid van Moolenbroek ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
687*00b67f09SDavid van Moolenbroek if (ent == NULL)
688*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
689*00b67f09SDavid van Moolenbroek
690*00b67f09SDavid van Moolenbroek /*
691*00b67f09SDavid van Moolenbroek * We need a lock.
692*00b67f09SDavid van Moolenbroek */
693*00b67f09SDavid van Moolenbroek result = isc_mutex_init(&ent->lock);
694*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
695*00b67f09SDavid van Moolenbroek goto errout;
696*00b67f09SDavid van Moolenbroek
697*00b67f09SDavid van Moolenbroek /*
698*00b67f09SDavid van Moolenbroek * From here down, no failures will/can occur.
699*00b67f09SDavid van Moolenbroek */
700*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(ent->sources);
701*00b67f09SDavid van Moolenbroek ent->nextsource = NULL;
702*00b67f09SDavid van Moolenbroek ent->nsources = 0;
703*00b67f09SDavid van Moolenbroek ent->mctx = NULL;
704*00b67f09SDavid van Moolenbroek isc_mem_attach(mctx, &ent->mctx);
705*00b67f09SDavid van Moolenbroek ent->refcnt = 1;
706*00b67f09SDavid van Moolenbroek ent->initialized = 0;
707*00b67f09SDavid van Moolenbroek ent->initcount = 0;
708*00b67f09SDavid van Moolenbroek ent->magic = ENTROPY_MAGIC;
709*00b67f09SDavid van Moolenbroek
710*00b67f09SDavid van Moolenbroek isc_entropypool_init(&ent->pool);
711*00b67f09SDavid van Moolenbroek
712*00b67f09SDavid van Moolenbroek *entp = ent;
713*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
714*00b67f09SDavid van Moolenbroek
715*00b67f09SDavid van Moolenbroek errout:
716*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
717*00b67f09SDavid van Moolenbroek
718*00b67f09SDavid van Moolenbroek return (result);
719*00b67f09SDavid van Moolenbroek }
720*00b67f09SDavid van Moolenbroek
721*00b67f09SDavid van Moolenbroek /*!
722*00b67f09SDavid van Moolenbroek * Requires "ent" be locked.
723*00b67f09SDavid van Moolenbroek */
724*00b67f09SDavid van Moolenbroek static void
destroysource(isc_entropysource_t ** sourcep)725*00b67f09SDavid van Moolenbroek destroysource(isc_entropysource_t **sourcep) {
726*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
727*00b67f09SDavid van Moolenbroek isc_entropy_t *ent;
728*00b67f09SDavid van Moolenbroek isc_cbsource_t *cbs;
729*00b67f09SDavid van Moolenbroek
730*00b67f09SDavid van Moolenbroek source = *sourcep;
731*00b67f09SDavid van Moolenbroek *sourcep = NULL;
732*00b67f09SDavid van Moolenbroek ent = source->ent;
733*00b67f09SDavid van Moolenbroek
734*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(ent->sources, source, link);
735*00b67f09SDavid van Moolenbroek ent->nextsource = NULL;
736*00b67f09SDavid van Moolenbroek REQUIRE(ent->nsources > 0);
737*00b67f09SDavid van Moolenbroek ent->nsources--;
738*00b67f09SDavid van Moolenbroek
739*00b67f09SDavid van Moolenbroek switch (source->type) {
740*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_FILE:
741*00b67f09SDavid van Moolenbroek if (! source->bad)
742*00b67f09SDavid van Moolenbroek destroyfilesource(&source->sources.file);
743*00b67f09SDavid van Moolenbroek break;
744*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_USOCKET:
745*00b67f09SDavid van Moolenbroek if (! source->bad)
746*00b67f09SDavid van Moolenbroek destroyusocketsource(&source->sources.usocket);
747*00b67f09SDavid van Moolenbroek break;
748*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_SAMPLE:
749*00b67f09SDavid van Moolenbroek samplequeue_release(ent, &source->sources.sample.samplequeue);
750*00b67f09SDavid van Moolenbroek break;
751*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_CALLBACK:
752*00b67f09SDavid van Moolenbroek cbs = &source->sources.callback;
753*00b67f09SDavid van Moolenbroek if (cbs->start_called && cbs->stopfunc != NULL) {
754*00b67f09SDavid van Moolenbroek cbs->stopfunc(source, cbs->arg);
755*00b67f09SDavid van Moolenbroek cbs->start_called = ISC_FALSE;
756*00b67f09SDavid van Moolenbroek }
757*00b67f09SDavid van Moolenbroek samplequeue_release(ent, &cbs->samplequeue);
758*00b67f09SDavid van Moolenbroek break;
759*00b67f09SDavid van Moolenbroek }
760*00b67f09SDavid van Moolenbroek
761*00b67f09SDavid van Moolenbroek memset(source, 0, sizeof(isc_entropysource_t));
762*00b67f09SDavid van Moolenbroek
763*00b67f09SDavid van Moolenbroek isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
764*00b67f09SDavid van Moolenbroek }
765*00b67f09SDavid van Moolenbroek
766*00b67f09SDavid van Moolenbroek static inline isc_boolean_t
destroy_check(isc_entropy_t * ent)767*00b67f09SDavid van Moolenbroek destroy_check(isc_entropy_t *ent) {
768*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
769*00b67f09SDavid van Moolenbroek
770*00b67f09SDavid van Moolenbroek if (ent->refcnt > 0)
771*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
772*00b67f09SDavid van Moolenbroek
773*00b67f09SDavid van Moolenbroek source = ISC_LIST_HEAD(ent->sources);
774*00b67f09SDavid van Moolenbroek while (source != NULL) {
775*00b67f09SDavid van Moolenbroek switch (source->type) {
776*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_FILE:
777*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_USOCKET:
778*00b67f09SDavid van Moolenbroek break;
779*00b67f09SDavid van Moolenbroek default:
780*00b67f09SDavid van Moolenbroek return (ISC_FALSE);
781*00b67f09SDavid van Moolenbroek }
782*00b67f09SDavid van Moolenbroek source = ISC_LIST_NEXT(source, link);
783*00b67f09SDavid van Moolenbroek }
784*00b67f09SDavid van Moolenbroek
785*00b67f09SDavid van Moolenbroek return (ISC_TRUE);
786*00b67f09SDavid van Moolenbroek }
787*00b67f09SDavid van Moolenbroek
788*00b67f09SDavid van Moolenbroek static void
destroy(isc_entropy_t ** entp)789*00b67f09SDavid van Moolenbroek destroy(isc_entropy_t **entp) {
790*00b67f09SDavid van Moolenbroek isc_entropy_t *ent;
791*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
792*00b67f09SDavid van Moolenbroek isc_mem_t *mctx;
793*00b67f09SDavid van Moolenbroek
794*00b67f09SDavid van Moolenbroek REQUIRE(entp != NULL && *entp != NULL);
795*00b67f09SDavid van Moolenbroek ent = *entp;
796*00b67f09SDavid van Moolenbroek *entp = NULL;
797*00b67f09SDavid van Moolenbroek
798*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
799*00b67f09SDavid van Moolenbroek
800*00b67f09SDavid van Moolenbroek REQUIRE(ent->refcnt == 0);
801*00b67f09SDavid van Moolenbroek
802*00b67f09SDavid van Moolenbroek /*
803*00b67f09SDavid van Moolenbroek * Here, detach non-sample sources.
804*00b67f09SDavid van Moolenbroek */
805*00b67f09SDavid van Moolenbroek source = ISC_LIST_HEAD(ent->sources);
806*00b67f09SDavid van Moolenbroek while (source != NULL) {
807*00b67f09SDavid van Moolenbroek switch(source->type) {
808*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_FILE:
809*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_USOCKET:
810*00b67f09SDavid van Moolenbroek destroysource(&source);
811*00b67f09SDavid van Moolenbroek break;
812*00b67f09SDavid van Moolenbroek }
813*00b67f09SDavid van Moolenbroek source = ISC_LIST_HEAD(ent->sources);
814*00b67f09SDavid van Moolenbroek }
815*00b67f09SDavid van Moolenbroek
816*00b67f09SDavid van Moolenbroek /*
817*00b67f09SDavid van Moolenbroek * If there are other types of sources, we've found a bug.
818*00b67f09SDavid van Moolenbroek */
819*00b67f09SDavid van Moolenbroek REQUIRE(ISC_LIST_EMPTY(ent->sources));
820*00b67f09SDavid van Moolenbroek
821*00b67f09SDavid van Moolenbroek mctx = ent->mctx;
822*00b67f09SDavid van Moolenbroek
823*00b67f09SDavid van Moolenbroek isc_entropypool_invalidate(&ent->pool);
824*00b67f09SDavid van Moolenbroek
825*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
826*00b67f09SDavid van Moolenbroek
827*00b67f09SDavid van Moolenbroek DESTROYLOCK(&ent->lock);
828*00b67f09SDavid van Moolenbroek
829*00b67f09SDavid van Moolenbroek memset(ent, 0, sizeof(isc_entropy_t));
830*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
831*00b67f09SDavid van Moolenbroek isc_mem_detach(&mctx);
832*00b67f09SDavid van Moolenbroek }
833*00b67f09SDavid van Moolenbroek
834*00b67f09SDavid van Moolenbroek void
isc_entropy_destroysource(isc_entropysource_t ** sourcep)835*00b67f09SDavid van Moolenbroek isc_entropy_destroysource(isc_entropysource_t **sourcep) {
836*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
837*00b67f09SDavid van Moolenbroek isc_entropy_t *ent;
838*00b67f09SDavid van Moolenbroek isc_boolean_t killit;
839*00b67f09SDavid van Moolenbroek
840*00b67f09SDavid van Moolenbroek REQUIRE(sourcep != NULL);
841*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SOURCE(*sourcep));
842*00b67f09SDavid van Moolenbroek
843*00b67f09SDavid van Moolenbroek source = *sourcep;
844*00b67f09SDavid van Moolenbroek *sourcep = NULL;
845*00b67f09SDavid van Moolenbroek
846*00b67f09SDavid van Moolenbroek ent = source->ent;
847*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
848*00b67f09SDavid van Moolenbroek
849*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
850*00b67f09SDavid van Moolenbroek
851*00b67f09SDavid van Moolenbroek destroysource(&source);
852*00b67f09SDavid van Moolenbroek
853*00b67f09SDavid van Moolenbroek killit = destroy_check(ent);
854*00b67f09SDavid van Moolenbroek
855*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
856*00b67f09SDavid van Moolenbroek
857*00b67f09SDavid van Moolenbroek if (killit)
858*00b67f09SDavid van Moolenbroek destroy(&ent);
859*00b67f09SDavid van Moolenbroek }
860*00b67f09SDavid van Moolenbroek
861*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_createcallbacksource(isc_entropy_t * ent,isc_entropystart_t start,isc_entropyget_t get,isc_entropystop_t stop,void * arg,isc_entropysource_t ** sourcep)862*00b67f09SDavid van Moolenbroek isc_entropy_createcallbacksource(isc_entropy_t *ent,
863*00b67f09SDavid van Moolenbroek isc_entropystart_t start,
864*00b67f09SDavid van Moolenbroek isc_entropyget_t get,
865*00b67f09SDavid van Moolenbroek isc_entropystop_t stop,
866*00b67f09SDavid van Moolenbroek void *arg,
867*00b67f09SDavid van Moolenbroek isc_entropysource_t **sourcep)
868*00b67f09SDavid van Moolenbroek {
869*00b67f09SDavid van Moolenbroek isc_result_t result;
870*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
871*00b67f09SDavid van Moolenbroek isc_cbsource_t *cbs;
872*00b67f09SDavid van Moolenbroek
873*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
874*00b67f09SDavid van Moolenbroek REQUIRE(get != NULL);
875*00b67f09SDavid van Moolenbroek REQUIRE(sourcep != NULL && *sourcep == NULL);
876*00b67f09SDavid van Moolenbroek
877*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
878*00b67f09SDavid van Moolenbroek
879*00b67f09SDavid van Moolenbroek source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
880*00b67f09SDavid van Moolenbroek if (source == NULL) {
881*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
882*00b67f09SDavid van Moolenbroek goto errout;
883*00b67f09SDavid van Moolenbroek }
884*00b67f09SDavid van Moolenbroek source->bad = ISC_FALSE;
885*00b67f09SDavid van Moolenbroek
886*00b67f09SDavid van Moolenbroek cbs = &source->sources.callback;
887*00b67f09SDavid van Moolenbroek
888*00b67f09SDavid van Moolenbroek result = samplesource_allocate(ent, &cbs->samplequeue);
889*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
890*00b67f09SDavid van Moolenbroek goto errout;
891*00b67f09SDavid van Moolenbroek
892*00b67f09SDavid van Moolenbroek cbs->start_called = ISC_FALSE;
893*00b67f09SDavid van Moolenbroek cbs->startfunc = start;
894*00b67f09SDavid van Moolenbroek cbs->getfunc = get;
895*00b67f09SDavid van Moolenbroek cbs->stopfunc = stop;
896*00b67f09SDavid van Moolenbroek cbs->arg = arg;
897*00b67f09SDavid van Moolenbroek
898*00b67f09SDavid van Moolenbroek /*
899*00b67f09SDavid van Moolenbroek * From here down, no failures can occur.
900*00b67f09SDavid van Moolenbroek */
901*00b67f09SDavid van Moolenbroek source->magic = SOURCE_MAGIC;
902*00b67f09SDavid van Moolenbroek source->type = ENTROPY_SOURCETYPE_CALLBACK;
903*00b67f09SDavid van Moolenbroek source->ent = ent;
904*00b67f09SDavid van Moolenbroek source->total = 0;
905*00b67f09SDavid van Moolenbroek memset(source->name, 0, sizeof(source->name));
906*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(source, link);
907*00b67f09SDavid van Moolenbroek
908*00b67f09SDavid van Moolenbroek /*
909*00b67f09SDavid van Moolenbroek * Hook it into the entropy system.
910*00b67f09SDavid van Moolenbroek */
911*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(ent->sources, source, link);
912*00b67f09SDavid van Moolenbroek ent->nsources++;
913*00b67f09SDavid van Moolenbroek
914*00b67f09SDavid van Moolenbroek *sourcep = source;
915*00b67f09SDavid van Moolenbroek
916*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
917*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
918*00b67f09SDavid van Moolenbroek
919*00b67f09SDavid van Moolenbroek errout:
920*00b67f09SDavid van Moolenbroek if (source != NULL)
921*00b67f09SDavid van Moolenbroek isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
922*00b67f09SDavid van Moolenbroek
923*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
924*00b67f09SDavid van Moolenbroek
925*00b67f09SDavid van Moolenbroek return (result);
926*00b67f09SDavid van Moolenbroek }
927*00b67f09SDavid van Moolenbroek
928*00b67f09SDavid van Moolenbroek void
isc_entropy_stopcallbacksources(isc_entropy_t * ent)929*00b67f09SDavid van Moolenbroek isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
930*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
931*00b67f09SDavid van Moolenbroek isc_cbsource_t *cbs;
932*00b67f09SDavid van Moolenbroek
933*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
934*00b67f09SDavid van Moolenbroek
935*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
936*00b67f09SDavid van Moolenbroek
937*00b67f09SDavid van Moolenbroek source = ISC_LIST_HEAD(ent->sources);
938*00b67f09SDavid van Moolenbroek while (source != NULL) {
939*00b67f09SDavid van Moolenbroek if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
940*00b67f09SDavid van Moolenbroek cbs = &source->sources.callback;
941*00b67f09SDavid van Moolenbroek if (cbs->start_called && cbs->stopfunc != NULL) {
942*00b67f09SDavid van Moolenbroek cbs->stopfunc(source, cbs->arg);
943*00b67f09SDavid van Moolenbroek cbs->start_called = ISC_FALSE;
944*00b67f09SDavid van Moolenbroek }
945*00b67f09SDavid van Moolenbroek }
946*00b67f09SDavid van Moolenbroek
947*00b67f09SDavid van Moolenbroek source = ISC_LIST_NEXT(source, link);
948*00b67f09SDavid van Moolenbroek }
949*00b67f09SDavid van Moolenbroek
950*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
951*00b67f09SDavid van Moolenbroek }
952*00b67f09SDavid van Moolenbroek
953*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_createsamplesource(isc_entropy_t * ent,isc_entropysource_t ** sourcep)954*00b67f09SDavid van Moolenbroek isc_entropy_createsamplesource(isc_entropy_t *ent,
955*00b67f09SDavid van Moolenbroek isc_entropysource_t **sourcep)
956*00b67f09SDavid van Moolenbroek {
957*00b67f09SDavid van Moolenbroek isc_result_t result;
958*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
959*00b67f09SDavid van Moolenbroek sample_queue_t *sq;
960*00b67f09SDavid van Moolenbroek
961*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
962*00b67f09SDavid van Moolenbroek REQUIRE(sourcep != NULL && *sourcep == NULL);
963*00b67f09SDavid van Moolenbroek
964*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
965*00b67f09SDavid van Moolenbroek
966*00b67f09SDavid van Moolenbroek source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
967*00b67f09SDavid van Moolenbroek if (source == NULL) {
968*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
969*00b67f09SDavid van Moolenbroek goto errout;
970*00b67f09SDavid van Moolenbroek }
971*00b67f09SDavid van Moolenbroek
972*00b67f09SDavid van Moolenbroek sq = &source->sources.sample.samplequeue;
973*00b67f09SDavid van Moolenbroek result = samplesource_allocate(ent, sq);
974*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
975*00b67f09SDavid van Moolenbroek goto errout;
976*00b67f09SDavid van Moolenbroek
977*00b67f09SDavid van Moolenbroek /*
978*00b67f09SDavid van Moolenbroek * From here down, no failures can occur.
979*00b67f09SDavid van Moolenbroek */
980*00b67f09SDavid van Moolenbroek source->magic = SOURCE_MAGIC;
981*00b67f09SDavid van Moolenbroek source->type = ENTROPY_SOURCETYPE_SAMPLE;
982*00b67f09SDavid van Moolenbroek source->ent = ent;
983*00b67f09SDavid van Moolenbroek source->total = 0;
984*00b67f09SDavid van Moolenbroek memset(source->name, 0, sizeof(source->name));
985*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(source, link);
986*00b67f09SDavid van Moolenbroek
987*00b67f09SDavid van Moolenbroek /*
988*00b67f09SDavid van Moolenbroek * Hook it into the entropy system.
989*00b67f09SDavid van Moolenbroek */
990*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(ent->sources, source, link);
991*00b67f09SDavid van Moolenbroek ent->nsources++;
992*00b67f09SDavid van Moolenbroek
993*00b67f09SDavid van Moolenbroek *sourcep = source;
994*00b67f09SDavid van Moolenbroek
995*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
996*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
997*00b67f09SDavid van Moolenbroek
998*00b67f09SDavid van Moolenbroek errout:
999*00b67f09SDavid van Moolenbroek if (source != NULL)
1000*00b67f09SDavid van Moolenbroek isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
1001*00b67f09SDavid van Moolenbroek
1002*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
1003*00b67f09SDavid van Moolenbroek
1004*00b67f09SDavid van Moolenbroek return (result);
1005*00b67f09SDavid van Moolenbroek }
1006*00b67f09SDavid van Moolenbroek
1007*00b67f09SDavid van Moolenbroek /*!
1008*00b67f09SDavid van Moolenbroek * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1009*00b67f09SDavid van Moolenbroek * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1010*00b67f09SDavid van Moolenbroek * queue was full when this function was called.
1011*00b67f09SDavid van Moolenbroek */
1012*00b67f09SDavid van Moolenbroek static isc_result_t
addsample(sample_queue_t * sq,isc_uint32_t sample,isc_uint32_t extra)1013*00b67f09SDavid van Moolenbroek addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
1014*00b67f09SDavid van Moolenbroek if (sq->nsamples >= RND_EVENTQSIZE)
1015*00b67f09SDavid van Moolenbroek return (ISC_R_NOMORE);
1016*00b67f09SDavid van Moolenbroek
1017*00b67f09SDavid van Moolenbroek sq->samples[sq->nsamples] = sample;
1018*00b67f09SDavid van Moolenbroek sq->extra[sq->nsamples] = extra;
1019*00b67f09SDavid van Moolenbroek sq->nsamples++;
1020*00b67f09SDavid van Moolenbroek
1021*00b67f09SDavid van Moolenbroek if (sq->nsamples >= RND_EVENTQSIZE)
1022*00b67f09SDavid van Moolenbroek return (ISC_R_QUEUEFULL);
1023*00b67f09SDavid van Moolenbroek
1024*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1025*00b67f09SDavid van Moolenbroek }
1026*00b67f09SDavid van Moolenbroek
1027*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_addsample(isc_entropysource_t * source,isc_uint32_t sample,isc_uint32_t extra)1028*00b67f09SDavid van Moolenbroek isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
1029*00b67f09SDavid van Moolenbroek isc_uint32_t extra)
1030*00b67f09SDavid van Moolenbroek {
1031*00b67f09SDavid van Moolenbroek isc_entropy_t *ent;
1032*00b67f09SDavid van Moolenbroek sample_queue_t *sq;
1033*00b67f09SDavid van Moolenbroek unsigned int entropy;
1034*00b67f09SDavid van Moolenbroek isc_result_t result;
1035*00b67f09SDavid van Moolenbroek
1036*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SOURCE(source));
1037*00b67f09SDavid van Moolenbroek
1038*00b67f09SDavid van Moolenbroek ent = source->ent;
1039*00b67f09SDavid van Moolenbroek
1040*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
1041*00b67f09SDavid van Moolenbroek
1042*00b67f09SDavid van Moolenbroek sq = &source->sources.sample.samplequeue;
1043*00b67f09SDavid van Moolenbroek result = addsample(sq, sample, extra);
1044*00b67f09SDavid van Moolenbroek if (result == ISC_R_QUEUEFULL) {
1045*00b67f09SDavid van Moolenbroek entropy = crunchsamples(ent, sq);
1046*00b67f09SDavid van Moolenbroek add_entropy(ent, entropy);
1047*00b67f09SDavid van Moolenbroek }
1048*00b67f09SDavid van Moolenbroek
1049*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
1050*00b67f09SDavid van Moolenbroek
1051*00b67f09SDavid van Moolenbroek return (result);
1052*00b67f09SDavid van Moolenbroek }
1053*00b67f09SDavid van Moolenbroek
1054*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_addcallbacksample(isc_entropysource_t * source,isc_uint32_t sample,isc_uint32_t extra)1055*00b67f09SDavid van Moolenbroek isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
1056*00b67f09SDavid van Moolenbroek isc_uint32_t extra)
1057*00b67f09SDavid van Moolenbroek {
1058*00b67f09SDavid van Moolenbroek sample_queue_t *sq;
1059*00b67f09SDavid van Moolenbroek isc_result_t result;
1060*00b67f09SDavid van Moolenbroek
1061*00b67f09SDavid van Moolenbroek REQUIRE(VALID_SOURCE(source));
1062*00b67f09SDavid van Moolenbroek REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
1063*00b67f09SDavid van Moolenbroek
1064*00b67f09SDavid van Moolenbroek sq = &source->sources.callback.samplequeue;
1065*00b67f09SDavid van Moolenbroek result = addsample(sq, sample, extra);
1066*00b67f09SDavid van Moolenbroek
1067*00b67f09SDavid van Moolenbroek return (result);
1068*00b67f09SDavid van Moolenbroek }
1069*00b67f09SDavid van Moolenbroek
1070*00b67f09SDavid van Moolenbroek void
isc_entropy_putdata(isc_entropy_t * ent,void * data,unsigned int length,isc_uint32_t entropy)1071*00b67f09SDavid van Moolenbroek isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
1072*00b67f09SDavid van Moolenbroek isc_uint32_t entropy)
1073*00b67f09SDavid van Moolenbroek {
1074*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
1075*00b67f09SDavid van Moolenbroek
1076*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
1077*00b67f09SDavid van Moolenbroek
1078*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, data, length, entropy);
1079*00b67f09SDavid van Moolenbroek
1080*00b67f09SDavid van Moolenbroek if (ent->initialized < THRESHOLD_BITS)
1081*00b67f09SDavid van Moolenbroek ent->initialized = THRESHOLD_BITS;
1082*00b67f09SDavid van Moolenbroek
1083*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
1084*00b67f09SDavid van Moolenbroek }
1085*00b67f09SDavid van Moolenbroek
1086*00b67f09SDavid van Moolenbroek static void
dumpstats(isc_entropy_t * ent,FILE * out)1087*00b67f09SDavid van Moolenbroek dumpstats(isc_entropy_t *ent, FILE *out) {
1088*00b67f09SDavid van Moolenbroek fprintf(out,
1089*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
1090*00b67f09SDavid van Moolenbroek ISC_MSG_ENTROPYSTATS,
1091*00b67f09SDavid van Moolenbroek "Entropy pool %p: refcnt %u cursor %u,"
1092*00b67f09SDavid van Moolenbroek " rotate %u entropy %u pseudo %u nsources %u"
1093*00b67f09SDavid van Moolenbroek " nextsource %p initialized %u initcount %u\n"),
1094*00b67f09SDavid van Moolenbroek ent, ent->refcnt,
1095*00b67f09SDavid van Moolenbroek ent->pool.cursor, ent->pool.rotate,
1096*00b67f09SDavid van Moolenbroek ent->pool.entropy, ent->pool.pseudo,
1097*00b67f09SDavid van Moolenbroek ent->nsources, ent->nextsource, ent->initialized,
1098*00b67f09SDavid van Moolenbroek ent->initcount);
1099*00b67f09SDavid van Moolenbroek }
1100*00b67f09SDavid van Moolenbroek
1101*00b67f09SDavid van Moolenbroek /*
1102*00b67f09SDavid van Moolenbroek * This function ignores locking. Use at your own risk.
1103*00b67f09SDavid van Moolenbroek */
1104*00b67f09SDavid van Moolenbroek void
isc_entropy_stats(isc_entropy_t * ent,FILE * out)1105*00b67f09SDavid van Moolenbroek isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
1106*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
1107*00b67f09SDavid van Moolenbroek
1108*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
1109*00b67f09SDavid van Moolenbroek dumpstats(ent, out);
1110*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
1111*00b67f09SDavid van Moolenbroek }
1112*00b67f09SDavid van Moolenbroek
1113*00b67f09SDavid van Moolenbroek unsigned int
isc_entropy_status(isc_entropy_t * ent)1114*00b67f09SDavid van Moolenbroek isc_entropy_status(isc_entropy_t *ent) {
1115*00b67f09SDavid van Moolenbroek unsigned int estimate;
1116*00b67f09SDavid van Moolenbroek
1117*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
1118*00b67f09SDavid van Moolenbroek estimate = ent->pool.entropy;
1119*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
1120*00b67f09SDavid van Moolenbroek
1121*00b67f09SDavid van Moolenbroek return estimate;
1122*00b67f09SDavid van Moolenbroek }
1123*00b67f09SDavid van Moolenbroek
1124*00b67f09SDavid van Moolenbroek void
isc_entropy_attach(isc_entropy_t * ent,isc_entropy_t ** entp)1125*00b67f09SDavid van Moolenbroek isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
1126*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
1127*00b67f09SDavid van Moolenbroek REQUIRE(entp != NULL && *entp == NULL);
1128*00b67f09SDavid van Moolenbroek
1129*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
1130*00b67f09SDavid van Moolenbroek
1131*00b67f09SDavid van Moolenbroek ent->refcnt++;
1132*00b67f09SDavid van Moolenbroek *entp = ent;
1133*00b67f09SDavid van Moolenbroek
1134*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
1135*00b67f09SDavid van Moolenbroek }
1136*00b67f09SDavid van Moolenbroek
1137*00b67f09SDavid van Moolenbroek void
isc_entropy_detach(isc_entropy_t ** entp)1138*00b67f09SDavid van Moolenbroek isc_entropy_detach(isc_entropy_t **entp) {
1139*00b67f09SDavid van Moolenbroek isc_entropy_t *ent;
1140*00b67f09SDavid van Moolenbroek isc_boolean_t killit;
1141*00b67f09SDavid van Moolenbroek
1142*00b67f09SDavid van Moolenbroek REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
1143*00b67f09SDavid van Moolenbroek ent = *entp;
1144*00b67f09SDavid van Moolenbroek *entp = NULL;
1145*00b67f09SDavid van Moolenbroek
1146*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
1147*00b67f09SDavid van Moolenbroek
1148*00b67f09SDavid van Moolenbroek REQUIRE(ent->refcnt > 0);
1149*00b67f09SDavid van Moolenbroek ent->refcnt--;
1150*00b67f09SDavid van Moolenbroek
1151*00b67f09SDavid van Moolenbroek killit = destroy_check(ent);
1152*00b67f09SDavid van Moolenbroek
1153*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
1154*00b67f09SDavid van Moolenbroek
1155*00b67f09SDavid van Moolenbroek if (killit)
1156*00b67f09SDavid van Moolenbroek destroy(&ent);
1157*00b67f09SDavid van Moolenbroek }
1158*00b67f09SDavid van Moolenbroek
1159*00b67f09SDavid van Moolenbroek static isc_result_t
kbdstart(isc_entropysource_t * source,void * arg,isc_boolean_t blocking)1160*00b67f09SDavid van Moolenbroek kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1161*00b67f09SDavid van Moolenbroek /*
1162*00b67f09SDavid van Moolenbroek * The intent of "first" is to provide a warning message only once
1163*00b67f09SDavid van Moolenbroek * during the run of a program that might try to gather keyboard
1164*00b67f09SDavid van Moolenbroek * entropy multiple times.
1165*00b67f09SDavid van Moolenbroek */
1166*00b67f09SDavid van Moolenbroek static isc_boolean_t first = ISC_TRUE;
1167*00b67f09SDavid van Moolenbroek
1168*00b67f09SDavid van Moolenbroek UNUSED(arg);
1169*00b67f09SDavid van Moolenbroek
1170*00b67f09SDavid van Moolenbroek if (! blocking)
1171*00b67f09SDavid van Moolenbroek return (ISC_R_NOENTROPY);
1172*00b67f09SDavid van Moolenbroek
1173*00b67f09SDavid van Moolenbroek if (first) {
1174*00b67f09SDavid van Moolenbroek if (source->warn_keyboard)
1175*00b67f09SDavid van Moolenbroek fprintf(stderr, "You must use the keyboard to create "
1176*00b67f09SDavid van Moolenbroek "entropy, since your system is lacking\n"
1177*00b67f09SDavid van Moolenbroek "/dev/random (or equivalent)\n\n");
1178*00b67f09SDavid van Moolenbroek first = ISC_FALSE;
1179*00b67f09SDavid van Moolenbroek }
1180*00b67f09SDavid van Moolenbroek fprintf(stderr, "start typing:\n");
1181*00b67f09SDavid van Moolenbroek
1182*00b67f09SDavid van Moolenbroek return (isc_keyboard_open(&source->kbd));
1183*00b67f09SDavid van Moolenbroek }
1184*00b67f09SDavid van Moolenbroek
1185*00b67f09SDavid van Moolenbroek static void
kbdstop(isc_entropysource_t * source,void * arg)1186*00b67f09SDavid van Moolenbroek kbdstop(isc_entropysource_t *source, void *arg) {
1187*00b67f09SDavid van Moolenbroek
1188*00b67f09SDavid van Moolenbroek UNUSED(arg);
1189*00b67f09SDavid van Moolenbroek
1190*00b67f09SDavid van Moolenbroek if (! isc_keyboard_canceled(&source->kbd))
1191*00b67f09SDavid van Moolenbroek fprintf(stderr, "stop typing.\r\n");
1192*00b67f09SDavid van Moolenbroek
1193*00b67f09SDavid van Moolenbroek (void)isc_keyboard_close(&source->kbd, 3);
1194*00b67f09SDavid van Moolenbroek }
1195*00b67f09SDavid van Moolenbroek
1196*00b67f09SDavid van Moolenbroek static isc_result_t
kbdget(isc_entropysource_t * source,void * arg,isc_boolean_t blocking)1197*00b67f09SDavid van Moolenbroek kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1198*00b67f09SDavid van Moolenbroek isc_result_t result;
1199*00b67f09SDavid van Moolenbroek isc_time_t t;
1200*00b67f09SDavid van Moolenbroek isc_uint32_t sample;
1201*00b67f09SDavid van Moolenbroek isc_uint32_t extra;
1202*00b67f09SDavid van Moolenbroek unsigned char c;
1203*00b67f09SDavid van Moolenbroek
1204*00b67f09SDavid van Moolenbroek UNUSED(arg);
1205*00b67f09SDavid van Moolenbroek
1206*00b67f09SDavid van Moolenbroek if (!blocking)
1207*00b67f09SDavid van Moolenbroek return (ISC_R_NOTBLOCKING);
1208*00b67f09SDavid van Moolenbroek
1209*00b67f09SDavid van Moolenbroek result = isc_keyboard_getchar(&source->kbd, &c);
1210*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
1211*00b67f09SDavid van Moolenbroek return (result);
1212*00b67f09SDavid van Moolenbroek
1213*00b67f09SDavid van Moolenbroek TIME_NOW(&t);
1214*00b67f09SDavid van Moolenbroek
1215*00b67f09SDavid van Moolenbroek sample = isc_time_nanoseconds(&t);
1216*00b67f09SDavid van Moolenbroek extra = c;
1217*00b67f09SDavid van Moolenbroek
1218*00b67f09SDavid van Moolenbroek result = isc_entropy_addcallbacksample(source, sample, extra);
1219*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
1220*00b67f09SDavid van Moolenbroek fprintf(stderr, "\r\n");
1221*00b67f09SDavid van Moolenbroek return (result);
1222*00b67f09SDavid van Moolenbroek }
1223*00b67f09SDavid van Moolenbroek
1224*00b67f09SDavid van Moolenbroek fprintf(stderr, ".");
1225*00b67f09SDavid van Moolenbroek fflush(stderr);
1226*00b67f09SDavid van Moolenbroek
1227*00b67f09SDavid van Moolenbroek return (result);
1228*00b67f09SDavid van Moolenbroek }
1229*00b67f09SDavid van Moolenbroek
1230*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_usebestsource(isc_entropy_t * ectx,isc_entropysource_t ** source,const char * randomfile,int use_keyboard)1231*00b67f09SDavid van Moolenbroek isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
1232*00b67f09SDavid van Moolenbroek const char *randomfile, int use_keyboard)
1233*00b67f09SDavid van Moolenbroek {
1234*00b67f09SDavid van Moolenbroek isc_result_t result;
1235*00b67f09SDavid van Moolenbroek isc_result_t final_result = ISC_R_NOENTROPY;
1236*00b67f09SDavid van Moolenbroek isc_boolean_t userfile = ISC_TRUE;
1237*00b67f09SDavid van Moolenbroek
1238*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ectx));
1239*00b67f09SDavid van Moolenbroek REQUIRE(source != NULL && *source == NULL);
1240*00b67f09SDavid van Moolenbroek REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
1241*00b67f09SDavid van Moolenbroek use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
1242*00b67f09SDavid van Moolenbroek use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
1243*00b67f09SDavid van Moolenbroek
1244*00b67f09SDavid van Moolenbroek #ifdef PKCS11CRYPTO
1245*00b67f09SDavid van Moolenbroek if (randomfile != NULL)
1246*00b67f09SDavid van Moolenbroek pk11_rand_seed_fromfile(randomfile);
1247*00b67f09SDavid van Moolenbroek #endif
1248*00b67f09SDavid van Moolenbroek
1249*00b67f09SDavid van Moolenbroek #ifdef PATH_RANDOMDEV
1250*00b67f09SDavid van Moolenbroek if (randomfile == NULL) {
1251*00b67f09SDavid van Moolenbroek randomfile = PATH_RANDOMDEV;
1252*00b67f09SDavid van Moolenbroek userfile = ISC_FALSE;
1253*00b67f09SDavid van Moolenbroek }
1254*00b67f09SDavid van Moolenbroek #endif
1255*00b67f09SDavid van Moolenbroek
1256*00b67f09SDavid van Moolenbroek if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
1257*00b67f09SDavid van Moolenbroek result = isc_entropy_createfilesource(ectx, randomfile);
1258*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS &&
1259*00b67f09SDavid van Moolenbroek use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
1260*00b67f09SDavid van Moolenbroek use_keyboard = ISC_ENTROPY_KEYBOARDNO;
1261*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS && userfile)
1262*00b67f09SDavid van Moolenbroek return (result);
1263*00b67f09SDavid van Moolenbroek
1264*00b67f09SDavid van Moolenbroek final_result = result;
1265*00b67f09SDavid van Moolenbroek }
1266*00b67f09SDavid van Moolenbroek
1267*00b67f09SDavid van Moolenbroek if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
1268*00b67f09SDavid van Moolenbroek result = isc_entropy_createcallbacksource(ectx, kbdstart,
1269*00b67f09SDavid van Moolenbroek kbdget, kbdstop,
1270*00b67f09SDavid van Moolenbroek NULL, source);
1271*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
1272*00b67f09SDavid van Moolenbroek (*source)->warn_keyboard =
1273*00b67f09SDavid van Moolenbroek ISC_TF(use_keyboard ==
1274*00b67f09SDavid van Moolenbroek ISC_ENTROPY_KEYBOARDMAYBE);
1275*00b67f09SDavid van Moolenbroek
1276*00b67f09SDavid van Moolenbroek if (final_result != ISC_R_SUCCESS)
1277*00b67f09SDavid van Moolenbroek final_result = result;
1278*00b67f09SDavid van Moolenbroek }
1279*00b67f09SDavid van Moolenbroek
1280*00b67f09SDavid van Moolenbroek /*
1281*00b67f09SDavid van Moolenbroek * final_result is ISC_R_SUCCESS if at least one source of entropy
1282*00b67f09SDavid van Moolenbroek * could be started, otherwise it is the error from the most recently
1283*00b67f09SDavid van Moolenbroek * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1284*00b67f09SDavid van Moolenbroek * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1285*00b67f09SDavid van Moolenbroek */
1286*00b67f09SDavid van Moolenbroek return (final_result);
1287*00b67f09SDavid van Moolenbroek }
1288