1135446Strhodes/*
2218384Sdougb * Copyright (C) 2004-2007, 2009, 2010  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2000-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: entropy.c,v 1.22 2010/08/10 23:48:19 tbox Exp $ */
19135446Strhodes
20170222Sdougb/*! \file
21170222Sdougb * \brief
22135446Strhodes * This is the system independent part of the entropy module.  It is
23135446Strhodes * compiled via inclusion from the relevant OS source file, ie,
24170222Sdougb * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
25170222Sdougb *
26170222Sdougb * \author Much of this code is modeled after the NetBSD /dev/random implementation,
27170222Sdougb * written by Michael Graff <explorer@netbsd.org>.
28135446Strhodes */
29135446Strhodes
30135446Strhodes#include <errno.h>
31135446Strhodes#include <fcntl.h>
32135446Strhodes#include <stdio.h>
33135446Strhodes
34135446Strhodes#include <isc/buffer.h>
35135446Strhodes#include <isc/entropy.h>
36135446Strhodes#include <isc/keyboard.h>
37135446Strhodes#include <isc/list.h>
38135446Strhodes#include <isc/magic.h>
39135446Strhodes#include <isc/mem.h>
40135446Strhodes#include <isc/msgs.h>
41135446Strhodes#include <isc/mutex.h>
42135446Strhodes#include <isc/platform.h>
43135446Strhodes#include <isc/region.h>
44135446Strhodes#include <isc/sha1.h>
45135446Strhodes#include <isc/string.h>
46135446Strhodes#include <isc/time.h>
47135446Strhodes#include <isc/util.h>
48135446Strhodes
49135446Strhodes
50135446Strhodes#define ENTROPY_MAGIC		ISC_MAGIC('E', 'n', 't', 'e')
51135446Strhodes#define SOURCE_MAGIC		ISC_MAGIC('E', 'n', 't', 's')
52135446Strhodes
53135446Strhodes#define VALID_ENTROPY(e)	ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
54135446Strhodes#define VALID_SOURCE(s)		ISC_MAGIC_VALID(s, SOURCE_MAGIC)
55135446Strhodes
56135446Strhodes/***
57135446Strhodes *** "constants."  Do not change these unless you _really_ know what
58135446Strhodes *** you are doing.
59135446Strhodes ***/
60135446Strhodes
61170222Sdougb/*%
62170222Sdougb * Size of entropy pool in 32-bit words.  This _MUST_ be a power of 2.
63135446Strhodes */
64135446Strhodes#define RND_POOLWORDS	128
65170222Sdougb/*% Pool in bytes. */
66135446Strhodes#define RND_POOLBYTES	(RND_POOLWORDS * 4)
67170222Sdougb/*% Pool in bits. */
68135446Strhodes#define RND_POOLBITS	(RND_POOLWORDS * 32)
69135446Strhodes
70170222Sdougb/*%
71135446Strhodes * Number of bytes returned per hash.  This must be true:
72135446Strhodes *	threshold * 2 <= digest_size_in_bytes
73135446Strhodes */
74135446Strhodes#define RND_ENTROPY_THRESHOLD	10
75135446Strhodes#define THRESHOLD_BITS		(RND_ENTROPY_THRESHOLD * 8)
76135446Strhodes
77170222Sdougb/*%
78135446Strhodes * Size of the input event queue in samples.
79135446Strhodes */
80135446Strhodes#define RND_EVENTQSIZE	32
81135446Strhodes
82170222Sdougb/*%
83135446Strhodes * The number of times we'll "reseed" for pseudorandom seeds.  This is an
84135446Strhodes * extremely weak pseudorandom seed.  If the caller is using lots of
85135446Strhodes * pseudorandom data and they cannot provide a stronger random source,
86135446Strhodes * there is little we can do other than hope they're smart enough to
87135446Strhodes * call _adddata() with something better than we can come up with.
88135446Strhodes */
89135446Strhodes#define RND_INITIALIZE	128
90135446Strhodes
91170222Sdougb/*% Entropy Pool */
92135446Strhodestypedef struct {
93170222Sdougb	isc_uint32_t	cursor;		/*%< current add point in the pool */
94170222Sdougb	isc_uint32_t	entropy;	/*%< current entropy estimate in bits */
95170222Sdougb	isc_uint32_t	pseudo;		/*%< bits extracted in pseudorandom */
96170222Sdougb	isc_uint32_t	rotate;		/*%< how many bits to rotate by */
97170222Sdougb	isc_uint32_t	pool[RND_POOLWORDS];	/*%< random pool data */
98135446Strhodes} isc_entropypool_t;
99135446Strhodes
100135446Strhodesstruct isc_entropy {
101135446Strhodes	unsigned int			magic;
102135446Strhodes	isc_mem_t		       *mctx;
103135446Strhodes	isc_mutex_t			lock;
104135446Strhodes	unsigned int			refcnt;
105135446Strhodes	isc_uint32_t			initialized;
106135446Strhodes	isc_uint32_t			initcount;
107135446Strhodes	isc_entropypool_t		pool;
108135446Strhodes	unsigned int			nsources;
109135446Strhodes	isc_entropysource_t	       *nextsource;
110135446Strhodes	ISC_LIST(isc_entropysource_t)	sources;
111135446Strhodes};
112135446Strhodes
113170222Sdougb/*% Sample Queue */
114135446Strhodestypedef struct {
115170222Sdougb	isc_uint32_t	last_time;	/*%< last time recorded */
116170222Sdougb	isc_uint32_t	last_delta;	/*%< last delta value */
117170222Sdougb	isc_uint32_t	last_delta2;	/*%< last delta2 value */
118170222Sdougb	isc_uint32_t	nsamples;	/*%< number of samples filled in */
119170222Sdougb	isc_uint32_t   *samples;	/*%< the samples */
120170222Sdougb	isc_uint32_t   *extra;		/*%< extra samples added in */
121135446Strhodes} sample_queue_t;
122135446Strhodes
123135446Strhodestypedef struct {
124135446Strhodes	sample_queue_t	samplequeue;
125135446Strhodes} isc_entropysamplesource_t;
126135446Strhodes
127135446Strhodestypedef struct {
128135446Strhodes	isc_boolean_t		start_called;
129135446Strhodes	isc_entropystart_t	startfunc;
130135446Strhodes	isc_entropyget_t	getfunc;
131135446Strhodes	isc_entropystop_t	stopfunc;
132135446Strhodes	void		       *arg;
133135446Strhodes	sample_queue_t		samplequeue;
134135446Strhodes} isc_cbsource_t;
135135446Strhodes
136135446Strhodestypedef struct {
137135446Strhodes	FILESOURCE_HANDLE_TYPE handle;
138135446Strhodes} isc_entropyfilesource_t;
139135446Strhodes
140135446Strhodesstruct isc_entropysource {
141135446Strhodes	unsigned int	magic;
142135446Strhodes	unsigned int	type;
143135446Strhodes	isc_entropy_t  *ent;
144170222Sdougb	isc_uint32_t	total;		/*%< entropy from this source */
145135446Strhodes	ISC_LINK(isc_entropysource_t)	link;
146135446Strhodes	char		name[32];
147135446Strhodes	isc_boolean_t	bad;
148135446Strhodes	isc_boolean_t	warn_keyboard;
149135446Strhodes	isc_keyboard_t	kbd;
150135446Strhodes	union {
151135446Strhodes		isc_entropysamplesource_t	sample;
152135446Strhodes		isc_entropyfilesource_t		file;
153135446Strhodes		isc_cbsource_t			callback;
154135446Strhodes		isc_entropyusocketsource_t	usocket;
155135446Strhodes	} sources;
156135446Strhodes};
157135446Strhodes
158170222Sdougb#define ENTROPY_SOURCETYPE_SAMPLE	1	/*%< Type is a sample source */
159170222Sdougb#define ENTROPY_SOURCETYPE_FILE		2	/*%< Type is a file source */
160170222Sdougb#define ENTROPY_SOURCETYPE_CALLBACK	3	/*%< Type is a callback source */
161170222Sdougb#define ENTROPY_SOURCETYPE_USOCKET	4	/*%< Type is a Unix socket source */
162135446Strhodes
163170222Sdougb/*@{*/
164170222Sdougb/*%
165135446Strhodes * The random pool "taps"
166135446Strhodes */
167135446Strhodes#define TAP1	99
168135446Strhodes#define TAP2	59
169135446Strhodes#define TAP3	31
170135446Strhodes#define TAP4	 9
171135446Strhodes#define TAP5	 7
172170222Sdougb/*@}*/
173135446Strhodes
174170222Sdougb/*@{*/
175170222Sdougb/*%
176135446Strhodes * Declarations for function provided by the system dependent sources that
177135446Strhodes * include this file.
178135446Strhodes */
179135446Strhodesstatic void
180135446Strhodesfillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
181135446Strhodes
182135446Strhodesstatic int
183135446Strhodeswait_for_sources(isc_entropy_t *);
184135446Strhodes
185135446Strhodesstatic void
186135446Strhodesdestroyfilesource(isc_entropyfilesource_t *source);
187135446Strhodes
188135446Strhodesstatic void
189135446Strhodesdestroyusocketsource(isc_entropyusocketsource_t *source);
190135446Strhodes
191170222Sdougb/*@}*/
192135446Strhodes
193135446Strhodesstatic void
194135446Strhodessamplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
195135446Strhodes	REQUIRE(sq->samples != NULL);
196135446Strhodes	REQUIRE(sq->extra != NULL);
197135446Strhodes
198135446Strhodes	isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
199135446Strhodes	isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
200135446Strhodes	sq->samples = NULL;
201135446Strhodes	sq->extra = NULL;
202135446Strhodes}
203135446Strhodes
204135446Strhodesstatic isc_result_t
205135446Strhodessamplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
206135446Strhodes	sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
207135446Strhodes	if (sq->samples == NULL)
208135446Strhodes		return (ISC_R_NOMEMORY);
209135446Strhodes
210135446Strhodes	sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
211135446Strhodes	if (sq->extra == NULL) {
212135446Strhodes		isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
213135446Strhodes		sq->samples = NULL;
214135446Strhodes		return (ISC_R_NOMEMORY);
215135446Strhodes	}
216135446Strhodes
217135446Strhodes	sq->nsamples = 0;
218135446Strhodes
219135446Strhodes	return (ISC_R_SUCCESS);
220135446Strhodes}
221135446Strhodes
222170222Sdougb/*%
223135446Strhodes * Add in entropy, even when the value we're adding in could be
224135446Strhodes * very large.
225135446Strhodes */
226135446Strhodesstatic inline void
227135446Strhodesadd_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
228135446Strhodes	/* clamp input.  Yes, this must be done. */
229135446Strhodes	entropy = ISC_MIN(entropy, RND_POOLBITS);
230135446Strhodes	/* Add in the entropy we already have. */
231135446Strhodes	entropy += ent->pool.entropy;
232135446Strhodes	/* Clamp. */
233135446Strhodes	ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
234135446Strhodes}
235135446Strhodes
236170222Sdougb/*%
237135446Strhodes * Decrement the amount of entropy the pool has.
238135446Strhodes */
239135446Strhodesstatic inline void
240135446Strhodessubtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
241135446Strhodes	entropy = ISC_MIN(entropy, ent->pool.entropy);
242135446Strhodes	ent->pool.entropy -= entropy;
243135446Strhodes}
244135446Strhodes
245170222Sdougb/*!
246135446Strhodes * Add in entropy, even when the value we're adding in could be
247135446Strhodes * very large.
248135446Strhodes */
249135446Strhodesstatic inline void
250135446Strhodesadd_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
251135446Strhodes	/* clamp input.  Yes, this must be done. */
252135446Strhodes	pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
253135446Strhodes	/* Add in the pseudo we already have. */
254135446Strhodes	pseudo += ent->pool.pseudo;
255135446Strhodes	/* Clamp. */
256135446Strhodes	ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
257135446Strhodes}
258135446Strhodes
259170222Sdougb/*!
260135446Strhodes * Decrement the amount of pseudo the pool has.
261135446Strhodes */
262135446Strhodesstatic inline void
263135446Strhodessubtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
264135446Strhodes	pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
265135446Strhodes	ent->pool.pseudo -= pseudo;
266135446Strhodes}
267135446Strhodes
268170222Sdougb/*!
269135446Strhodes * Add one word to the pool, rotating the input as needed.
270135446Strhodes */
271135446Strhodesstatic inline void
272135446Strhodesentropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
273135446Strhodes	/*
274135446Strhodes	 * Steal some values out of the pool, and xor them into the
275135446Strhodes	 * word we were given.
276135446Strhodes	 *
277135446Strhodes	 * Mix the new value into the pool using xor.  This will
278135446Strhodes	 * prevent the actual values from being known to the caller
279135446Strhodes	 * since the previous values are assumed to be unknown as well.
280135446Strhodes	 */
281135446Strhodes	val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
282135446Strhodes	val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
283135446Strhodes	val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
284135446Strhodes	val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
285135446Strhodes	val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
286218384Sdougb	if (rp->rotate == 0)
287218384Sdougb		rp->pool[rp->cursor++] ^= val;
288218384Sdougb	else
289218384Sdougb		rp->pool[rp->cursor++] ^=
290218384Sdougb		  ((val << rp->rotate) | (val >> (32 - rp->rotate)));
291135446Strhodes
292135446Strhodes	/*
293135446Strhodes	 * If we have looped around the pool, increment the rotate
294135446Strhodes	 * variable so the next value will get xored in rotated to
295135446Strhodes	 * a different position.
296193149Sdougb	 * Increment by a value that is relatively prime to the word size
297135446Strhodes	 * to try to spread the bits throughout the pool quickly when the
298135446Strhodes	 * pool is empty.
299135446Strhodes	 */
300135446Strhodes	if (rp->cursor == RND_POOLWORDS) {
301135446Strhodes		rp->cursor = 0;
302135446Strhodes		rp->rotate = (rp->rotate + 7) & 31;
303135446Strhodes	}
304135446Strhodes}
305135446Strhodes
306170222Sdougb/*!
307135446Strhodes * Add a buffer's worth of data to the pool.
308135446Strhodes *
309135446Strhodes * Requires that the lock is held on the entropy pool.
310135446Strhodes */
311135446Strhodesstatic void
312135446Strhodesentropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
313135446Strhodes		    isc_uint32_t entropy)
314135446Strhodes{
315135446Strhodes	isc_uint32_t val;
316135446Strhodes	unsigned long addr;
317135446Strhodes	isc_uint8_t *buf;
318135446Strhodes
319135446Strhodes	addr = (unsigned long)p;
320135446Strhodes	buf = p;
321135446Strhodes
322135446Strhodes	if ((addr & 0x03U) != 0U) {
323135446Strhodes		val = 0;
324135446Strhodes		switch (len) {
325135446Strhodes		case 3:
326135446Strhodes			val = *buf++;
327135446Strhodes			len--;
328135446Strhodes		case 2:
329135446Strhodes			val = val << 8 | *buf++;
330135446Strhodes			len--;
331135446Strhodes		case 1:
332135446Strhodes			val = val << 8 | *buf++;
333135446Strhodes			len--;
334135446Strhodes		}
335135446Strhodes
336135446Strhodes		entropypool_add_word(&ent->pool, val);
337135446Strhodes	}
338135446Strhodes
339135446Strhodes	for (; len > 3; len -= 4) {
340135446Strhodes		val = *((isc_uint32_t *)buf);
341135446Strhodes
342135446Strhodes		entropypool_add_word(&ent->pool, val);
343135446Strhodes		buf += 4;
344135446Strhodes	}
345135446Strhodes
346135446Strhodes	if (len != 0) {
347135446Strhodes		val = 0;
348135446Strhodes		switch (len) {
349135446Strhodes		case 3:
350135446Strhodes			val = *buf++;
351135446Strhodes		case 2:
352135446Strhodes			val = val << 8 | *buf++;
353135446Strhodes		case 1:
354135446Strhodes			val = val << 8 | *buf++;
355135446Strhodes		}
356135446Strhodes
357135446Strhodes		entropypool_add_word(&ent->pool, val);
358135446Strhodes	}
359135446Strhodes
360135446Strhodes	add_entropy(ent, entropy);
361135446Strhodes	subtract_pseudo(ent, entropy);
362135446Strhodes}
363135446Strhodes
364135446Strhodesstatic inline void
365135446Strhodesreseed(isc_entropy_t *ent) {
366135446Strhodes	isc_time_t t;
367135446Strhodes	pid_t pid;
368135446Strhodes
369135446Strhodes	if (ent->initcount == 0) {
370135446Strhodes		pid = getpid();
371135446Strhodes		entropypool_adddata(ent, &pid, sizeof(pid), 0);
372135446Strhodes		pid = getppid();
373135446Strhodes		entropypool_adddata(ent, &pid, sizeof(pid), 0);
374135446Strhodes	}
375135446Strhodes
376170222Sdougb	/*!
377135446Strhodes	 * After we've reseeded 100 times, only add new timing info every
378135446Strhodes	 * 50 requests.  This will keep us from using lots and lots of
379135446Strhodes	 * CPU just to return bad pseudorandom data anyway.
380135446Strhodes	 */
381135446Strhodes	if (ent->initcount > 100)
382135446Strhodes		if ((ent->initcount % 50) != 0)
383135446Strhodes			return;
384135446Strhodes
385135446Strhodes	TIME_NOW(&t);
386135446Strhodes	entropypool_adddata(ent, &t, sizeof(t), 0);
387135446Strhodes	ent->initcount++;
388135446Strhodes}
389135446Strhodes
390135446Strhodesstatic inline unsigned int
391135446Strhodesestimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
392135446Strhodes	isc_int32_t		delta;
393135446Strhodes	isc_int32_t		delta2;
394135446Strhodes	isc_int32_t		delta3;
395135446Strhodes
396170222Sdougb	/*!
397135446Strhodes	 * If the time counter has overflowed, calculate the real difference.
398135446Strhodes	 * If it has not, it is simpler.
399135446Strhodes	 */
400135446Strhodes	if (t < sq->last_time)
401135446Strhodes		delta = UINT_MAX - sq->last_time + t;
402135446Strhodes	else
403135446Strhodes		delta = sq->last_time - t;
404135446Strhodes
405135446Strhodes	if (delta < 0)
406135446Strhodes		delta = -delta;
407135446Strhodes
408135446Strhodes	/*
409135446Strhodes	 * Calculate the second and third order differentials
410135446Strhodes	 */
411135446Strhodes	delta2 = sq->last_delta - delta;
412135446Strhodes	if (delta2 < 0)
413135446Strhodes		delta2 = -delta2;
414135446Strhodes
415135446Strhodes	delta3 = sq->last_delta2 - delta2;
416135446Strhodes	if (delta3 < 0)
417135446Strhodes		delta3 = -delta3;
418135446Strhodes
419135446Strhodes	sq->last_time = t;
420135446Strhodes	sq->last_delta = delta;
421135446Strhodes	sq->last_delta2 = delta2;
422135446Strhodes
423135446Strhodes	/*
424135446Strhodes	 * If any delta is 0, we got no entropy.  If all are non-zero, we
425135446Strhodes	 * might have something.
426135446Strhodes	 */
427135446Strhodes	if (delta == 0 || delta2 == 0 || delta3 == 0)
428135446Strhodes		return 0;
429135446Strhodes
430135446Strhodes	/*
431135446Strhodes	 * We could find the smallest delta and claim we got log2(delta)
432135446Strhodes	 * bits, but for now return that we found 1 bit.
433135446Strhodes	 */
434135446Strhodes	return 1;
435135446Strhodes}
436135446Strhodes
437135446Strhodesstatic unsigned int
438135446Strhodescrunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
439135446Strhodes	unsigned int ns;
440135446Strhodes	unsigned int added;
441135446Strhodes
442135446Strhodes	if (sq->nsamples < 6)
443135446Strhodes		return (0);
444135446Strhodes
445135446Strhodes	added = 0;
446135446Strhodes	sq->last_time = sq->samples[0];
447135446Strhodes	sq->last_delta = 0;
448135446Strhodes	sq->last_delta2 = 0;
449135446Strhodes
450135446Strhodes	/*
451135446Strhodes	 * Prime the values by adding in the first 4 samples in.  This
452135446Strhodes	 * should completely initialize the delta calculations.
453135446Strhodes	 */
454135446Strhodes	for (ns = 0; ns < 4; ns++)
455135446Strhodes		(void)estimate_entropy(sq, sq->samples[ns]);
456135446Strhodes
457135446Strhodes	for (ns = 4; ns < sq->nsamples; ns++)
458135446Strhodes		added += estimate_entropy(sq, sq->samples[ns]);
459135446Strhodes
460135446Strhodes	entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
461135446Strhodes	entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
462135446Strhodes
463135446Strhodes	/*
464135446Strhodes	 * Move the last 4 samples into the first 4 positions, and start
465135446Strhodes	 * adding new samples from that point.
466135446Strhodes	 */
467135446Strhodes	for (ns = 0; ns < 4; ns++) {
468135446Strhodes		sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
469135446Strhodes		sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
470135446Strhodes	}
471135446Strhodes
472135446Strhodes	sq->nsamples = 4;
473135446Strhodes
474135446Strhodes	return (added);
475135446Strhodes}
476135446Strhodes
477135446Strhodesstatic unsigned int
478135446Strhodesget_from_callback(isc_entropysource_t *source, unsigned int desired,
479135446Strhodes		  isc_boolean_t blocking)
480135446Strhodes{
481135446Strhodes	isc_entropy_t *ent = source->ent;
482135446Strhodes	isc_cbsource_t *cbs = &source->sources.callback;
483135446Strhodes	unsigned int added;
484135446Strhodes	unsigned int got;
485135446Strhodes	isc_result_t result;
486135446Strhodes
487135446Strhodes	if (desired == 0)
488135446Strhodes		return (0);
489135446Strhodes
490135446Strhodes	if (source->bad)
491135446Strhodes		return (0);
492135446Strhodes
493135446Strhodes	if (!cbs->start_called && cbs->startfunc != NULL) {
494135446Strhodes		result = cbs->startfunc(source, cbs->arg, blocking);
495135446Strhodes		if (result != ISC_R_SUCCESS)
496135446Strhodes			return (0);
497135446Strhodes		cbs->start_called = ISC_TRUE;
498135446Strhodes	}
499135446Strhodes
500135446Strhodes	added = 0;
501135446Strhodes	result = ISC_R_SUCCESS;
502135446Strhodes	while (desired > 0 && result == ISC_R_SUCCESS) {
503135446Strhodes		result = cbs->getfunc(source, cbs->arg, blocking);
504135446Strhodes		if (result == ISC_R_QUEUEFULL) {
505135446Strhodes			got = crunchsamples(ent, &cbs->samplequeue);
506135446Strhodes			added += got;
507135446Strhodes			desired -= ISC_MIN(got, desired);
508135446Strhodes			result = ISC_R_SUCCESS;
509135446Strhodes		} else if (result != ISC_R_SUCCESS &&
510135446Strhodes			   result != ISC_R_NOTBLOCKING)
511135446Strhodes			source->bad = ISC_TRUE;
512135446Strhodes
513135446Strhodes	}
514135446Strhodes
515135446Strhodes	return (added);
516135446Strhodes}
517135446Strhodes
518135446Strhodes/*
519135446Strhodes * Extract some number of bytes from the random pool, decreasing the
520135446Strhodes * estimate of randomness as each byte is extracted.
521135446Strhodes *
522135446Strhodes * Do this by stiring the pool and returning a part of hash as randomness.
523135446Strhodes * Note that no secrets are given away here since parts of the hash are
524135446Strhodes * xored together before returned.
525135446Strhodes *
526135446Strhodes * Honor the request from the caller to only return good data, any data,
527135446Strhodes * etc.
528135446Strhodes */
529135446Strhodesisc_result_t
530135446Strhodesisc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
531135446Strhodes		    unsigned int *returned, unsigned int flags)
532135446Strhodes{
533135446Strhodes	unsigned int i;
534135446Strhodes	isc_sha1_t hash;
535135446Strhodes	unsigned char digest[ISC_SHA1_DIGESTLENGTH];
536135446Strhodes	isc_uint32_t remain, deltae, count, total;
537135446Strhodes	isc_uint8_t *buf;
538135446Strhodes	isc_boolean_t goodonly, partial, blocking;
539135446Strhodes
540135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
541135446Strhodes	REQUIRE(data != NULL);
542135446Strhodes	REQUIRE(length > 0);
543135446Strhodes
544135446Strhodes	goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
545135446Strhodes	partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
546135446Strhodes	blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
547135446Strhodes
548135446Strhodes	REQUIRE(!partial || returned != NULL);
549135446Strhodes
550135446Strhodes	LOCK(&ent->lock);
551135446Strhodes
552135446Strhodes	remain = length;
553135446Strhodes	buf = data;
554135446Strhodes	total = 0;
555135446Strhodes	while (remain != 0) {
556135446Strhodes		count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
557135446Strhodes
558135446Strhodes		/*
559135446Strhodes		 * If we are extracting good data only, make certain we
560135446Strhodes		 * have enough data in our pool for this pass.  If we don't,
561135446Strhodes		 * get some, and fail if we can't, and partial returns
562135446Strhodes		 * are not ok.
563135446Strhodes		 */
564135446Strhodes		if (goodonly) {
565135446Strhodes			unsigned int fillcount;
566135446Strhodes
567135446Strhodes			fillcount = ISC_MAX(remain * 8, count * 8);
568135446Strhodes
569135446Strhodes			/*
570135446Strhodes			 * If, however, we have at least THRESHOLD_BITS
571135446Strhodes			 * of entropy in the pool, don't block here.  It is
572135446Strhodes			 * better to drain the pool once in a while and
573135446Strhodes			 * then refill it than it is to constantly keep the
574135446Strhodes			 * pool full.
575135446Strhodes			 */
576135446Strhodes			if (ent->pool.entropy >= THRESHOLD_BITS)
577135446Strhodes				fillpool(ent, fillcount, ISC_FALSE);
578135446Strhodes			else
579135446Strhodes				fillpool(ent, fillcount, blocking);
580135446Strhodes
581135446Strhodes			/*
582135446Strhodes			 * Verify that we got enough entropy to do one
583135446Strhodes			 * extraction.  If we didn't, bail.
584135446Strhodes			 */
585135446Strhodes			if (ent->pool.entropy < THRESHOLD_BITS) {
586135446Strhodes				if (!partial)
587135446Strhodes					goto zeroize;
588135446Strhodes				else
589135446Strhodes					goto partial_output;
590135446Strhodes			}
591135446Strhodes		} else {
592135446Strhodes			/*
593135446Strhodes			 * If we've extracted half our pool size in bits
594135446Strhodes			 * since the last refresh, try to refresh here.
595135446Strhodes			 */
596135446Strhodes			if (ent->initialized < THRESHOLD_BITS)
597135446Strhodes				fillpool(ent, THRESHOLD_BITS, blocking);
598135446Strhodes			else
599135446Strhodes				fillpool(ent, 0, ISC_FALSE);
600135446Strhodes
601135446Strhodes			/*
602135446Strhodes			 * If we've not initialized with enough good random
603135446Strhodes			 * data, seed with our crappy code.
604135446Strhodes			 */
605135446Strhodes			if (ent->initialized < THRESHOLD_BITS)
606135446Strhodes				reseed(ent);
607135446Strhodes		}
608135446Strhodes
609135446Strhodes		isc_sha1_init(&hash);
610135446Strhodes		isc_sha1_update(&hash, (void *)(ent->pool.pool),
611135446Strhodes				RND_POOLBYTES);
612135446Strhodes		isc_sha1_final(&hash, digest);
613135446Strhodes
614135446Strhodes		/*
615135446Strhodes		 * Stir the extracted data (all of it) back into the pool.
616135446Strhodes		 */
617135446Strhodes		entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
618135446Strhodes
619135446Strhodes		for (i = 0; i < count; i++)
620135446Strhodes			buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
621135446Strhodes
622135446Strhodes		buf += count;
623135446Strhodes		remain -= count;
624135446Strhodes
625135446Strhodes		deltae = count * 8;
626135446Strhodes		deltae = ISC_MIN(deltae, ent->pool.entropy);
627135446Strhodes		total += deltae;
628135446Strhodes		subtract_entropy(ent, deltae);
629135446Strhodes		add_pseudo(ent, count * 8);
630135446Strhodes	}
631135446Strhodes
632135446Strhodes partial_output:
633135446Strhodes	memset(digest, 0, sizeof(digest));
634135446Strhodes
635135446Strhodes	if (returned != NULL)
636135446Strhodes		*returned = (length - remain);
637135446Strhodes
638135446Strhodes	UNLOCK(&ent->lock);
639135446Strhodes
640135446Strhodes	return (ISC_R_SUCCESS);
641135446Strhodes
642135446Strhodes zeroize:
643135446Strhodes	/* put the entropy we almost extracted back */
644135446Strhodes	add_entropy(ent, total);
645135446Strhodes	memset(data, 0, length);
646135446Strhodes	memset(digest, 0, sizeof(digest));
647135446Strhodes	if (returned != NULL)
648135446Strhodes		*returned = 0;
649135446Strhodes
650135446Strhodes	UNLOCK(&ent->lock);
651135446Strhodes
652135446Strhodes	return (ISC_R_NOENTROPY);
653135446Strhodes}
654135446Strhodes
655135446Strhodesstatic void
656135446Strhodesisc_entropypool_init(isc_entropypool_t *pool) {
657135446Strhodes	pool->cursor = RND_POOLWORDS - 1;
658135446Strhodes	pool->entropy = 0;
659135446Strhodes	pool->pseudo = 0;
660135446Strhodes	pool->rotate = 0;
661135446Strhodes	memset(pool->pool, 0, RND_POOLBYTES);
662135446Strhodes}
663135446Strhodes
664135446Strhodesstatic void
665135446Strhodesisc_entropypool_invalidate(isc_entropypool_t *pool) {
666135446Strhodes	pool->cursor = 0;
667135446Strhodes	pool->entropy = 0;
668135446Strhodes	pool->pseudo = 0;
669135446Strhodes	pool->rotate = 0;
670135446Strhodes	memset(pool->pool, 0, RND_POOLBYTES);
671135446Strhodes}
672135446Strhodes
673135446Strhodesisc_result_t
674135446Strhodesisc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
675170222Sdougb	isc_result_t result;
676135446Strhodes	isc_entropy_t *ent;
677135446Strhodes
678135446Strhodes	REQUIRE(mctx != NULL);
679135446Strhodes	REQUIRE(entp != NULL && *entp == NULL);
680135446Strhodes
681135446Strhodes	ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
682135446Strhodes	if (ent == NULL)
683135446Strhodes		return (ISC_R_NOMEMORY);
684135446Strhodes
685135446Strhodes	/*
686135446Strhodes	 * We need a lock.
687135446Strhodes	 */
688170222Sdougb	result = isc_mutex_init(&ent->lock);
689170222Sdougb	if (result != ISC_R_SUCCESS)
690135446Strhodes		goto errout;
691135446Strhodes
692135446Strhodes	/*
693135446Strhodes	 * From here down, no failures will/can occur.
694135446Strhodes	 */
695135446Strhodes	ISC_LIST_INIT(ent->sources);
696135446Strhodes	ent->nextsource = NULL;
697135446Strhodes	ent->nsources = 0;
698135446Strhodes	ent->mctx = NULL;
699135446Strhodes	isc_mem_attach(mctx, &ent->mctx);
700135446Strhodes	ent->refcnt = 1;
701135446Strhodes	ent->initialized = 0;
702135446Strhodes	ent->initcount = 0;
703135446Strhodes	ent->magic = ENTROPY_MAGIC;
704135446Strhodes
705135446Strhodes	isc_entropypool_init(&ent->pool);
706135446Strhodes
707135446Strhodes	*entp = ent;
708135446Strhodes	return (ISC_R_SUCCESS);
709135446Strhodes
710135446Strhodes errout:
711135446Strhodes	isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
712135446Strhodes
713170222Sdougb	return (result);
714135446Strhodes}
715135446Strhodes
716170222Sdougb/*!
717135446Strhodes * Requires "ent" be locked.
718135446Strhodes */
719135446Strhodesstatic void
720135446Strhodesdestroysource(isc_entropysource_t **sourcep) {
721135446Strhodes	isc_entropysource_t *source;
722135446Strhodes	isc_entropy_t *ent;
723135446Strhodes	isc_cbsource_t *cbs;
724135446Strhodes
725135446Strhodes	source = *sourcep;
726135446Strhodes	*sourcep = NULL;
727135446Strhodes	ent = source->ent;
728135446Strhodes
729135446Strhodes	ISC_LIST_UNLINK(ent->sources, source, link);
730135446Strhodes	ent->nextsource = NULL;
731135446Strhodes	REQUIRE(ent->nsources > 0);
732135446Strhodes	ent->nsources--;
733135446Strhodes
734135446Strhodes	switch (source->type) {
735135446Strhodes	case ENTROPY_SOURCETYPE_FILE:
736135446Strhodes		if (! source->bad)
737135446Strhodes			destroyfilesource(&source->sources.file);
738135446Strhodes		break;
739135446Strhodes	case ENTROPY_SOURCETYPE_USOCKET:
740135446Strhodes		if (! source->bad)
741135446Strhodes			destroyusocketsource(&source->sources.usocket);
742135446Strhodes		break;
743135446Strhodes	case ENTROPY_SOURCETYPE_SAMPLE:
744135446Strhodes		samplequeue_release(ent, &source->sources.sample.samplequeue);
745135446Strhodes		break;
746135446Strhodes	case ENTROPY_SOURCETYPE_CALLBACK:
747135446Strhodes		cbs = &source->sources.callback;
748135446Strhodes		if (cbs->start_called && cbs->stopfunc != NULL) {
749135446Strhodes			cbs->stopfunc(source, cbs->arg);
750135446Strhodes			cbs->start_called = ISC_FALSE;
751135446Strhodes		}
752135446Strhodes		samplequeue_release(ent, &cbs->samplequeue);
753135446Strhodes		break;
754135446Strhodes	}
755135446Strhodes
756135446Strhodes	memset(source, 0, sizeof(isc_entropysource_t));
757135446Strhodes
758135446Strhodes	isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
759135446Strhodes}
760135446Strhodes
761135446Strhodesstatic inline isc_boolean_t
762135446Strhodesdestroy_check(isc_entropy_t *ent) {
763135446Strhodes	isc_entropysource_t *source;
764135446Strhodes
765135446Strhodes	if (ent->refcnt > 0)
766135446Strhodes		return (ISC_FALSE);
767135446Strhodes
768135446Strhodes	source = ISC_LIST_HEAD(ent->sources);
769135446Strhodes	while (source != NULL) {
770135446Strhodes		switch (source->type) {
771135446Strhodes		case ENTROPY_SOURCETYPE_FILE:
772135446Strhodes		case ENTROPY_SOURCETYPE_USOCKET:
773135446Strhodes			break;
774135446Strhodes		default:
775135446Strhodes			return (ISC_FALSE);
776135446Strhodes		}
777135446Strhodes		source = ISC_LIST_NEXT(source, link);
778135446Strhodes	}
779135446Strhodes
780135446Strhodes	return (ISC_TRUE);
781135446Strhodes}
782135446Strhodes
783135446Strhodesstatic void
784135446Strhodesdestroy(isc_entropy_t **entp) {
785135446Strhodes	isc_entropy_t *ent;
786135446Strhodes	isc_entropysource_t *source;
787135446Strhodes	isc_mem_t *mctx;
788135446Strhodes
789135446Strhodes	REQUIRE(entp != NULL && *entp != NULL);
790135446Strhodes	ent = *entp;
791135446Strhodes	*entp = NULL;
792135446Strhodes
793135446Strhodes	LOCK(&ent->lock);
794135446Strhodes
795135446Strhodes	REQUIRE(ent->refcnt == 0);
796135446Strhodes
797135446Strhodes	/*
798135446Strhodes	 * Here, detach non-sample sources.
799135446Strhodes	 */
800135446Strhodes	source = ISC_LIST_HEAD(ent->sources);
801135446Strhodes	while (source != NULL) {
802135446Strhodes		switch(source->type) {
803135446Strhodes		case ENTROPY_SOURCETYPE_FILE:
804135446Strhodes		case ENTROPY_SOURCETYPE_USOCKET:
805135446Strhodes			destroysource(&source);
806135446Strhodes			break;
807135446Strhodes		}
808135446Strhodes		source = ISC_LIST_HEAD(ent->sources);
809135446Strhodes	}
810135446Strhodes
811135446Strhodes	/*
812135446Strhodes	 * If there are other types of sources, we've found a bug.
813135446Strhodes	 */
814135446Strhodes	REQUIRE(ISC_LIST_EMPTY(ent->sources));
815135446Strhodes
816135446Strhodes	mctx = ent->mctx;
817135446Strhodes
818135446Strhodes	isc_entropypool_invalidate(&ent->pool);
819135446Strhodes
820135446Strhodes	UNLOCK(&ent->lock);
821135446Strhodes
822135446Strhodes	DESTROYLOCK(&ent->lock);
823135446Strhodes
824135446Strhodes	memset(ent, 0, sizeof(isc_entropy_t));
825135446Strhodes	isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
826135446Strhodes	isc_mem_detach(&mctx);
827135446Strhodes}
828135446Strhodes
829135446Strhodesvoid
830135446Strhodesisc_entropy_destroysource(isc_entropysource_t **sourcep) {
831135446Strhodes	isc_entropysource_t *source;
832135446Strhodes	isc_entropy_t *ent;
833135446Strhodes	isc_boolean_t killit;
834135446Strhodes
835135446Strhodes	REQUIRE(sourcep != NULL);
836135446Strhodes	REQUIRE(VALID_SOURCE(*sourcep));
837135446Strhodes
838135446Strhodes	source = *sourcep;
839135446Strhodes	*sourcep = NULL;
840135446Strhodes
841135446Strhodes	ent = source->ent;
842135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
843135446Strhodes
844135446Strhodes	LOCK(&ent->lock);
845135446Strhodes
846135446Strhodes	destroysource(&source);
847135446Strhodes
848135446Strhodes	killit = destroy_check(ent);
849135446Strhodes
850135446Strhodes	UNLOCK(&ent->lock);
851135446Strhodes
852135446Strhodes	if (killit)
853135446Strhodes		destroy(&ent);
854135446Strhodes}
855135446Strhodes
856135446Strhodesisc_result_t
857135446Strhodesisc_entropy_createcallbacksource(isc_entropy_t *ent,
858135446Strhodes				 isc_entropystart_t start,
859135446Strhodes				 isc_entropyget_t get,
860135446Strhodes				 isc_entropystop_t stop,
861135446Strhodes				 void *arg,
862135446Strhodes				 isc_entropysource_t **sourcep)
863135446Strhodes{
864170222Sdougb	isc_result_t result;
865135446Strhodes	isc_entropysource_t *source;
866135446Strhodes	isc_cbsource_t *cbs;
867135446Strhodes
868135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
869135446Strhodes	REQUIRE(get != NULL);
870135446Strhodes	REQUIRE(sourcep != NULL && *sourcep == NULL);
871135446Strhodes
872135446Strhodes	LOCK(&ent->lock);
873135446Strhodes
874135446Strhodes	source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
875135446Strhodes	if (source == NULL) {
876170222Sdougb		result = ISC_R_NOMEMORY;
877135446Strhodes		goto errout;
878135446Strhodes	}
879135446Strhodes	source->bad = ISC_FALSE;
880135446Strhodes
881135446Strhodes	cbs = &source->sources.callback;
882135446Strhodes
883170222Sdougb	result = samplesource_allocate(ent, &cbs->samplequeue);
884170222Sdougb	if (result != ISC_R_SUCCESS)
885135446Strhodes		goto errout;
886135446Strhodes
887135446Strhodes	cbs->start_called = ISC_FALSE;
888135446Strhodes	cbs->startfunc = start;
889135446Strhodes	cbs->getfunc = get;
890135446Strhodes	cbs->stopfunc = stop;
891135446Strhodes	cbs->arg = arg;
892135446Strhodes
893135446Strhodes	/*
894135446Strhodes	 * From here down, no failures can occur.
895135446Strhodes	 */
896135446Strhodes	source->magic = SOURCE_MAGIC;
897135446Strhodes	source->type = ENTROPY_SOURCETYPE_CALLBACK;
898135446Strhodes	source->ent = ent;
899135446Strhodes	source->total = 0;
900135446Strhodes	memset(source->name, 0, sizeof(source->name));
901135446Strhodes	ISC_LINK_INIT(source, link);
902135446Strhodes
903135446Strhodes	/*
904135446Strhodes	 * Hook it into the entropy system.
905135446Strhodes	 */
906135446Strhodes	ISC_LIST_APPEND(ent->sources, source, link);
907135446Strhodes	ent->nsources++;
908135446Strhodes
909135446Strhodes	*sourcep = source;
910135446Strhodes
911135446Strhodes	UNLOCK(&ent->lock);
912135446Strhodes	return (ISC_R_SUCCESS);
913135446Strhodes
914135446Strhodes errout:
915135446Strhodes	if (source != NULL)
916135446Strhodes		isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
917135446Strhodes
918135446Strhodes	UNLOCK(&ent->lock);
919135446Strhodes
920170222Sdougb	return (result);
921135446Strhodes}
922135446Strhodes
923135446Strhodesvoid
924135446Strhodesisc_entropy_stopcallbacksources(isc_entropy_t *ent) {
925135446Strhodes	isc_entropysource_t *source;
926135446Strhodes	isc_cbsource_t *cbs;
927135446Strhodes
928135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
929135446Strhodes
930135446Strhodes	LOCK(&ent->lock);
931135446Strhodes
932135446Strhodes	source = ISC_LIST_HEAD(ent->sources);
933135446Strhodes	while (source != NULL) {
934135446Strhodes		if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
935135446Strhodes			cbs = &source->sources.callback;
936135446Strhodes			if (cbs->start_called && cbs->stopfunc != NULL) {
937135446Strhodes				cbs->stopfunc(source, cbs->arg);
938135446Strhodes				cbs->start_called = ISC_FALSE;
939135446Strhodes			}
940135446Strhodes		}
941135446Strhodes
942135446Strhodes		source = ISC_LIST_NEXT(source, link);
943135446Strhodes	}
944135446Strhodes
945135446Strhodes	UNLOCK(&ent->lock);
946135446Strhodes}
947135446Strhodes
948135446Strhodesisc_result_t
949135446Strhodesisc_entropy_createsamplesource(isc_entropy_t *ent,
950135446Strhodes			       isc_entropysource_t **sourcep)
951135446Strhodes{
952170222Sdougb	isc_result_t result;
953135446Strhodes	isc_entropysource_t *source;
954135446Strhodes	sample_queue_t *sq;
955135446Strhodes
956135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
957135446Strhodes	REQUIRE(sourcep != NULL && *sourcep == NULL);
958135446Strhodes
959135446Strhodes	LOCK(&ent->lock);
960135446Strhodes
961135446Strhodes	source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
962135446Strhodes	if (source == NULL) {
963170222Sdougb		result = ISC_R_NOMEMORY;
964135446Strhodes		goto errout;
965135446Strhodes	}
966135446Strhodes
967135446Strhodes	sq = &source->sources.sample.samplequeue;
968170222Sdougb	result = samplesource_allocate(ent, sq);
969170222Sdougb	if (result != ISC_R_SUCCESS)
970135446Strhodes		goto errout;
971135446Strhodes
972135446Strhodes	/*
973135446Strhodes	 * From here down, no failures can occur.
974135446Strhodes	 */
975135446Strhodes	source->magic = SOURCE_MAGIC;
976135446Strhodes	source->type = ENTROPY_SOURCETYPE_SAMPLE;
977135446Strhodes	source->ent = ent;
978135446Strhodes	source->total = 0;
979135446Strhodes	memset(source->name, 0, sizeof(source->name));
980135446Strhodes	ISC_LINK_INIT(source, link);
981135446Strhodes
982135446Strhodes	/*
983135446Strhodes	 * Hook it into the entropy system.
984135446Strhodes	 */
985135446Strhodes	ISC_LIST_APPEND(ent->sources, source, link);
986135446Strhodes	ent->nsources++;
987135446Strhodes
988135446Strhodes	*sourcep = source;
989135446Strhodes
990135446Strhodes	UNLOCK(&ent->lock);
991135446Strhodes	return (ISC_R_SUCCESS);
992135446Strhodes
993135446Strhodes errout:
994135446Strhodes	if (source != NULL)
995135446Strhodes		isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
996135446Strhodes
997135446Strhodes	UNLOCK(&ent->lock);
998135446Strhodes
999170222Sdougb	return (result);
1000135446Strhodes}
1001135446Strhodes
1002170222Sdougb/*!
1003135446Strhodes * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1004135446Strhodes * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1005135446Strhodes * queue was full when this function was called.
1006135446Strhodes */
1007135446Strhodesstatic isc_result_t
1008135446Strhodesaddsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
1009135446Strhodes	if (sq->nsamples >= RND_EVENTQSIZE)
1010135446Strhodes		return (ISC_R_NOMORE);
1011135446Strhodes
1012135446Strhodes	sq->samples[sq->nsamples] = sample;
1013135446Strhodes	sq->extra[sq->nsamples] = extra;
1014135446Strhodes	sq->nsamples++;
1015135446Strhodes
1016135446Strhodes	if (sq->nsamples >= RND_EVENTQSIZE)
1017135446Strhodes		return (ISC_R_QUEUEFULL);
1018135446Strhodes
1019135446Strhodes	return (ISC_R_SUCCESS);
1020135446Strhodes}
1021135446Strhodes
1022135446Strhodesisc_result_t
1023135446Strhodesisc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
1024135446Strhodes		      isc_uint32_t extra)
1025135446Strhodes{
1026135446Strhodes	isc_entropy_t *ent;
1027135446Strhodes	sample_queue_t *sq;
1028135446Strhodes	unsigned int entropy;
1029135446Strhodes	isc_result_t result;
1030135446Strhodes
1031135446Strhodes	REQUIRE(VALID_SOURCE(source));
1032135446Strhodes
1033135446Strhodes	ent = source->ent;
1034135446Strhodes
1035135446Strhodes	LOCK(&ent->lock);
1036135446Strhodes
1037135446Strhodes	sq = &source->sources.sample.samplequeue;
1038135446Strhodes	result = addsample(sq, sample, extra);
1039135446Strhodes	if (result == ISC_R_QUEUEFULL) {
1040135446Strhodes		entropy = crunchsamples(ent, sq);
1041135446Strhodes		add_entropy(ent, entropy);
1042135446Strhodes	}
1043135446Strhodes
1044135446Strhodes	UNLOCK(&ent->lock);
1045135446Strhodes
1046135446Strhodes	return (result);
1047135446Strhodes}
1048135446Strhodes
1049135446Strhodesisc_result_t
1050135446Strhodesisc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
1051135446Strhodes			      isc_uint32_t extra)
1052135446Strhodes{
1053135446Strhodes	sample_queue_t *sq;
1054135446Strhodes	isc_result_t result;
1055135446Strhodes
1056135446Strhodes	REQUIRE(VALID_SOURCE(source));
1057135446Strhodes	REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
1058135446Strhodes
1059135446Strhodes	sq = &source->sources.callback.samplequeue;
1060135446Strhodes	result = addsample(sq, sample, extra);
1061135446Strhodes
1062135446Strhodes	return (result);
1063135446Strhodes}
1064135446Strhodes
1065135446Strhodesvoid
1066135446Strhodesisc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
1067135446Strhodes		    isc_uint32_t entropy)
1068135446Strhodes{
1069135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
1070135446Strhodes
1071135446Strhodes	LOCK(&ent->lock);
1072135446Strhodes
1073135446Strhodes	entropypool_adddata(ent, data, length, entropy);
1074135446Strhodes
1075135446Strhodes	if (ent->initialized < THRESHOLD_BITS)
1076135446Strhodes		ent->initialized = THRESHOLD_BITS;
1077135446Strhodes
1078135446Strhodes	UNLOCK(&ent->lock);
1079135446Strhodes}
1080135446Strhodes
1081135446Strhodesstatic void
1082135446Strhodesdumpstats(isc_entropy_t *ent, FILE *out) {
1083135446Strhodes	fprintf(out,
1084135446Strhodes		isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
1085135446Strhodes			       ISC_MSG_ENTROPYSTATS,
1086135446Strhodes			       "Entropy pool %p:  refcnt %u cursor %u,"
1087135446Strhodes			       " rotate %u entropy %u pseudo %u nsources %u"
1088135446Strhodes			       " nextsource %p initialized %u initcount %u\n"),
1089135446Strhodes		ent, ent->refcnt,
1090135446Strhodes		ent->pool.cursor, ent->pool.rotate,
1091135446Strhodes		ent->pool.entropy, ent->pool.pseudo,
1092135446Strhodes		ent->nsources, ent->nextsource, ent->initialized,
1093135446Strhodes		ent->initcount);
1094135446Strhodes}
1095135446Strhodes
1096135446Strhodes/*
1097135446Strhodes * This function ignores locking.  Use at your own risk.
1098135446Strhodes */
1099135446Strhodesvoid
1100135446Strhodesisc_entropy_stats(isc_entropy_t *ent, FILE *out) {
1101135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
1102135446Strhodes
1103135446Strhodes	LOCK(&ent->lock);
1104135446Strhodes	dumpstats(ent, out);
1105135446Strhodes	UNLOCK(&ent->lock);
1106135446Strhodes}
1107135446Strhodes
1108193149Sdougbunsigned int
1109193149Sdougbisc_entropy_status(isc_entropy_t *ent) {
1110193149Sdougb	unsigned int estimate;
1111193149Sdougb
1112193149Sdougb	LOCK(&ent->lock);
1113193149Sdougb	estimate = ent->pool.entropy;
1114193149Sdougb	UNLOCK(&ent->lock);
1115193149Sdougb
1116193149Sdougb	return estimate;
1117193149Sdougb}
1118193149Sdougb
1119135446Strhodesvoid
1120135446Strhodesisc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
1121135446Strhodes	REQUIRE(VALID_ENTROPY(ent));
1122135446Strhodes	REQUIRE(entp != NULL && *entp == NULL);
1123135446Strhodes
1124135446Strhodes	LOCK(&ent->lock);
1125135446Strhodes
1126135446Strhodes	ent->refcnt++;
1127135446Strhodes	*entp = ent;
1128135446Strhodes
1129135446Strhodes	UNLOCK(&ent->lock);
1130135446Strhodes}
1131135446Strhodes
1132135446Strhodesvoid
1133135446Strhodesisc_entropy_detach(isc_entropy_t **entp) {
1134135446Strhodes	isc_entropy_t *ent;
1135135446Strhodes	isc_boolean_t killit;
1136135446Strhodes
1137135446Strhodes	REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
1138135446Strhodes	ent = *entp;
1139135446Strhodes	*entp = NULL;
1140135446Strhodes
1141135446Strhodes	LOCK(&ent->lock);
1142135446Strhodes
1143135446Strhodes	REQUIRE(ent->refcnt > 0);
1144135446Strhodes	ent->refcnt--;
1145135446Strhodes
1146135446Strhodes	killit = destroy_check(ent);
1147135446Strhodes
1148135446Strhodes	UNLOCK(&ent->lock);
1149135446Strhodes
1150135446Strhodes	if (killit)
1151135446Strhodes		destroy(&ent);
1152135446Strhodes}
1153135446Strhodes
1154135446Strhodesstatic isc_result_t
1155135446Strhodeskbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1156135446Strhodes	/*
1157135446Strhodes	 * The intent of "first" is to provide a warning message only once
1158135446Strhodes	 * during the run of a program that might try to gather keyboard
1159135446Strhodes	 * entropy multiple times.
1160135446Strhodes	 */
1161135446Strhodes	static isc_boolean_t first = ISC_TRUE;
1162135446Strhodes
1163135446Strhodes	UNUSED(arg);
1164135446Strhodes
1165135446Strhodes	if (! blocking)
1166135446Strhodes		return (ISC_R_NOENTROPY);
1167135446Strhodes
1168135446Strhodes	if (first) {
1169135446Strhodes		if (source->warn_keyboard)
1170135446Strhodes			fprintf(stderr, "You must use the keyboard to create "
1171135446Strhodes				"entropy, since your system is lacking\n"
1172135446Strhodes				"/dev/random (or equivalent)\n\n");
1173135446Strhodes		first = ISC_FALSE;
1174135446Strhodes	}
1175135446Strhodes	fprintf(stderr, "start typing:\n");
1176135446Strhodes
1177135446Strhodes	return (isc_keyboard_open(&source->kbd));
1178135446Strhodes}
1179135446Strhodes
1180135446Strhodesstatic void
1181135446Strhodeskbdstop(isc_entropysource_t *source, void *arg) {
1182135446Strhodes
1183135446Strhodes	UNUSED(arg);
1184135446Strhodes
1185135446Strhodes	if (! isc_keyboard_canceled(&source->kbd))
1186135446Strhodes		fprintf(stderr, "stop typing.\r\n");
1187135446Strhodes
1188135446Strhodes	(void)isc_keyboard_close(&source->kbd, 3);
1189135446Strhodes}
1190135446Strhodes
1191135446Strhodesstatic isc_result_t
1192135446Strhodeskbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1193135446Strhodes	isc_result_t result;
1194135446Strhodes	isc_time_t t;
1195135446Strhodes	isc_uint32_t sample;
1196135446Strhodes	isc_uint32_t extra;
1197135446Strhodes	unsigned char c;
1198135446Strhodes
1199135446Strhodes	UNUSED(arg);
1200135446Strhodes
1201135446Strhodes	if (!blocking)
1202135446Strhodes		return (ISC_R_NOTBLOCKING);
1203135446Strhodes
1204135446Strhodes	result = isc_keyboard_getchar(&source->kbd, &c);
1205135446Strhodes	if (result != ISC_R_SUCCESS)
1206135446Strhodes		return (result);
1207135446Strhodes
1208135446Strhodes	TIME_NOW(&t);
1209135446Strhodes
1210135446Strhodes	sample = isc_time_nanoseconds(&t);
1211135446Strhodes	extra = c;
1212135446Strhodes
1213135446Strhodes	result = isc_entropy_addcallbacksample(source, sample, extra);
1214135446Strhodes	if (result != ISC_R_SUCCESS) {
1215135446Strhodes		fprintf(stderr, "\r\n");
1216135446Strhodes		return (result);
1217135446Strhodes	}
1218135446Strhodes
1219135446Strhodes	fprintf(stderr, ".");
1220135446Strhodes	fflush(stderr);
1221135446Strhodes
1222135446Strhodes	return (result);
1223135446Strhodes}
1224135446Strhodes
1225135446Strhodesisc_result_t
1226135446Strhodesisc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
1227135446Strhodes			  const char *randomfile, int use_keyboard)
1228135446Strhodes{
1229135446Strhodes	isc_result_t result;
1230135446Strhodes	isc_result_t final_result = ISC_R_NOENTROPY;
1231135446Strhodes	isc_boolean_t userfile = ISC_TRUE;
1232135446Strhodes
1233135446Strhodes	REQUIRE(VALID_ENTROPY(ectx));
1234135446Strhodes	REQUIRE(source != NULL && *source == NULL);
1235135446Strhodes	REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
1236135446Strhodes		use_keyboard == ISC_ENTROPY_KEYBOARDNO  ||
1237135446Strhodes		use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
1238135446Strhodes
1239135446Strhodes#ifdef PATH_RANDOMDEV
1240135446Strhodes	if (randomfile == NULL) {
1241135446Strhodes		randomfile = PATH_RANDOMDEV;
1242135446Strhodes		userfile = ISC_FALSE;
1243135446Strhodes	}
1244135446Strhodes#endif
1245135446Strhodes
1246135446Strhodes	if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
1247135446Strhodes		result = isc_entropy_createfilesource(ectx, randomfile);
1248135446Strhodes		if (result == ISC_R_SUCCESS &&
1249135446Strhodes		    use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
1250135446Strhodes			use_keyboard = ISC_ENTROPY_KEYBOARDNO;
1251135446Strhodes		if (result != ISC_R_SUCCESS && userfile)
1252135446Strhodes			return (result);
1253135446Strhodes
1254135446Strhodes		final_result = result;
1255135446Strhodes	}
1256135446Strhodes
1257135446Strhodes	if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
1258135446Strhodes		result = isc_entropy_createcallbacksource(ectx, kbdstart,
1259135446Strhodes							  kbdget, kbdstop,
1260135446Strhodes							  NULL, source);
1261135446Strhodes		if (result == ISC_R_SUCCESS)
1262135446Strhodes			(*source)->warn_keyboard =
1263135446Strhodes				ISC_TF(use_keyboard ==
1264135446Strhodes				       ISC_ENTROPY_KEYBOARDMAYBE);
1265135446Strhodes
1266135446Strhodes		if (final_result != ISC_R_SUCCESS)
1267135446Strhodes			final_result = result;
1268193149Sdougb	}
1269135446Strhodes
1270135446Strhodes	/*
1271135446Strhodes	 * final_result is ISC_R_SUCCESS if at least one source of entropy
1272135446Strhodes	 * could be started, otherwise it is the error from the most recently
1273135446Strhodes	 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1274135446Strhodes	 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1275135446Strhodes	 */
1276135446Strhodes	return (final_result);
1277135446Strhodes}
1278