Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / isc / entropy.c
blob7cda72bedb885a0e6668e09898d4ea13e142148f
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: entropy.c,v 1.20 2009/01/18 23:48:14 tbox Exp */
22 /*! \file
23 * \brief
24 * This is the system independent part of the entropy module. It is
25 * compiled via inclusion from the relevant OS source file, ie,
26 * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
28 * \author Much of this code is modeled after the NetBSD /dev/random implementation,
29 * written by Michael Graff <explorer@netbsd.org>.
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
36 #include <isc/buffer.h>
37 #include <isc/entropy.h>
38 #include <isc/keyboard.h>
39 #include <isc/list.h>
40 #include <isc/magic.h>
41 #include <isc/mem.h>
42 #include <isc/msgs.h>
43 #include <isc/mutex.h>
44 #include <isc/platform.h>
45 #include <isc/region.h>
46 #include <isc/sha1.h>
47 #include <isc/string.h>
48 #include <isc/time.h>
49 #include <isc/util.h>
52 #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
53 #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
55 #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
56 #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
58 /***
59 *** "constants." Do not change these unless you _really_ know what
60 *** you are doing.
61 ***/
63 /*%
64 * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
66 #define RND_POOLWORDS 128
67 /*% Pool in bytes. */
68 #define RND_POOLBYTES (RND_POOLWORDS * 4)
69 /*% Pool in bits. */
70 #define RND_POOLBITS (RND_POOLWORDS * 32)
72 /*%
73 * Number of bytes returned per hash. This must be true:
74 * threshold * 2 <= digest_size_in_bytes
76 #define RND_ENTROPY_THRESHOLD 10
77 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
79 /*%
80 * Size of the input event queue in samples.
82 #define RND_EVENTQSIZE 32
84 /*%
85 * The number of times we'll "reseed" for pseudorandom seeds. This is an
86 * extremely weak pseudorandom seed. If the caller is using lots of
87 * pseudorandom data and they cannot provide a stronger random source,
88 * there is little we can do other than hope they're smart enough to
89 * call _adddata() with something better than we can come up with.
91 #define RND_INITIALIZE 128
93 /*% Entropy Pool */
94 typedef struct {
95 isc_uint32_t cursor; /*%< current add point in the pool */
96 isc_uint32_t entropy; /*%< current entropy estimate in bits */
97 isc_uint32_t pseudo; /*%< bits extracted in pseudorandom */
98 isc_uint32_t rotate; /*%< how many bits to rotate by */
99 isc_uint32_t pool[RND_POOLWORDS]; /*%< random pool data */
100 } isc_entropypool_t;
102 struct isc_entropy {
103 unsigned int magic;
104 isc_mem_t *mctx;
105 isc_mutex_t lock;
106 unsigned int refcnt;
107 isc_uint32_t initialized;
108 isc_uint32_t initcount;
109 isc_entropypool_t pool;
110 unsigned int nsources;
111 isc_entropysource_t *nextsource;
112 ISC_LIST(isc_entropysource_t) sources;
115 /*% Sample Queue */
116 typedef struct {
117 isc_uint32_t last_time; /*%< last time recorded */
118 isc_uint32_t last_delta; /*%< last delta value */
119 isc_uint32_t last_delta2; /*%< last delta2 value */
120 isc_uint32_t nsamples; /*%< number of samples filled in */
121 isc_uint32_t *samples; /*%< the samples */
122 isc_uint32_t *extra; /*%< extra samples added in */
123 } sample_queue_t;
125 typedef struct {
126 sample_queue_t samplequeue;
127 } isc_entropysamplesource_t;
129 typedef struct {
130 isc_boolean_t start_called;
131 isc_entropystart_t startfunc;
132 isc_entropyget_t getfunc;
133 isc_entropystop_t stopfunc;
134 void *arg;
135 sample_queue_t samplequeue;
136 } isc_cbsource_t;
138 typedef struct {
139 FILESOURCE_HANDLE_TYPE handle;
140 } isc_entropyfilesource_t;
142 struct isc_entropysource {
143 unsigned int magic;
144 unsigned int type;
145 isc_entropy_t *ent;
146 isc_uint32_t total; /*%< entropy from this source */
147 ISC_LINK(isc_entropysource_t) link;
148 char name[32];
149 isc_boolean_t bad;
150 isc_boolean_t warn_keyboard;
151 isc_keyboard_t kbd;
152 union {
153 isc_entropysamplesource_t sample;
154 isc_entropyfilesource_t file;
155 isc_cbsource_t callback;
156 isc_entropyusocketsource_t usocket;
157 } sources;
160 #define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
161 #define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
162 #define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
163 #define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
165 /*@{*/
167 * The random pool "taps"
169 #define TAP1 99
170 #define TAP2 59
171 #define TAP3 31
172 #define TAP4 9
173 #define TAP5 7
174 /*@}*/
176 /*@{*/
178 * Declarations for function provided by the system dependent sources that
179 * include this file.
181 static void
182 fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
184 static int
185 wait_for_sources(isc_entropy_t *);
187 static void
188 destroyfilesource(isc_entropyfilesource_t *source);
190 static void
191 destroyusocketsource(isc_entropyusocketsource_t *source);
193 /*@}*/
195 static void
196 samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
197 REQUIRE(sq->samples != NULL);
198 REQUIRE(sq->extra != NULL);
200 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
201 isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
202 sq->samples = NULL;
203 sq->extra = NULL;
206 static isc_result_t
207 samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
208 sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
209 if (sq->samples == NULL)
210 return (ISC_R_NOMEMORY);
212 sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
213 if (sq->extra == NULL) {
214 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
215 sq->samples = NULL;
216 return (ISC_R_NOMEMORY);
219 sq->nsamples = 0;
221 return (ISC_R_SUCCESS);
225 * Add in entropy, even when the value we're adding in could be
226 * very large.
228 static inline void
229 add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
230 /* clamp input. Yes, this must be done. */
231 entropy = ISC_MIN(entropy, RND_POOLBITS);
232 /* Add in the entropy we already have. */
233 entropy += ent->pool.entropy;
234 /* Clamp. */
235 ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
239 * Decrement the amount of entropy the pool has.
241 static inline void
242 subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
243 entropy = ISC_MIN(entropy, ent->pool.entropy);
244 ent->pool.entropy -= entropy;
248 * Add in entropy, even when the value we're adding in could be
249 * very large.
251 static inline void
252 add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
253 /* clamp input. Yes, this must be done. */
254 pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
255 /* Add in the pseudo we already have. */
256 pseudo += ent->pool.pseudo;
257 /* Clamp. */
258 ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
262 * Decrement the amount of pseudo the pool has.
264 static inline void
265 subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
266 pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
267 ent->pool.pseudo -= pseudo;
271 * Add one word to the pool, rotating the input as needed.
273 static inline void
274 entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
276 * Steal some values out of the pool, and xor them into the
277 * word we were given.
279 * Mix the new value into the pool using xor. This will
280 * prevent the actual values from being known to the caller
281 * since the previous values are assumed to be unknown as well.
283 val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
284 val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
285 val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
286 val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
287 val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
288 rp->pool[rp->cursor++] ^=
289 ((val << rp->rotate) | (val >> (32 - rp->rotate)));
292 * If we have looped around the pool, increment the rotate
293 * variable so the next value will get xored in rotated to
294 * a different position.
295 * Increment by a value that is relatively prime to the word size
296 * to try to spread the bits throughout the pool quickly when the
297 * pool is empty.
299 if (rp->cursor == RND_POOLWORDS) {
300 rp->cursor = 0;
301 rp->rotate = (rp->rotate + 7) & 31;
306 * Add a buffer's worth of data to the pool.
308 * Requires that the lock is held on the entropy pool.
310 static void
311 entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
312 isc_uint32_t entropy)
314 isc_uint32_t val;
315 unsigned long addr;
316 isc_uint8_t *buf;
318 addr = (unsigned long)p;
319 buf = p;
321 if ((addr & 0x03U) != 0U) {
322 val = 0;
323 switch (len) {
324 case 3:
325 val = *buf++;
326 len--;
327 case 2:
328 val = val << 8 | *buf++;
329 len--;
330 case 1:
331 val = val << 8 | *buf++;
332 len--;
335 entropypool_add_word(&ent->pool, val);
338 for (; len > 3; len -= 4) {
339 val = *((isc_uint32_t *)buf);
341 entropypool_add_word(&ent->pool, val);
342 buf += 4;
345 if (len != 0) {
346 val = 0;
347 switch (len) {
348 case 3:
349 val = *buf++;
350 case 2:
351 val = val << 8 | *buf++;
352 case 1:
353 val = val << 8 | *buf++;
356 entropypool_add_word(&ent->pool, val);
359 add_entropy(ent, entropy);
360 subtract_pseudo(ent, entropy);
363 static inline void
364 reseed(isc_entropy_t *ent) {
365 isc_time_t t;
366 pid_t pid;
368 if (ent->initcount == 0) {
369 pid = getpid();
370 entropypool_adddata(ent, &pid, sizeof(pid), 0);
371 pid = getppid();
372 entropypool_adddata(ent, &pid, sizeof(pid), 0);
376 * After we've reseeded 100 times, only add new timing info every
377 * 50 requests. This will keep us from using lots and lots of
378 * CPU just to return bad pseudorandom data anyway.
380 if (ent->initcount > 100)
381 if ((ent->initcount % 50) != 0)
382 return;
384 TIME_NOW(&t);
385 entropypool_adddata(ent, &t, sizeof(t), 0);
386 ent->initcount++;
389 static inline unsigned int
390 estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
391 isc_int32_t delta;
392 isc_int32_t delta2;
393 isc_int32_t delta3;
396 * If the time counter has overflowed, calculate the real difference.
397 * If it has not, it is simpler.
399 if (t < sq->last_time)
400 delta = UINT_MAX - sq->last_time + t;
401 else
402 delta = sq->last_time - t;
404 if (delta < 0)
405 delta = -delta;
408 * Calculate the second and third order differentials
410 delta2 = sq->last_delta - delta;
411 if (delta2 < 0)
412 delta2 = -delta2;
414 delta3 = sq->last_delta2 - delta2;
415 if (delta3 < 0)
416 delta3 = -delta3;
418 sq->last_time = t;
419 sq->last_delta = delta;
420 sq->last_delta2 = delta2;
423 * If any delta is 0, we got no entropy. If all are non-zero, we
424 * might have something.
426 if (delta == 0 || delta2 == 0 || delta3 == 0)
427 return 0;
430 * We could find the smallest delta and claim we got log2(delta)
431 * bits, but for now return that we found 1 bit.
433 return 1;
436 static unsigned int
437 crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
438 unsigned int ns;
439 unsigned int added;
441 if (sq->nsamples < 6)
442 return (0);
444 added = 0;
445 sq->last_time = sq->samples[0];
446 sq->last_delta = 0;
447 sq->last_delta2 = 0;
450 * Prime the values by adding in the first 4 samples in. This
451 * should completely initialize the delta calculations.
453 for (ns = 0; ns < 4; ns++)
454 (void)estimate_entropy(sq, sq->samples[ns]);
456 for (ns = 4; ns < sq->nsamples; ns++)
457 added += estimate_entropy(sq, sq->samples[ns]);
459 entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
460 entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
463 * Move the last 4 samples into the first 4 positions, and start
464 * adding new samples from that point.
466 for (ns = 0; ns < 4; ns++) {
467 sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
468 sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
471 sq->nsamples = 4;
473 return (added);
476 static unsigned int
477 get_from_callback(isc_entropysource_t *source, unsigned int desired,
478 isc_boolean_t blocking)
480 isc_entropy_t *ent = source->ent;
481 isc_cbsource_t *cbs = &source->sources.callback;
482 unsigned int added;
483 unsigned int got;
484 isc_result_t result;
486 if (desired == 0)
487 return (0);
489 if (source->bad)
490 return (0);
492 if (!cbs->start_called && cbs->startfunc != NULL) {
493 result = cbs->startfunc(source, cbs->arg, blocking);
494 if (result != ISC_R_SUCCESS)
495 return (0);
496 cbs->start_called = ISC_TRUE;
499 added = 0;
500 result = ISC_R_SUCCESS;
501 while (desired > 0 && result == ISC_R_SUCCESS) {
502 result = cbs->getfunc(source, cbs->arg, blocking);
503 if (result == ISC_R_QUEUEFULL) {
504 got = crunchsamples(ent, &cbs->samplequeue);
505 added += got;
506 desired -= ISC_MIN(got, desired);
507 result = ISC_R_SUCCESS;
508 } else if (result != ISC_R_SUCCESS &&
509 result != ISC_R_NOTBLOCKING)
510 source->bad = ISC_TRUE;
514 return (added);
518 * Extract some number of bytes from the random pool, decreasing the
519 * estimate of randomness as each byte is extracted.
521 * Do this by stiring the pool and returning a part of hash as randomness.
522 * Note that no secrets are given away here since parts of the hash are
523 * xored together before returned.
525 * Honor the request from the caller to only return good data, any data,
526 * etc.
528 isc_result_t
529 isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
530 unsigned int *returned, unsigned int flags)
532 unsigned int i;
533 isc_sha1_t hash;
534 unsigned char digest[ISC_SHA1_DIGESTLENGTH];
535 isc_uint32_t remain, deltae, count, total;
536 isc_uint8_t *buf;
537 isc_boolean_t goodonly, partial, blocking;
539 REQUIRE(VALID_ENTROPY(ent));
540 REQUIRE(data != NULL);
541 REQUIRE(length > 0);
543 goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
544 partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
545 blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
547 REQUIRE(!partial || returned != NULL);
549 LOCK(&ent->lock);
551 remain = length;
552 buf = data;
553 total = 0;
554 while (remain != 0) {
555 count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
558 * If we are extracting good data only, make certain we
559 * have enough data in our pool for this pass. If we don't,
560 * get some, and fail if we can't, and partial returns
561 * are not ok.
563 if (goodonly) {
564 unsigned int fillcount;
566 fillcount = ISC_MAX(remain * 8, count * 8);
569 * If, however, we have at least THRESHOLD_BITS
570 * of entropy in the pool, don't block here. It is
571 * better to drain the pool once in a while and
572 * then refill it than it is to constantly keep the
573 * pool full.
575 if (ent->pool.entropy >= THRESHOLD_BITS)
576 fillpool(ent, fillcount, ISC_FALSE);
577 else
578 fillpool(ent, fillcount, blocking);
581 * Verify that we got enough entropy to do one
582 * extraction. If we didn't, bail.
584 if (ent->pool.entropy < THRESHOLD_BITS) {
585 if (!partial)
586 goto zeroize;
587 else
588 goto partial_output;
590 } else {
592 * If we've extracted half our pool size in bits
593 * since the last refresh, try to refresh here.
595 if (ent->initialized < THRESHOLD_BITS)
596 fillpool(ent, THRESHOLD_BITS, blocking);
597 else
598 fillpool(ent, 0, ISC_FALSE);
601 * If we've not initialized with enough good random
602 * data, seed with our crappy code.
604 if (ent->initialized < THRESHOLD_BITS)
605 reseed(ent);
608 isc_sha1_init(&hash);
609 isc_sha1_update(&hash, (void *)(ent->pool.pool),
610 RND_POOLBYTES);
611 isc_sha1_final(&hash, digest);
614 * Stir the extracted data (all of it) back into the pool.
616 entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
618 for (i = 0; i < count; i++)
619 buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
621 buf += count;
622 remain -= count;
624 deltae = count * 8;
625 deltae = ISC_MIN(deltae, ent->pool.entropy);
626 total += deltae;
627 subtract_entropy(ent, deltae);
628 add_pseudo(ent, count * 8);
631 partial_output:
632 memset(digest, 0, sizeof(digest));
634 if (returned != NULL)
635 *returned = (length - remain);
637 UNLOCK(&ent->lock);
639 return (ISC_R_SUCCESS);
641 zeroize:
642 /* put the entropy we almost extracted back */
643 add_entropy(ent, total);
644 memset(data, 0, length);
645 memset(digest, 0, sizeof(digest));
646 if (returned != NULL)
647 *returned = 0;
649 UNLOCK(&ent->lock);
651 return (ISC_R_NOENTROPY);
654 static void
655 isc_entropypool_init(isc_entropypool_t *pool) {
656 pool->cursor = RND_POOLWORDS - 1;
657 pool->entropy = 0;
658 pool->pseudo = 0;
659 pool->rotate = 0;
660 memset(pool->pool, 0, RND_POOLBYTES);
663 static void
664 isc_entropypool_invalidate(isc_entropypool_t *pool) {
665 pool->cursor = 0;
666 pool->entropy = 0;
667 pool->pseudo = 0;
668 pool->rotate = 0;
669 memset(pool->pool, 0, RND_POOLBYTES);
672 isc_result_t
673 isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
674 isc_result_t result;
675 isc_entropy_t *ent;
677 REQUIRE(mctx != NULL);
678 REQUIRE(entp != NULL && *entp == NULL);
680 ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
681 if (ent == NULL)
682 return (ISC_R_NOMEMORY);
685 * We need a lock.
687 result = isc_mutex_init(&ent->lock);
688 if (result != ISC_R_SUCCESS)
689 goto errout;
692 * From here down, no failures will/can occur.
694 ISC_LIST_INIT(ent->sources);
695 ent->nextsource = NULL;
696 ent->nsources = 0;
697 ent->mctx = NULL;
698 isc_mem_attach(mctx, &ent->mctx);
699 ent->refcnt = 1;
700 ent->initialized = 0;
701 ent->initcount = 0;
702 ent->magic = ENTROPY_MAGIC;
704 isc_entropypool_init(&ent->pool);
706 *entp = ent;
707 return (ISC_R_SUCCESS);
709 errout:
710 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
712 return (result);
716 * Requires "ent" be locked.
718 static void
719 destroysource(isc_entropysource_t **sourcep) {
720 isc_entropysource_t *source;
721 isc_entropy_t *ent;
722 isc_cbsource_t *cbs;
724 source = *sourcep;
725 *sourcep = NULL;
726 ent = source->ent;
728 ISC_LIST_UNLINK(ent->sources, source, link);
729 ent->nextsource = NULL;
730 REQUIRE(ent->nsources > 0);
731 ent->nsources--;
733 switch (source->type) {
734 case ENTROPY_SOURCETYPE_FILE:
735 if (! source->bad)
736 destroyfilesource(&source->sources.file);
737 break;
738 case ENTROPY_SOURCETYPE_USOCKET:
739 if (! source->bad)
740 destroyusocketsource(&source->sources.usocket);
741 break;
742 case ENTROPY_SOURCETYPE_SAMPLE:
743 samplequeue_release(ent, &source->sources.sample.samplequeue);
744 break;
745 case ENTROPY_SOURCETYPE_CALLBACK:
746 cbs = &source->sources.callback;
747 if (cbs->start_called && cbs->stopfunc != NULL) {
748 cbs->stopfunc(source, cbs->arg);
749 cbs->start_called = ISC_FALSE;
751 samplequeue_release(ent, &cbs->samplequeue);
752 break;
755 memset(source, 0, sizeof(isc_entropysource_t));
757 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
760 static inline isc_boolean_t
761 destroy_check(isc_entropy_t *ent) {
762 isc_entropysource_t *source;
764 if (ent->refcnt > 0)
765 return (ISC_FALSE);
767 source = ISC_LIST_HEAD(ent->sources);
768 while (source != NULL) {
769 switch (source->type) {
770 case ENTROPY_SOURCETYPE_FILE:
771 case ENTROPY_SOURCETYPE_USOCKET:
772 break;
773 default:
774 return (ISC_FALSE);
776 source = ISC_LIST_NEXT(source, link);
779 return (ISC_TRUE);
782 static void
783 destroy(isc_entropy_t **entp) {
784 isc_entropy_t *ent;
785 isc_entropysource_t *source;
786 isc_mem_t *mctx;
788 REQUIRE(entp != NULL && *entp != NULL);
789 ent = *entp;
790 *entp = NULL;
792 LOCK(&ent->lock);
794 REQUIRE(ent->refcnt == 0);
797 * Here, detach non-sample sources.
799 source = ISC_LIST_HEAD(ent->sources);
800 while (source != NULL) {
801 switch(source->type) {
802 case ENTROPY_SOURCETYPE_FILE:
803 case ENTROPY_SOURCETYPE_USOCKET:
804 destroysource(&source);
805 break;
807 source = ISC_LIST_HEAD(ent->sources);
811 * If there are other types of sources, we've found a bug.
813 REQUIRE(ISC_LIST_EMPTY(ent->sources));
815 mctx = ent->mctx;
817 isc_entropypool_invalidate(&ent->pool);
819 UNLOCK(&ent->lock);
821 DESTROYLOCK(&ent->lock);
823 memset(ent, 0, sizeof(isc_entropy_t));
824 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
825 isc_mem_detach(&mctx);
828 void
829 isc_entropy_destroysource(isc_entropysource_t **sourcep) {
830 isc_entropysource_t *source;
831 isc_entropy_t *ent;
832 isc_boolean_t killit;
834 REQUIRE(sourcep != NULL);
835 REQUIRE(VALID_SOURCE(*sourcep));
837 source = *sourcep;
838 *sourcep = NULL;
840 ent = source->ent;
841 REQUIRE(VALID_ENTROPY(ent));
843 LOCK(&ent->lock);
845 destroysource(&source);
847 killit = destroy_check(ent);
849 UNLOCK(&ent->lock);
851 if (killit)
852 destroy(&ent);
855 isc_result_t
856 isc_entropy_createcallbacksource(isc_entropy_t *ent,
857 isc_entropystart_t start,
858 isc_entropyget_t get,
859 isc_entropystop_t stop,
860 void *arg,
861 isc_entropysource_t **sourcep)
863 isc_result_t result;
864 isc_entropysource_t *source;
865 isc_cbsource_t *cbs;
867 REQUIRE(VALID_ENTROPY(ent));
868 REQUIRE(get != NULL);
869 REQUIRE(sourcep != NULL && *sourcep == NULL);
871 LOCK(&ent->lock);
873 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
874 if (source == NULL) {
875 result = ISC_R_NOMEMORY;
876 goto errout;
878 source->bad = ISC_FALSE;
880 cbs = &source->sources.callback;
882 result = samplesource_allocate(ent, &cbs->samplequeue);
883 if (result != ISC_R_SUCCESS)
884 goto errout;
886 cbs->start_called = ISC_FALSE;
887 cbs->startfunc = start;
888 cbs->getfunc = get;
889 cbs->stopfunc = stop;
890 cbs->arg = arg;
893 * From here down, no failures can occur.
895 source->magic = SOURCE_MAGIC;
896 source->type = ENTROPY_SOURCETYPE_CALLBACK;
897 source->ent = ent;
898 source->total = 0;
899 memset(source->name, 0, sizeof(source->name));
900 ISC_LINK_INIT(source, link);
903 * Hook it into the entropy system.
905 ISC_LIST_APPEND(ent->sources, source, link);
906 ent->nsources++;
908 *sourcep = source;
910 UNLOCK(&ent->lock);
911 return (ISC_R_SUCCESS);
913 errout:
914 if (source != NULL)
915 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
917 UNLOCK(&ent->lock);
919 return (result);
922 void
923 isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
924 isc_entropysource_t *source;
925 isc_cbsource_t *cbs;
927 REQUIRE(VALID_ENTROPY(ent));
929 LOCK(&ent->lock);
931 source = ISC_LIST_HEAD(ent->sources);
932 while (source != NULL) {
933 if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
934 cbs = &source->sources.callback;
935 if (cbs->start_called && cbs->stopfunc != NULL) {
936 cbs->stopfunc(source, cbs->arg);
937 cbs->start_called = ISC_FALSE;
941 source = ISC_LIST_NEXT(source, link);
944 UNLOCK(&ent->lock);
947 isc_result_t
948 isc_entropy_createsamplesource(isc_entropy_t *ent,
949 isc_entropysource_t **sourcep)
951 isc_result_t result;
952 isc_entropysource_t *source;
953 sample_queue_t *sq;
955 REQUIRE(VALID_ENTROPY(ent));
956 REQUIRE(sourcep != NULL && *sourcep == NULL);
958 LOCK(&ent->lock);
960 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
961 if (source == NULL) {
962 result = ISC_R_NOMEMORY;
963 goto errout;
966 sq = &source->sources.sample.samplequeue;
967 result = samplesource_allocate(ent, sq);
968 if (result != ISC_R_SUCCESS)
969 goto errout;
972 * From here down, no failures can occur.
974 source->magic = SOURCE_MAGIC;
975 source->type = ENTROPY_SOURCETYPE_SAMPLE;
976 source->ent = ent;
977 source->total = 0;
978 memset(source->name, 0, sizeof(source->name));
979 ISC_LINK_INIT(source, link);
982 * Hook it into the entropy system.
984 ISC_LIST_APPEND(ent->sources, source, link);
985 ent->nsources++;
987 *sourcep = source;
989 UNLOCK(&ent->lock);
990 return (ISC_R_SUCCESS);
992 errout:
993 if (source != NULL)
994 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
996 UNLOCK(&ent->lock);
998 return (result);
1002 * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1003 * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1004 * queue was full when this function was called.
1006 static isc_result_t
1007 addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
1008 if (sq->nsamples >= RND_EVENTQSIZE)
1009 return (ISC_R_NOMORE);
1011 sq->samples[sq->nsamples] = sample;
1012 sq->extra[sq->nsamples] = extra;
1013 sq->nsamples++;
1015 if (sq->nsamples >= RND_EVENTQSIZE)
1016 return (ISC_R_QUEUEFULL);
1018 return (ISC_R_SUCCESS);
1021 isc_result_t
1022 isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
1023 isc_uint32_t extra)
1025 isc_entropy_t *ent;
1026 sample_queue_t *sq;
1027 unsigned int entropy;
1028 isc_result_t result;
1030 REQUIRE(VALID_SOURCE(source));
1032 ent = source->ent;
1034 LOCK(&ent->lock);
1036 sq = &source->sources.sample.samplequeue;
1037 result = addsample(sq, sample, extra);
1038 if (result == ISC_R_QUEUEFULL) {
1039 entropy = crunchsamples(ent, sq);
1040 add_entropy(ent, entropy);
1043 UNLOCK(&ent->lock);
1045 return (result);
1048 isc_result_t
1049 isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
1050 isc_uint32_t extra)
1052 sample_queue_t *sq;
1053 isc_result_t result;
1055 REQUIRE(VALID_SOURCE(source));
1056 REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
1058 sq = &source->sources.callback.samplequeue;
1059 result = addsample(sq, sample, extra);
1061 return (result);
1064 void
1065 isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
1066 isc_uint32_t entropy)
1068 REQUIRE(VALID_ENTROPY(ent));
1070 LOCK(&ent->lock);
1072 entropypool_adddata(ent, data, length, entropy);
1074 if (ent->initialized < THRESHOLD_BITS)
1075 ent->initialized = THRESHOLD_BITS;
1077 UNLOCK(&ent->lock);
1080 static void
1081 dumpstats(isc_entropy_t *ent, FILE *out) {
1082 fprintf(out,
1083 isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
1084 ISC_MSG_ENTROPYSTATS,
1085 "Entropy pool %p: refcnt %u cursor %u,"
1086 " rotate %u entropy %u pseudo %u nsources %u"
1087 " nextsource %p initialized %u initcount %u\n"),
1088 ent, ent->refcnt,
1089 ent->pool.cursor, ent->pool.rotate,
1090 ent->pool.entropy, ent->pool.pseudo,
1091 ent->nsources, ent->nextsource, ent->initialized,
1092 ent->initcount);
1096 * This function ignores locking. Use at your own risk.
1098 void
1099 isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
1100 REQUIRE(VALID_ENTROPY(ent));
1102 LOCK(&ent->lock);
1103 dumpstats(ent, out);
1104 UNLOCK(&ent->lock);
1107 unsigned int
1108 isc_entropy_status(isc_entropy_t *ent) {
1109 unsigned int estimate;
1111 LOCK(&ent->lock);
1112 estimate = ent->pool.entropy;
1113 UNLOCK(&ent->lock);
1115 return estimate;
1118 void
1119 isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
1120 REQUIRE(VALID_ENTROPY(ent));
1121 REQUIRE(entp != NULL && *entp == NULL);
1123 LOCK(&ent->lock);
1125 ent->refcnt++;
1126 *entp = ent;
1128 UNLOCK(&ent->lock);
1131 void
1132 isc_entropy_detach(isc_entropy_t **entp) {
1133 isc_entropy_t *ent;
1134 isc_boolean_t killit;
1136 REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
1137 ent = *entp;
1138 *entp = NULL;
1140 LOCK(&ent->lock);
1142 REQUIRE(ent->refcnt > 0);
1143 ent->refcnt--;
1145 killit = destroy_check(ent);
1147 UNLOCK(&ent->lock);
1149 if (killit)
1150 destroy(&ent);
1153 static isc_result_t
1154 kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1156 * The intent of "first" is to provide a warning message only once
1157 * during the run of a program that might try to gather keyboard
1158 * entropy multiple times.
1160 static isc_boolean_t first = ISC_TRUE;
1162 UNUSED(arg);
1164 if (! blocking)
1165 return (ISC_R_NOENTROPY);
1167 if (first) {
1168 if (source->warn_keyboard)
1169 fprintf(stderr, "You must use the keyboard to create "
1170 "entropy, since your system is lacking\n"
1171 "/dev/random (or equivalent)\n\n");
1172 first = ISC_FALSE;
1174 fprintf(stderr, "start typing:\n");
1176 return (isc_keyboard_open(&source->kbd));
1179 static void
1180 kbdstop(isc_entropysource_t *source, void *arg) {
1182 UNUSED(arg);
1184 if (! isc_keyboard_canceled(&source->kbd))
1185 fprintf(stderr, "stop typing.\r\n");
1187 (void)isc_keyboard_close(&source->kbd, 3);
1190 static isc_result_t
1191 kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1192 isc_result_t result;
1193 isc_time_t t;
1194 isc_uint32_t sample;
1195 isc_uint32_t extra;
1196 unsigned char c;
1198 UNUSED(arg);
1200 if (!blocking)
1201 return (ISC_R_NOTBLOCKING);
1203 result = isc_keyboard_getchar(&source->kbd, &c);
1204 if (result != ISC_R_SUCCESS)
1205 return (result);
1207 TIME_NOW(&t);
1209 sample = isc_time_nanoseconds(&t);
1210 extra = c;
1212 result = isc_entropy_addcallbacksample(source, sample, extra);
1213 if (result != ISC_R_SUCCESS) {
1214 fprintf(stderr, "\r\n");
1215 return (result);
1218 fprintf(stderr, ".");
1219 fflush(stderr);
1221 return (result);
1224 isc_result_t
1225 isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
1226 const char *randomfile, int use_keyboard)
1228 isc_result_t result;
1229 isc_result_t final_result = ISC_R_NOENTROPY;
1230 isc_boolean_t userfile = ISC_TRUE;
1232 REQUIRE(VALID_ENTROPY(ectx));
1233 REQUIRE(source != NULL && *source == NULL);
1234 REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
1235 use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
1236 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
1238 #ifdef PATH_RANDOMDEV
1239 if (randomfile == NULL) {
1240 randomfile = PATH_RANDOMDEV;
1241 userfile = ISC_FALSE;
1243 #endif
1245 if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
1246 result = isc_entropy_createfilesource(ectx, randomfile);
1247 if (result == ISC_R_SUCCESS &&
1248 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
1249 use_keyboard = ISC_ENTROPY_KEYBOARDNO;
1250 if (result != ISC_R_SUCCESS && userfile)
1251 return (result);
1253 final_result = result;
1256 if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
1257 result = isc_entropy_createcallbacksource(ectx, kbdstart,
1258 kbdget, kbdstop,
1259 NULL, source);
1260 if (result == ISC_R_SUCCESS)
1261 (*source)->warn_keyboard =
1262 ISC_TF(use_keyboard ==
1263 ISC_ENTROPY_KEYBOARDMAYBE);
1265 if (final_result != ISC_R_SUCCESS)
1266 final_result = result;
1270 * final_result is ISC_R_SUCCESS if at least one source of entropy
1271 * could be started, otherwise it is the error from the most recently
1272 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1273 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1275 return (final_result);