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