etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / lib / isc / entropy.c
blob8ade6035c54d940d89b570430d2ee97c7b5547f0
1 /* $NetBSD: entropy.c,v 1.5 2014/12/10 04:37:59 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2007, 2009, 2010, 2014 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.22 2010/08/10 23:48:19 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>
51 #ifdef PKCS11CRYPTO
52 #include <pk11/pk11.h>
53 #endif
55 #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
56 #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
58 #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
59 #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
61 /***
62 *** "constants." Do not change these unless you _really_ know what
63 *** you are doing.
64 ***/
66 /*%
67 * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
69 #define RND_POOLWORDS 128
70 /*% Pool in bytes. */
71 #define RND_POOLBYTES (RND_POOLWORDS * 4)
72 /*% Pool in bits. */
73 #define RND_POOLBITS (RND_POOLWORDS * 32)
75 /*%
76 * Number of bytes returned per hash. This must be true:
77 * threshold * 2 <= digest_size_in_bytes
79 #define RND_ENTROPY_THRESHOLD 10
80 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
82 /*%
83 * Size of the input event queue in samples.
85 #define RND_EVENTQSIZE 32
87 /*%
88 * The number of times we'll "reseed" for pseudorandom seeds. This is an
89 * extremely weak pseudorandom seed. If the caller is using lots of
90 * pseudorandom data and they cannot provide a stronger random source,
91 * there is little we can do other than hope they're smart enough to
92 * call _adddata() with something better than we can come up with.
94 #define RND_INITIALIZE 128
96 /*% Entropy Pool */
97 typedef struct {
98 isc_uint32_t cursor; /*%< current add point in the pool */
99 isc_uint32_t entropy; /*%< current entropy estimate in bits */
100 isc_uint32_t pseudo; /*%< bits extracted in pseudorandom */
101 isc_uint32_t rotate; /*%< how many bits to rotate by */
102 isc_uint32_t pool[RND_POOLWORDS]; /*%< random pool data */
103 } isc_entropypool_t;
105 struct isc_entropy {
106 unsigned int magic;
107 isc_mem_t *mctx;
108 isc_mutex_t lock;
109 unsigned int refcnt;
110 isc_uint32_t initialized;
111 isc_uint32_t initcount;
112 isc_entropypool_t pool;
113 unsigned int nsources;
114 isc_entropysource_t *nextsource;
115 ISC_LIST(isc_entropysource_t) sources;
118 /*% Sample Queue */
119 typedef struct {
120 isc_uint32_t last_time; /*%< last time recorded */
121 isc_uint32_t last_delta; /*%< last delta value */
122 isc_uint32_t last_delta2; /*%< last delta2 value */
123 isc_uint32_t nsamples; /*%< number of samples filled in */
124 isc_uint32_t *samples; /*%< the samples */
125 isc_uint32_t *extra; /*%< extra samples added in */
126 } sample_queue_t;
128 typedef struct {
129 sample_queue_t samplequeue;
130 } isc_entropysamplesource_t;
132 typedef struct {
133 isc_boolean_t start_called;
134 isc_entropystart_t startfunc;
135 isc_entropyget_t getfunc;
136 isc_entropystop_t stopfunc;
137 void *arg;
138 sample_queue_t samplequeue;
139 } isc_cbsource_t;
141 typedef struct {
142 FILESOURCE_HANDLE_TYPE handle;
143 } isc_entropyfilesource_t;
145 struct isc_entropysource {
146 unsigned int magic;
147 unsigned int type;
148 isc_entropy_t *ent;
149 isc_uint32_t total; /*%< entropy from this source */
150 ISC_LINK(isc_entropysource_t) link;
151 char name[32];
152 isc_boolean_t bad;
153 isc_boolean_t warn_keyboard;
154 isc_keyboard_t kbd;
155 union {
156 isc_entropysamplesource_t sample;
157 isc_entropyfilesource_t file;
158 isc_cbsource_t callback;
159 isc_entropyusocketsource_t usocket;
160 } sources;
163 #define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
164 #define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
165 #define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
166 #define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
168 /*@{*/
170 * The random pool "taps"
172 #define TAP1 99
173 #define TAP2 59
174 #define TAP3 31
175 #define TAP4 9
176 #define TAP5 7
177 /*@}*/
179 /*@{*/
181 * Declarations for function provided by the system dependent sources that
182 * include this file.
184 static void
185 fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
187 static int
188 wait_for_sources(isc_entropy_t *);
190 static void
191 destroyfilesource(isc_entropyfilesource_t *source);
193 static void
194 destroyusocketsource(isc_entropyusocketsource_t *source);
196 /*@}*/
198 static void
199 samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
200 REQUIRE(sq->samples != NULL);
201 REQUIRE(sq->extra != NULL);
203 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
204 isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
205 sq->samples = NULL;
206 sq->extra = NULL;
209 static isc_result_t
210 samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
211 sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
212 if (sq->samples == NULL)
213 return (ISC_R_NOMEMORY);
215 sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
216 if (sq->extra == NULL) {
217 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
218 sq->samples = NULL;
219 return (ISC_R_NOMEMORY);
222 sq->nsamples = 0;
224 return (ISC_R_SUCCESS);
228 * Add in entropy, even when the value we're adding in could be
229 * very large.
231 static inline void
232 add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
233 /* clamp input. Yes, this must be done. */
234 entropy = ISC_MIN(entropy, RND_POOLBITS);
235 /* Add in the entropy we already have. */
236 entropy += ent->pool.entropy;
237 /* Clamp. */
238 ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
242 * Decrement the amount of entropy the pool has.
244 static inline void
245 subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
246 entropy = ISC_MIN(entropy, ent->pool.entropy);
247 ent->pool.entropy -= entropy;
251 * Add in entropy, even when the value we're adding in could be
252 * very large.
254 static inline void
255 add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
256 /* clamp input. Yes, this must be done. */
257 pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
258 /* Add in the pseudo we already have. */
259 pseudo += ent->pool.pseudo;
260 /* Clamp. */
261 ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
265 * Decrement the amount of pseudo the pool has.
267 static inline void
268 subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
269 pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
270 ent->pool.pseudo -= pseudo;
274 * Add one word to the pool, rotating the input as needed.
276 static inline void
277 entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
279 * Steal some values out of the pool, and xor them into the
280 * word we were given.
282 * Mix the new value into the pool using xor. This will
283 * prevent the actual values from being known to the caller
284 * since the previous values are assumed to be unknown as well.
286 val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
287 val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
288 val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
289 val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
290 val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
291 if (rp->rotate == 0)
292 rp->pool[rp->cursor++] ^= val;
293 else
294 rp->pool[rp->cursor++] ^=
295 ((val << rp->rotate) | (val >> (32 - rp->rotate)));
298 * If we have looped around the pool, increment the rotate
299 * variable so the next value will get xored in rotated to
300 * a different position.
301 * Increment by a value that is relatively prime to the word size
302 * to try to spread the bits throughout the pool quickly when the
303 * pool is empty.
305 if (rp->cursor == RND_POOLWORDS) {
306 rp->cursor = 0;
307 rp->rotate = (rp->rotate + 7) & 31;
312 * Add a buffer's worth of data to the pool.
314 * Requires that the lock is held on the entropy pool.
316 static void
317 entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
318 isc_uint32_t entropy)
320 isc_uint32_t val;
321 unsigned long addr;
322 isc_uint8_t *buf;
324 addr = (unsigned long)p;
325 buf = p;
327 if ((addr & 0x03U) != 0U) {
328 val = 0;
329 switch (len) {
330 case 3:
331 val = *buf++;
332 len--;
333 case 2:
334 val = val << 8 | *buf++;
335 len--;
336 case 1:
337 val = val << 8 | *buf++;
338 len--;
341 entropypool_add_word(&ent->pool, val);
344 for (; len > 3; len -= 4) {
345 val = *((isc_uint32_t *)buf);
347 entropypool_add_word(&ent->pool, val);
348 buf += 4;
351 if (len != 0) {
352 val = 0;
353 switch (len) {
354 case 3:
355 val = *buf++;
356 case 2:
357 val = val << 8 | *buf++;
358 case 1:
359 val = val << 8 | *buf++;
362 entropypool_add_word(&ent->pool, val);
365 add_entropy(ent, entropy);
366 subtract_pseudo(ent, entropy);
369 static inline void
370 reseed(isc_entropy_t *ent) {
371 isc_time_t t;
372 pid_t pid;
374 if (ent->initcount == 0) {
375 pid = getpid();
376 entropypool_adddata(ent, &pid, sizeof(pid), 0);
377 pid = getppid();
378 entropypool_adddata(ent, &pid, sizeof(pid), 0);
382 * After we've reseeded 100 times, only add new timing info every
383 * 50 requests. This will keep us from using lots and lots of
384 * CPU just to return bad pseudorandom data anyway.
386 if (ent->initcount > 100)
387 if ((ent->initcount % 50) != 0)
388 return;
390 TIME_NOW(&t);
391 entropypool_adddata(ent, &t, sizeof(t), 0);
392 ent->initcount++;
395 static inline unsigned int
396 estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
397 isc_int32_t delta;
398 isc_int32_t delta2;
399 isc_int32_t delta3;
402 * If the time counter has overflowed, calculate the real difference.
403 * If it has not, it is simpler.
405 if (t < sq->last_time)
406 delta = UINT_MAX - sq->last_time + t;
407 else
408 delta = sq->last_time - t;
410 if (delta < 0)
411 delta = -delta;
414 * Calculate the second and third order differentials
416 delta2 = sq->last_delta - delta;
417 if (delta2 < 0)
418 delta2 = -delta2;
420 delta3 = sq->last_delta2 - delta2;
421 if (delta3 < 0)
422 delta3 = -delta3;
424 sq->last_time = t;
425 sq->last_delta = delta;
426 sq->last_delta2 = delta2;
429 * If any delta is 0, we got no entropy. If all are non-zero, we
430 * might have something.
432 if (delta == 0 || delta2 == 0 || delta3 == 0)
433 return 0;
436 * We could find the smallest delta and claim we got log2(delta)
437 * bits, but for now return that we found 1 bit.
439 return 1;
442 static unsigned int
443 crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
444 unsigned int ns;
445 unsigned int added;
447 if (sq->nsamples < 6)
448 return (0);
450 added = 0;
451 sq->last_time = sq->samples[0];
452 sq->last_delta = 0;
453 sq->last_delta2 = 0;
456 * Prime the values by adding in the first 4 samples in. This
457 * should completely initialize the delta calculations.
459 for (ns = 0; ns < 4; ns++)
460 (void)estimate_entropy(sq, sq->samples[ns]);
462 for (ns = 4; ns < sq->nsamples; ns++)
463 added += estimate_entropy(sq, sq->samples[ns]);
465 entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
466 entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
469 * Move the last 4 samples into the first 4 positions, and start
470 * adding new samples from that point.
472 for (ns = 0; ns < 4; ns++) {
473 sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
474 sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
477 sq->nsamples = 4;
479 return (added);
482 static unsigned int
483 get_from_callback(isc_entropysource_t *source, unsigned int desired,
484 isc_boolean_t blocking)
486 isc_entropy_t *ent = source->ent;
487 isc_cbsource_t *cbs = &source->sources.callback;
488 unsigned int added;
489 unsigned int got;
490 isc_result_t result;
492 if (desired == 0)
493 return (0);
495 if (source->bad)
496 return (0);
498 if (!cbs->start_called && cbs->startfunc != NULL) {
499 result = cbs->startfunc(source, cbs->arg, blocking);
500 if (result != ISC_R_SUCCESS)
501 return (0);
502 cbs->start_called = ISC_TRUE;
505 added = 0;
506 result = ISC_R_SUCCESS;
507 while (desired > 0 && result == ISC_R_SUCCESS) {
508 result = cbs->getfunc(source, cbs->arg, blocking);
509 if (result == ISC_R_QUEUEFULL) {
510 got = crunchsamples(ent, &cbs->samplequeue);
511 added += got;
512 desired -= ISC_MIN(got, desired);
513 result = ISC_R_SUCCESS;
514 } else if (result != ISC_R_SUCCESS &&
515 result != ISC_R_NOTBLOCKING)
516 source->bad = ISC_TRUE;
520 return (added);
524 * Extract some number of bytes from the random pool, decreasing the
525 * estimate of randomness as each byte is extracted.
527 * Do this by stiring the pool and returning a part of hash as randomness.
528 * Note that no secrets are given away here since parts of the hash are
529 * xored together before returned.
531 * Honor the request from the caller to only return good data, any data,
532 * etc.
534 isc_result_t
535 isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
536 unsigned int *returned, unsigned int flags)
538 unsigned int i;
539 isc_sha1_t hash;
540 unsigned char digest[ISC_SHA1_DIGESTLENGTH];
541 isc_uint32_t remain, deltae, count, total;
542 isc_uint8_t *buf;
543 isc_boolean_t goodonly, partial, blocking;
545 REQUIRE(VALID_ENTROPY(ent));
546 REQUIRE(data != NULL);
547 REQUIRE(length > 0);
549 goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
550 partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
551 blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
553 REQUIRE(!partial || returned != NULL);
555 LOCK(&ent->lock);
557 remain = length;
558 buf = data;
559 total = 0;
560 while (remain != 0) {
561 count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
564 * If we are extracting good data only, make certain we
565 * have enough data in our pool for this pass. If we don't,
566 * get some, and fail if we can't, and partial returns
567 * are not ok.
569 if (goodonly) {
570 unsigned int fillcount;
572 fillcount = ISC_MAX(remain * 8, count * 8);
575 * If, however, we have at least THRESHOLD_BITS
576 * of entropy in the pool, don't block here. It is
577 * better to drain the pool once in a while and
578 * then refill it than it is to constantly keep the
579 * pool full.
581 if (ent->pool.entropy >= THRESHOLD_BITS)
582 fillpool(ent, fillcount, ISC_FALSE);
583 else
584 fillpool(ent, fillcount, blocking);
587 * Verify that we got enough entropy to do one
588 * extraction. If we didn't, bail.
590 if (ent->pool.entropy < THRESHOLD_BITS) {
591 if (!partial)
592 goto zeroize;
593 else
594 goto partial_output;
596 } else {
598 * If we've extracted half our pool size in bits
599 * since the last refresh, try to refresh here.
601 if (ent->initialized < THRESHOLD_BITS)
602 fillpool(ent, THRESHOLD_BITS, blocking);
603 else
604 fillpool(ent, 0, ISC_FALSE);
607 * If we've not initialized with enough good random
608 * data, seed with our crappy code.
610 if (ent->initialized < THRESHOLD_BITS)
611 reseed(ent);
614 isc_sha1_init(&hash);
615 isc_sha1_update(&hash, (void *)(ent->pool.pool),
616 RND_POOLBYTES);
617 isc_sha1_final(&hash, digest);
620 * Stir the extracted data (all of it) back into the pool.
622 entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
624 for (i = 0; i < count; i++)
625 buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
627 buf += count;
628 remain -= count;
630 deltae = count * 8;
631 deltae = ISC_MIN(deltae, ent->pool.entropy);
632 total += deltae;
633 subtract_entropy(ent, deltae);
634 add_pseudo(ent, count * 8);
637 partial_output:
638 memset(digest, 0, sizeof(digest));
640 if (returned != NULL)
641 *returned = (length - remain);
643 UNLOCK(&ent->lock);
645 return (ISC_R_SUCCESS);
647 zeroize:
648 /* put the entropy we almost extracted back */
649 add_entropy(ent, total);
650 memset(data, 0, length);
651 memset(digest, 0, sizeof(digest));
652 if (returned != NULL)
653 *returned = 0;
655 UNLOCK(&ent->lock);
657 return (ISC_R_NOENTROPY);
660 static void
661 isc_entropypool_init(isc_entropypool_t *pool) {
662 pool->cursor = RND_POOLWORDS - 1;
663 pool->entropy = 0;
664 pool->pseudo = 0;
665 pool->rotate = 0;
666 memset(pool->pool, 0, RND_POOLBYTES);
669 static void
670 isc_entropypool_invalidate(isc_entropypool_t *pool) {
671 pool->cursor = 0;
672 pool->entropy = 0;
673 pool->pseudo = 0;
674 pool->rotate = 0;
675 memset(pool->pool, 0, RND_POOLBYTES);
678 isc_result_t
679 isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
680 isc_result_t result;
681 isc_entropy_t *ent;
683 REQUIRE(mctx != NULL);
684 REQUIRE(entp != NULL && *entp == NULL);
686 ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
687 if (ent == NULL)
688 return (ISC_R_NOMEMORY);
691 * We need a lock.
693 result = isc_mutex_init(&ent->lock);
694 if (result != ISC_R_SUCCESS)
695 goto errout;
698 * From here down, no failures will/can occur.
700 ISC_LIST_INIT(ent->sources);
701 ent->nextsource = NULL;
702 ent->nsources = 0;
703 ent->mctx = NULL;
704 isc_mem_attach(mctx, &ent->mctx);
705 ent->refcnt = 1;
706 ent->initialized = 0;
707 ent->initcount = 0;
708 ent->magic = ENTROPY_MAGIC;
710 isc_entropypool_init(&ent->pool);
712 *entp = ent;
713 return (ISC_R_SUCCESS);
715 errout:
716 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
718 return (result);
722 * Requires "ent" be locked.
724 static void
725 destroysource(isc_entropysource_t **sourcep) {
726 isc_entropysource_t *source;
727 isc_entropy_t *ent;
728 isc_cbsource_t *cbs;
730 source = *sourcep;
731 *sourcep = NULL;
732 ent = source->ent;
734 ISC_LIST_UNLINK(ent->sources, source, link);
735 ent->nextsource = NULL;
736 REQUIRE(ent->nsources > 0);
737 ent->nsources--;
739 switch (source->type) {
740 case ENTROPY_SOURCETYPE_FILE:
741 if (! source->bad)
742 destroyfilesource(&source->sources.file);
743 break;
744 case ENTROPY_SOURCETYPE_USOCKET:
745 if (! source->bad)
746 destroyusocketsource(&source->sources.usocket);
747 break;
748 case ENTROPY_SOURCETYPE_SAMPLE:
749 samplequeue_release(ent, &source->sources.sample.samplequeue);
750 break;
751 case ENTROPY_SOURCETYPE_CALLBACK:
752 cbs = &source->sources.callback;
753 if (cbs->start_called && cbs->stopfunc != NULL) {
754 cbs->stopfunc(source, cbs->arg);
755 cbs->start_called = ISC_FALSE;
757 samplequeue_release(ent, &cbs->samplequeue);
758 break;
761 memset(source, 0, sizeof(isc_entropysource_t));
763 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
766 static inline isc_boolean_t
767 destroy_check(isc_entropy_t *ent) {
768 isc_entropysource_t *source;
770 if (ent->refcnt > 0)
771 return (ISC_FALSE);
773 source = ISC_LIST_HEAD(ent->sources);
774 while (source != NULL) {
775 switch (source->type) {
776 case ENTROPY_SOURCETYPE_FILE:
777 case ENTROPY_SOURCETYPE_USOCKET:
778 break;
779 default:
780 return (ISC_FALSE);
782 source = ISC_LIST_NEXT(source, link);
785 return (ISC_TRUE);
788 static void
789 destroy(isc_entropy_t **entp) {
790 isc_entropy_t *ent;
791 isc_entropysource_t *source;
792 isc_mem_t *mctx;
794 REQUIRE(entp != NULL && *entp != NULL);
795 ent = *entp;
796 *entp = NULL;
798 LOCK(&ent->lock);
800 REQUIRE(ent->refcnt == 0);
803 * Here, detach non-sample sources.
805 source = ISC_LIST_HEAD(ent->sources);
806 while (source != NULL) {
807 switch(source->type) {
808 case ENTROPY_SOURCETYPE_FILE:
809 case ENTROPY_SOURCETYPE_USOCKET:
810 destroysource(&source);
811 break;
813 source = ISC_LIST_HEAD(ent->sources);
817 * If there are other types of sources, we've found a bug.
819 REQUIRE(ISC_LIST_EMPTY(ent->sources));
821 mctx = ent->mctx;
823 isc_entropypool_invalidate(&ent->pool);
825 UNLOCK(&ent->lock);
827 DESTROYLOCK(&ent->lock);
829 memset(ent, 0, sizeof(isc_entropy_t));
830 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
831 isc_mem_detach(&mctx);
834 void
835 isc_entropy_destroysource(isc_entropysource_t **sourcep) {
836 isc_entropysource_t *source;
837 isc_entropy_t *ent;
838 isc_boolean_t killit;
840 REQUIRE(sourcep != NULL);
841 REQUIRE(VALID_SOURCE(*sourcep));
843 source = *sourcep;
844 *sourcep = NULL;
846 ent = source->ent;
847 REQUIRE(VALID_ENTROPY(ent));
849 LOCK(&ent->lock);
851 destroysource(&source);
853 killit = destroy_check(ent);
855 UNLOCK(&ent->lock);
857 if (killit)
858 destroy(&ent);
861 isc_result_t
862 isc_entropy_createcallbacksource(isc_entropy_t *ent,
863 isc_entropystart_t start,
864 isc_entropyget_t get,
865 isc_entropystop_t stop,
866 void *arg,
867 isc_entropysource_t **sourcep)
869 isc_result_t result;
870 isc_entropysource_t *source;
871 isc_cbsource_t *cbs;
873 REQUIRE(VALID_ENTROPY(ent));
874 REQUIRE(get != NULL);
875 REQUIRE(sourcep != NULL && *sourcep == NULL);
877 LOCK(&ent->lock);
879 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
880 if (source == NULL) {
881 result = ISC_R_NOMEMORY;
882 goto errout;
884 source->bad = ISC_FALSE;
886 cbs = &source->sources.callback;
888 result = samplesource_allocate(ent, &cbs->samplequeue);
889 if (result != ISC_R_SUCCESS)
890 goto errout;
892 cbs->start_called = ISC_FALSE;
893 cbs->startfunc = start;
894 cbs->getfunc = get;
895 cbs->stopfunc = stop;
896 cbs->arg = arg;
899 * From here down, no failures can occur.
901 source->magic = SOURCE_MAGIC;
902 source->type = ENTROPY_SOURCETYPE_CALLBACK;
903 source->ent = ent;
904 source->total = 0;
905 memset(source->name, 0, sizeof(source->name));
906 ISC_LINK_INIT(source, link);
909 * Hook it into the entropy system.
911 ISC_LIST_APPEND(ent->sources, source, link);
912 ent->nsources++;
914 *sourcep = source;
916 UNLOCK(&ent->lock);
917 return (ISC_R_SUCCESS);
919 errout:
920 if (source != NULL)
921 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
923 UNLOCK(&ent->lock);
925 return (result);
928 void
929 isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
930 isc_entropysource_t *source;
931 isc_cbsource_t *cbs;
933 REQUIRE(VALID_ENTROPY(ent));
935 LOCK(&ent->lock);
937 source = ISC_LIST_HEAD(ent->sources);
938 while (source != NULL) {
939 if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
940 cbs = &source->sources.callback;
941 if (cbs->start_called && cbs->stopfunc != NULL) {
942 cbs->stopfunc(source, cbs->arg);
943 cbs->start_called = ISC_FALSE;
947 source = ISC_LIST_NEXT(source, link);
950 UNLOCK(&ent->lock);
953 isc_result_t
954 isc_entropy_createsamplesource(isc_entropy_t *ent,
955 isc_entropysource_t **sourcep)
957 isc_result_t result;
958 isc_entropysource_t *source;
959 sample_queue_t *sq;
961 REQUIRE(VALID_ENTROPY(ent));
962 REQUIRE(sourcep != NULL && *sourcep == NULL);
964 LOCK(&ent->lock);
966 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
967 if (source == NULL) {
968 result = ISC_R_NOMEMORY;
969 goto errout;
972 sq = &source->sources.sample.samplequeue;
973 result = samplesource_allocate(ent, sq);
974 if (result != ISC_R_SUCCESS)
975 goto errout;
978 * From here down, no failures can occur.
980 source->magic = SOURCE_MAGIC;
981 source->type = ENTROPY_SOURCETYPE_SAMPLE;
982 source->ent = ent;
983 source->total = 0;
984 memset(source->name, 0, sizeof(source->name));
985 ISC_LINK_INIT(source, link);
988 * Hook it into the entropy system.
990 ISC_LIST_APPEND(ent->sources, source, link);
991 ent->nsources++;
993 *sourcep = source;
995 UNLOCK(&ent->lock);
996 return (ISC_R_SUCCESS);
998 errout:
999 if (source != NULL)
1000 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
1002 UNLOCK(&ent->lock);
1004 return (result);
1008 * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1009 * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1010 * queue was full when this function was called.
1012 static isc_result_t
1013 addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
1014 if (sq->nsamples >= RND_EVENTQSIZE)
1015 return (ISC_R_NOMORE);
1017 sq->samples[sq->nsamples] = sample;
1018 sq->extra[sq->nsamples] = extra;
1019 sq->nsamples++;
1021 if (sq->nsamples >= RND_EVENTQSIZE)
1022 return (ISC_R_QUEUEFULL);
1024 return (ISC_R_SUCCESS);
1027 isc_result_t
1028 isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
1029 isc_uint32_t extra)
1031 isc_entropy_t *ent;
1032 sample_queue_t *sq;
1033 unsigned int entropy;
1034 isc_result_t result;
1036 REQUIRE(VALID_SOURCE(source));
1038 ent = source->ent;
1040 LOCK(&ent->lock);
1042 sq = &source->sources.sample.samplequeue;
1043 result = addsample(sq, sample, extra);
1044 if (result == ISC_R_QUEUEFULL) {
1045 entropy = crunchsamples(ent, sq);
1046 add_entropy(ent, entropy);
1049 UNLOCK(&ent->lock);
1051 return (result);
1054 isc_result_t
1055 isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
1056 isc_uint32_t extra)
1058 sample_queue_t *sq;
1059 isc_result_t result;
1061 REQUIRE(VALID_SOURCE(source));
1062 REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
1064 sq = &source->sources.callback.samplequeue;
1065 result = addsample(sq, sample, extra);
1067 return (result);
1070 void
1071 isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
1072 isc_uint32_t entropy)
1074 REQUIRE(VALID_ENTROPY(ent));
1076 LOCK(&ent->lock);
1078 entropypool_adddata(ent, data, length, entropy);
1080 if (ent->initialized < THRESHOLD_BITS)
1081 ent->initialized = THRESHOLD_BITS;
1083 UNLOCK(&ent->lock);
1086 static void
1087 dumpstats(isc_entropy_t *ent, FILE *out) {
1088 fprintf(out,
1089 isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
1090 ISC_MSG_ENTROPYSTATS,
1091 "Entropy pool %p: refcnt %u cursor %u,"
1092 " rotate %u entropy %u pseudo %u nsources %u"
1093 " nextsource %p initialized %u initcount %u\n"),
1094 ent, ent->refcnt,
1095 ent->pool.cursor, ent->pool.rotate,
1096 ent->pool.entropy, ent->pool.pseudo,
1097 ent->nsources, ent->nextsource, ent->initialized,
1098 ent->initcount);
1102 * This function ignores locking. Use at your own risk.
1104 void
1105 isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
1106 REQUIRE(VALID_ENTROPY(ent));
1108 LOCK(&ent->lock);
1109 dumpstats(ent, out);
1110 UNLOCK(&ent->lock);
1113 unsigned int
1114 isc_entropy_status(isc_entropy_t *ent) {
1115 unsigned int estimate;
1117 LOCK(&ent->lock);
1118 estimate = ent->pool.entropy;
1119 UNLOCK(&ent->lock);
1121 return estimate;
1124 void
1125 isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
1126 REQUIRE(VALID_ENTROPY(ent));
1127 REQUIRE(entp != NULL && *entp == NULL);
1129 LOCK(&ent->lock);
1131 ent->refcnt++;
1132 *entp = ent;
1134 UNLOCK(&ent->lock);
1137 void
1138 isc_entropy_detach(isc_entropy_t **entp) {
1139 isc_entropy_t *ent;
1140 isc_boolean_t killit;
1142 REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
1143 ent = *entp;
1144 *entp = NULL;
1146 LOCK(&ent->lock);
1148 REQUIRE(ent->refcnt > 0);
1149 ent->refcnt--;
1151 killit = destroy_check(ent);
1153 UNLOCK(&ent->lock);
1155 if (killit)
1156 destroy(&ent);
1159 static isc_result_t
1160 kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1162 * The intent of "first" is to provide a warning message only once
1163 * during the run of a program that might try to gather keyboard
1164 * entropy multiple times.
1166 static isc_boolean_t first = ISC_TRUE;
1168 UNUSED(arg);
1170 if (! blocking)
1171 return (ISC_R_NOENTROPY);
1173 if (first) {
1174 if (source->warn_keyboard)
1175 fprintf(stderr, "You must use the keyboard to create "
1176 "entropy, since your system is lacking\n"
1177 "/dev/random (or equivalent)\n\n");
1178 first = ISC_FALSE;
1180 fprintf(stderr, "start typing:\n");
1182 return (isc_keyboard_open(&source->kbd));
1185 static void
1186 kbdstop(isc_entropysource_t *source, void *arg) {
1188 UNUSED(arg);
1190 if (! isc_keyboard_canceled(&source->kbd))
1191 fprintf(stderr, "stop typing.\r\n");
1193 (void)isc_keyboard_close(&source->kbd, 3);
1196 static isc_result_t
1197 kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1198 isc_result_t result;
1199 isc_time_t t;
1200 isc_uint32_t sample;
1201 isc_uint32_t extra;
1202 unsigned char c;
1204 UNUSED(arg);
1206 if (!blocking)
1207 return (ISC_R_NOTBLOCKING);
1209 result = isc_keyboard_getchar(&source->kbd, &c);
1210 if (result != ISC_R_SUCCESS)
1211 return (result);
1213 TIME_NOW(&t);
1215 sample = isc_time_nanoseconds(&t);
1216 extra = c;
1218 result = isc_entropy_addcallbacksample(source, sample, extra);
1219 if (result != ISC_R_SUCCESS) {
1220 fprintf(stderr, "\r\n");
1221 return (result);
1224 fprintf(stderr, ".");
1225 fflush(stderr);
1227 return (result);
1230 isc_result_t
1231 isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
1232 const char *randomfile, int use_keyboard)
1234 isc_result_t result;
1235 isc_result_t final_result = ISC_R_NOENTROPY;
1236 isc_boolean_t userfile = ISC_TRUE;
1238 REQUIRE(VALID_ENTROPY(ectx));
1239 REQUIRE(source != NULL && *source == NULL);
1240 REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
1241 use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
1242 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
1244 #ifdef PKCS11CRYPTO
1245 if (randomfile != NULL)
1246 pk11_rand_seed_fromfile(randomfile);
1247 #endif
1249 #ifdef PATH_RANDOMDEV
1250 if (randomfile == NULL) {
1251 randomfile = PATH_RANDOMDEV;
1252 userfile = ISC_FALSE;
1254 #endif
1256 if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
1257 result = isc_entropy_createfilesource(ectx, randomfile);
1258 if (result == ISC_R_SUCCESS &&
1259 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
1260 use_keyboard = ISC_ENTROPY_KEYBOARDNO;
1261 if (result != ISC_R_SUCCESS && userfile)
1262 return (result);
1264 final_result = result;
1267 if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
1268 result = isc_entropy_createcallbacksource(ectx, kbdstart,
1269 kbdget, kbdstop,
1270 NULL, source);
1271 if (result == ISC_R_SUCCESS)
1272 (*source)->warn_keyboard =
1273 ISC_TF(use_keyboard ==
1274 ISC_ENTROPY_KEYBOARDMAYBE);
1276 if (final_result != ISC_R_SUCCESS)
1277 final_result = result;
1281 * final_result is ISC_R_SUCCESS if at least one source of entropy
1282 * could be started, otherwise it is the error from the most recently
1283 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1284 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1286 return (final_result);