kernel - Update swapcache manual page
[dragonfly.git] / contrib / bind / lib / isc / entropy.c
blob5400e32ab18c6c5adbef842c31dbc2ce4585a946
1 /*
2 * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: entropy.c,v 1.18.128.2 2009/01/19 23:47:03 tbox Exp $ */
20 /*! \file
21 * \brief
22 * This is the system independent part of the entropy module. It is
23 * compiled via inclusion from the relevant OS source file, ie,
24 * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
26 * \author Much of this code is modeled after the NetBSD /dev/random implementation,
27 * written by Michael Graff <explorer@netbsd.org>.
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <stdio.h>
34 #include <isc/buffer.h>
35 #include <isc/entropy.h>
36 #include <isc/keyboard.h>
37 #include <isc/list.h>
38 #include <isc/magic.h>
39 #include <isc/mem.h>
40 #include <isc/msgs.h>
41 #include <isc/mutex.h>
42 #include <isc/platform.h>
43 #include <isc/region.h>
44 #include <isc/sha1.h>
45 #include <isc/string.h>
46 #include <isc/time.h>
47 #include <isc/util.h>
50 #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
51 #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
53 #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
54 #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
56 /***
57 *** "constants." Do not change these unless you _really_ know what
58 *** you are doing.
59 ***/
61 /*%
62 * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
64 #define RND_POOLWORDS 128
65 /*% Pool in bytes. */
66 #define RND_POOLBYTES (RND_POOLWORDS * 4)
67 /*% Pool in bits. */
68 #define RND_POOLBITS (RND_POOLWORDS * 32)
70 /*%
71 * Number of bytes returned per hash. This must be true:
72 * threshold * 2 <= digest_size_in_bytes
74 #define RND_ENTROPY_THRESHOLD 10
75 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
77 /*%
78 * Size of the input event queue in samples.
80 #define RND_EVENTQSIZE 32
82 /*%
83 * The number of times we'll "reseed" for pseudorandom seeds. This is an
84 * extremely weak pseudorandom seed. If the caller is using lots of
85 * pseudorandom data and they cannot provide a stronger random source,
86 * there is little we can do other than hope they're smart enough to
87 * call _adddata() with something better than we can come up with.
89 #define RND_INITIALIZE 128
91 /*% Entropy Pool */
92 typedef struct {
93 isc_uint32_t cursor; /*%< current add point in the pool */
94 isc_uint32_t entropy; /*%< current entropy estimate in bits */
95 isc_uint32_t pseudo; /*%< bits extracted in pseudorandom */
96 isc_uint32_t rotate; /*%< how many bits to rotate by */
97 isc_uint32_t pool[RND_POOLWORDS]; /*%< random pool data */
98 } isc_entropypool_t;
100 struct isc_entropy {
101 unsigned int magic;
102 isc_mem_t *mctx;
103 isc_mutex_t lock;
104 unsigned int refcnt;
105 isc_uint32_t initialized;
106 isc_uint32_t initcount;
107 isc_entropypool_t pool;
108 unsigned int nsources;
109 isc_entropysource_t *nextsource;
110 ISC_LIST(isc_entropysource_t) sources;
113 /*% Sample Queue */
114 typedef struct {
115 isc_uint32_t last_time; /*%< last time recorded */
116 isc_uint32_t last_delta; /*%< last delta value */
117 isc_uint32_t last_delta2; /*%< last delta2 value */
118 isc_uint32_t nsamples; /*%< number of samples filled in */
119 isc_uint32_t *samples; /*%< the samples */
120 isc_uint32_t *extra; /*%< extra samples added in */
121 } sample_queue_t;
123 typedef struct {
124 sample_queue_t samplequeue;
125 } isc_entropysamplesource_t;
127 typedef struct {
128 isc_boolean_t start_called;
129 isc_entropystart_t startfunc;
130 isc_entropyget_t getfunc;
131 isc_entropystop_t stopfunc;
132 void *arg;
133 sample_queue_t samplequeue;
134 } isc_cbsource_t;
136 typedef struct {
137 FILESOURCE_HANDLE_TYPE handle;
138 } isc_entropyfilesource_t;
140 struct isc_entropysource {
141 unsigned int magic;
142 unsigned int type;
143 isc_entropy_t *ent;
144 isc_uint32_t total; /*%< entropy from this source */
145 ISC_LINK(isc_entropysource_t) link;
146 char name[32];
147 isc_boolean_t bad;
148 isc_boolean_t warn_keyboard;
149 isc_keyboard_t kbd;
150 union {
151 isc_entropysamplesource_t sample;
152 isc_entropyfilesource_t file;
153 isc_cbsource_t callback;
154 isc_entropyusocketsource_t usocket;
155 } sources;
158 #define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
159 #define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
160 #define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
161 #define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
163 /*@{*/
165 * The random pool "taps"
167 #define TAP1 99
168 #define TAP2 59
169 #define TAP3 31
170 #define TAP4 9
171 #define TAP5 7
172 /*@}*/
174 /*@{*/
176 * Declarations for function provided by the system dependent sources that
177 * include this file.
179 static void
180 fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
182 static int
183 wait_for_sources(isc_entropy_t *);
185 static void
186 destroyfilesource(isc_entropyfilesource_t *source);
188 static void
189 destroyusocketsource(isc_entropyusocketsource_t *source);
191 /*@}*/
193 static void
194 samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
195 REQUIRE(sq->samples != NULL);
196 REQUIRE(sq->extra != NULL);
198 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
199 isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
200 sq->samples = NULL;
201 sq->extra = NULL;
204 static isc_result_t
205 samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
206 sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
207 if (sq->samples == NULL)
208 return (ISC_R_NOMEMORY);
210 sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
211 if (sq->extra == NULL) {
212 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
213 sq->samples = NULL;
214 return (ISC_R_NOMEMORY);
217 sq->nsamples = 0;
219 return (ISC_R_SUCCESS);
223 * Add in entropy, even when the value we're adding in could be
224 * very large.
226 static inline void
227 add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
228 /* clamp input. Yes, this must be done. */
229 entropy = ISC_MIN(entropy, RND_POOLBITS);
230 /* Add in the entropy we already have. */
231 entropy += ent->pool.entropy;
232 /* Clamp. */
233 ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
237 * Decrement the amount of entropy the pool has.
239 static inline void
240 subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
241 entropy = ISC_MIN(entropy, ent->pool.entropy);
242 ent->pool.entropy -= entropy;
246 * Add in entropy, even when the value we're adding in could be
247 * very large.
249 static inline void
250 add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
251 /* clamp input. Yes, this must be done. */
252 pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
253 /* Add in the pseudo we already have. */
254 pseudo += ent->pool.pseudo;
255 /* Clamp. */
256 ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
260 * Decrement the amount of pseudo the pool has.
262 static inline void
263 subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
264 pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
265 ent->pool.pseudo -= pseudo;
269 * Add one word to the pool, rotating the input as needed.
271 static inline void
272 entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
274 * Steal some values out of the pool, and xor them into the
275 * word we were given.
277 * Mix the new value into the pool using xor. This will
278 * prevent the actual values from being known to the caller
279 * since the previous values are assumed to be unknown as well.
281 val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
282 val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
283 val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
284 val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
285 val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
286 rp->pool[rp->cursor++] ^=
287 ((val << rp->rotate) | (val >> (32 - rp->rotate)));
290 * If we have looped around the pool, increment the rotate
291 * variable so the next value will get xored in rotated to
292 * a different position.
293 * Increment by a value that is relatively prime to the word size
294 * to try to spread the bits throughout the pool quickly when the
295 * pool is empty.
297 if (rp->cursor == RND_POOLWORDS) {
298 rp->cursor = 0;
299 rp->rotate = (rp->rotate + 7) & 31;
304 * Add a buffer's worth of data to the pool.
306 * Requires that the lock is held on the entropy pool.
308 static void
309 entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
310 isc_uint32_t entropy)
312 isc_uint32_t val;
313 unsigned long addr;
314 isc_uint8_t *buf;
316 addr = (unsigned long)p;
317 buf = p;
319 if ((addr & 0x03U) != 0U) {
320 val = 0;
321 switch (len) {
322 case 3:
323 val = *buf++;
324 len--;
325 case 2:
326 val = val << 8 | *buf++;
327 len--;
328 case 1:
329 val = val << 8 | *buf++;
330 len--;
333 entropypool_add_word(&ent->pool, val);
336 for (; len > 3; len -= 4) {
337 val = *((isc_uint32_t *)buf);
339 entropypool_add_word(&ent->pool, val);
340 buf += 4;
343 if (len != 0) {
344 val = 0;
345 switch (len) {
346 case 3:
347 val = *buf++;
348 case 2:
349 val = val << 8 | *buf++;
350 case 1:
351 val = val << 8 | *buf++;
354 entropypool_add_word(&ent->pool, val);
357 add_entropy(ent, entropy);
358 subtract_pseudo(ent, entropy);
361 static inline void
362 reseed(isc_entropy_t *ent) {
363 isc_time_t t;
364 pid_t pid;
366 if (ent->initcount == 0) {
367 pid = getpid();
368 entropypool_adddata(ent, &pid, sizeof(pid), 0);
369 pid = getppid();
370 entropypool_adddata(ent, &pid, sizeof(pid), 0);
374 * After we've reseeded 100 times, only add new timing info every
375 * 50 requests. This will keep us from using lots and lots of
376 * CPU just to return bad pseudorandom data anyway.
378 if (ent->initcount > 100)
379 if ((ent->initcount % 50) != 0)
380 return;
382 TIME_NOW(&t);
383 entropypool_adddata(ent, &t, sizeof(t), 0);
384 ent->initcount++;
387 static inline unsigned int
388 estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
389 isc_int32_t delta;
390 isc_int32_t delta2;
391 isc_int32_t delta3;
394 * If the time counter has overflowed, calculate the real difference.
395 * If it has not, it is simpler.
397 if (t < sq->last_time)
398 delta = UINT_MAX - sq->last_time + t;
399 else
400 delta = sq->last_time - t;
402 if (delta < 0)
403 delta = -delta;
406 * Calculate the second and third order differentials
408 delta2 = sq->last_delta - delta;
409 if (delta2 < 0)
410 delta2 = -delta2;
412 delta3 = sq->last_delta2 - delta2;
413 if (delta3 < 0)
414 delta3 = -delta3;
416 sq->last_time = t;
417 sq->last_delta = delta;
418 sq->last_delta2 = delta2;
421 * If any delta is 0, we got no entropy. If all are non-zero, we
422 * might have something.
424 if (delta == 0 || delta2 == 0 || delta3 == 0)
425 return 0;
428 * We could find the smallest delta and claim we got log2(delta)
429 * bits, but for now return that we found 1 bit.
431 return 1;
434 static unsigned int
435 crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
436 unsigned int ns;
437 unsigned int added;
439 if (sq->nsamples < 6)
440 return (0);
442 added = 0;
443 sq->last_time = sq->samples[0];
444 sq->last_delta = 0;
445 sq->last_delta2 = 0;
448 * Prime the values by adding in the first 4 samples in. This
449 * should completely initialize the delta calculations.
451 for (ns = 0; ns < 4; ns++)
452 (void)estimate_entropy(sq, sq->samples[ns]);
454 for (ns = 4; ns < sq->nsamples; ns++)
455 added += estimate_entropy(sq, sq->samples[ns]);
457 entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
458 entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
461 * Move the last 4 samples into the first 4 positions, and start
462 * adding new samples from that point.
464 for (ns = 0; ns < 4; ns++) {
465 sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
466 sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
469 sq->nsamples = 4;
471 return (added);
474 static unsigned int
475 get_from_callback(isc_entropysource_t *source, unsigned int desired,
476 isc_boolean_t blocking)
478 isc_entropy_t *ent = source->ent;
479 isc_cbsource_t *cbs = &source->sources.callback;
480 unsigned int added;
481 unsigned int got;
482 isc_result_t result;
484 if (desired == 0)
485 return (0);
487 if (source->bad)
488 return (0);
490 if (!cbs->start_called && cbs->startfunc != NULL) {
491 result = cbs->startfunc(source, cbs->arg, blocking);
492 if (result != ISC_R_SUCCESS)
493 return (0);
494 cbs->start_called = ISC_TRUE;
497 added = 0;
498 result = ISC_R_SUCCESS;
499 while (desired > 0 && result == ISC_R_SUCCESS) {
500 result = cbs->getfunc(source, cbs->arg, blocking);
501 if (result == ISC_R_QUEUEFULL) {
502 got = crunchsamples(ent, &cbs->samplequeue);
503 added += got;
504 desired -= ISC_MIN(got, desired);
505 result = ISC_R_SUCCESS;
506 } else if (result != ISC_R_SUCCESS &&
507 result != ISC_R_NOTBLOCKING)
508 source->bad = ISC_TRUE;
512 return (added);
516 * Extract some number of bytes from the random pool, decreasing the
517 * estimate of randomness as each byte is extracted.
519 * Do this by stiring the pool and returning a part of hash as randomness.
520 * Note that no secrets are given away here since parts of the hash are
521 * xored together before returned.
523 * Honor the request from the caller to only return good data, any data,
524 * etc.
526 isc_result_t
527 isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
528 unsigned int *returned, unsigned int flags)
530 unsigned int i;
531 isc_sha1_t hash;
532 unsigned char digest[ISC_SHA1_DIGESTLENGTH];
533 isc_uint32_t remain, deltae, count, total;
534 isc_uint8_t *buf;
535 isc_boolean_t goodonly, partial, blocking;
537 REQUIRE(VALID_ENTROPY(ent));
538 REQUIRE(data != NULL);
539 REQUIRE(length > 0);
541 goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
542 partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
543 blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
545 REQUIRE(!partial || returned != NULL);
547 LOCK(&ent->lock);
549 remain = length;
550 buf = data;
551 total = 0;
552 while (remain != 0) {
553 count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
556 * If we are extracting good data only, make certain we
557 * have enough data in our pool for this pass. If we don't,
558 * get some, and fail if we can't, and partial returns
559 * are not ok.
561 if (goodonly) {
562 unsigned int fillcount;
564 fillcount = ISC_MAX(remain * 8, count * 8);
567 * If, however, we have at least THRESHOLD_BITS
568 * of entropy in the pool, don't block here. It is
569 * better to drain the pool once in a while and
570 * then refill it than it is to constantly keep the
571 * pool full.
573 if (ent->pool.entropy >= THRESHOLD_BITS)
574 fillpool(ent, fillcount, ISC_FALSE);
575 else
576 fillpool(ent, fillcount, blocking);
579 * Verify that we got enough entropy to do one
580 * extraction. If we didn't, bail.
582 if (ent->pool.entropy < THRESHOLD_BITS) {
583 if (!partial)
584 goto zeroize;
585 else
586 goto partial_output;
588 } else {
590 * If we've extracted half our pool size in bits
591 * since the last refresh, try to refresh here.
593 if (ent->initialized < THRESHOLD_BITS)
594 fillpool(ent, THRESHOLD_BITS, blocking);
595 else
596 fillpool(ent, 0, ISC_FALSE);
599 * If we've not initialized with enough good random
600 * data, seed with our crappy code.
602 if (ent->initialized < THRESHOLD_BITS)
603 reseed(ent);
606 isc_sha1_init(&hash);
607 isc_sha1_update(&hash, (void *)(ent->pool.pool),
608 RND_POOLBYTES);
609 isc_sha1_final(&hash, digest);
612 * Stir the extracted data (all of it) back into the pool.
614 entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
616 for (i = 0; i < count; i++)
617 buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
619 buf += count;
620 remain -= count;
622 deltae = count * 8;
623 deltae = ISC_MIN(deltae, ent->pool.entropy);
624 total += deltae;
625 subtract_entropy(ent, deltae);
626 add_pseudo(ent, count * 8);
629 partial_output:
630 memset(digest, 0, sizeof(digest));
632 if (returned != NULL)
633 *returned = (length - remain);
635 UNLOCK(&ent->lock);
637 return (ISC_R_SUCCESS);
639 zeroize:
640 /* put the entropy we almost extracted back */
641 add_entropy(ent, total);
642 memset(data, 0, length);
643 memset(digest, 0, sizeof(digest));
644 if (returned != NULL)
645 *returned = 0;
647 UNLOCK(&ent->lock);
649 return (ISC_R_NOENTROPY);
652 static void
653 isc_entropypool_init(isc_entropypool_t *pool) {
654 pool->cursor = RND_POOLWORDS - 1;
655 pool->entropy = 0;
656 pool->pseudo = 0;
657 pool->rotate = 0;
658 memset(pool->pool, 0, RND_POOLBYTES);
661 static void
662 isc_entropypool_invalidate(isc_entropypool_t *pool) {
663 pool->cursor = 0;
664 pool->entropy = 0;
665 pool->pseudo = 0;
666 pool->rotate = 0;
667 memset(pool->pool, 0, RND_POOLBYTES);
670 isc_result_t
671 isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
672 isc_result_t result;
673 isc_entropy_t *ent;
675 REQUIRE(mctx != NULL);
676 REQUIRE(entp != NULL && *entp == NULL);
678 ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
679 if (ent == NULL)
680 return (ISC_R_NOMEMORY);
683 * We need a lock.
685 result = isc_mutex_init(&ent->lock);
686 if (result != ISC_R_SUCCESS)
687 goto errout;
690 * From here down, no failures will/can occur.
692 ISC_LIST_INIT(ent->sources);
693 ent->nextsource = NULL;
694 ent->nsources = 0;
695 ent->mctx = NULL;
696 isc_mem_attach(mctx, &ent->mctx);
697 ent->refcnt = 1;
698 ent->initialized = 0;
699 ent->initcount = 0;
700 ent->magic = ENTROPY_MAGIC;
702 isc_entropypool_init(&ent->pool);
704 *entp = ent;
705 return (ISC_R_SUCCESS);
707 errout:
708 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
710 return (result);
714 * Requires "ent" be locked.
716 static void
717 destroysource(isc_entropysource_t **sourcep) {
718 isc_entropysource_t *source;
719 isc_entropy_t *ent;
720 isc_cbsource_t *cbs;
722 source = *sourcep;
723 *sourcep = NULL;
724 ent = source->ent;
726 ISC_LIST_UNLINK(ent->sources, source, link);
727 ent->nextsource = NULL;
728 REQUIRE(ent->nsources > 0);
729 ent->nsources--;
731 switch (source->type) {
732 case ENTROPY_SOURCETYPE_FILE:
733 if (! source->bad)
734 destroyfilesource(&source->sources.file);
735 break;
736 case ENTROPY_SOURCETYPE_USOCKET:
737 if (! source->bad)
738 destroyusocketsource(&source->sources.usocket);
739 break;
740 case ENTROPY_SOURCETYPE_SAMPLE:
741 samplequeue_release(ent, &source->sources.sample.samplequeue);
742 break;
743 case ENTROPY_SOURCETYPE_CALLBACK:
744 cbs = &source->sources.callback;
745 if (cbs->start_called && cbs->stopfunc != NULL) {
746 cbs->stopfunc(source, cbs->arg);
747 cbs->start_called = ISC_FALSE;
749 samplequeue_release(ent, &cbs->samplequeue);
750 break;
753 memset(source, 0, sizeof(isc_entropysource_t));
755 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
758 static inline isc_boolean_t
759 destroy_check(isc_entropy_t *ent) {
760 isc_entropysource_t *source;
762 if (ent->refcnt > 0)
763 return (ISC_FALSE);
765 source = ISC_LIST_HEAD(ent->sources);
766 while (source != NULL) {
767 switch (source->type) {
768 case ENTROPY_SOURCETYPE_FILE:
769 case ENTROPY_SOURCETYPE_USOCKET:
770 break;
771 default:
772 return (ISC_FALSE);
774 source = ISC_LIST_NEXT(source, link);
777 return (ISC_TRUE);
780 static void
781 destroy(isc_entropy_t **entp) {
782 isc_entropy_t *ent;
783 isc_entropysource_t *source;
784 isc_mem_t *mctx;
786 REQUIRE(entp != NULL && *entp != NULL);
787 ent = *entp;
788 *entp = NULL;
790 LOCK(&ent->lock);
792 REQUIRE(ent->refcnt == 0);
795 * Here, detach non-sample sources.
797 source = ISC_LIST_HEAD(ent->sources);
798 while (source != NULL) {
799 switch(source->type) {
800 case ENTROPY_SOURCETYPE_FILE:
801 case ENTROPY_SOURCETYPE_USOCKET:
802 destroysource(&source);
803 break;
805 source = ISC_LIST_HEAD(ent->sources);
809 * If there are other types of sources, we've found a bug.
811 REQUIRE(ISC_LIST_EMPTY(ent->sources));
813 mctx = ent->mctx;
815 isc_entropypool_invalidate(&ent->pool);
817 UNLOCK(&ent->lock);
819 DESTROYLOCK(&ent->lock);
821 memset(ent, 0, sizeof(isc_entropy_t));
822 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
823 isc_mem_detach(&mctx);
826 void
827 isc_entropy_destroysource(isc_entropysource_t **sourcep) {
828 isc_entropysource_t *source;
829 isc_entropy_t *ent;
830 isc_boolean_t killit;
832 REQUIRE(sourcep != NULL);
833 REQUIRE(VALID_SOURCE(*sourcep));
835 source = *sourcep;
836 *sourcep = NULL;
838 ent = source->ent;
839 REQUIRE(VALID_ENTROPY(ent));
841 LOCK(&ent->lock);
843 destroysource(&source);
845 killit = destroy_check(ent);
847 UNLOCK(&ent->lock);
849 if (killit)
850 destroy(&ent);
853 isc_result_t
854 isc_entropy_createcallbacksource(isc_entropy_t *ent,
855 isc_entropystart_t start,
856 isc_entropyget_t get,
857 isc_entropystop_t stop,
858 void *arg,
859 isc_entropysource_t **sourcep)
861 isc_result_t result;
862 isc_entropysource_t *source;
863 isc_cbsource_t *cbs;
865 REQUIRE(VALID_ENTROPY(ent));
866 REQUIRE(get != NULL);
867 REQUIRE(sourcep != NULL && *sourcep == NULL);
869 LOCK(&ent->lock);
871 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
872 if (source == NULL) {
873 result = ISC_R_NOMEMORY;
874 goto errout;
876 source->bad = ISC_FALSE;
878 cbs = &source->sources.callback;
880 result = samplesource_allocate(ent, &cbs->samplequeue);
881 if (result != ISC_R_SUCCESS)
882 goto errout;
884 cbs->start_called = ISC_FALSE;
885 cbs->startfunc = start;
886 cbs->getfunc = get;
887 cbs->stopfunc = stop;
888 cbs->arg = arg;
891 * From here down, no failures can occur.
893 source->magic = SOURCE_MAGIC;
894 source->type = ENTROPY_SOURCETYPE_CALLBACK;
895 source->ent = ent;
896 source->total = 0;
897 memset(source->name, 0, sizeof(source->name));
898 ISC_LINK_INIT(source, link);
901 * Hook it into the entropy system.
903 ISC_LIST_APPEND(ent->sources, source, link);
904 ent->nsources++;
906 *sourcep = source;
908 UNLOCK(&ent->lock);
909 return (ISC_R_SUCCESS);
911 errout:
912 if (source != NULL)
913 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
915 UNLOCK(&ent->lock);
917 return (result);
920 void
921 isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
922 isc_entropysource_t *source;
923 isc_cbsource_t *cbs;
925 REQUIRE(VALID_ENTROPY(ent));
927 LOCK(&ent->lock);
929 source = ISC_LIST_HEAD(ent->sources);
930 while (source != NULL) {
931 if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
932 cbs = &source->sources.callback;
933 if (cbs->start_called && cbs->stopfunc != NULL) {
934 cbs->stopfunc(source, cbs->arg);
935 cbs->start_called = ISC_FALSE;
939 source = ISC_LIST_NEXT(source, link);
942 UNLOCK(&ent->lock);
945 isc_result_t
946 isc_entropy_createsamplesource(isc_entropy_t *ent,
947 isc_entropysource_t **sourcep)
949 isc_result_t result;
950 isc_entropysource_t *source;
951 sample_queue_t *sq;
953 REQUIRE(VALID_ENTROPY(ent));
954 REQUIRE(sourcep != NULL && *sourcep == NULL);
956 LOCK(&ent->lock);
958 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
959 if (source == NULL) {
960 result = ISC_R_NOMEMORY;
961 goto errout;
964 sq = &source->sources.sample.samplequeue;
965 result = samplesource_allocate(ent, sq);
966 if (result != ISC_R_SUCCESS)
967 goto errout;
970 * From here down, no failures can occur.
972 source->magic = SOURCE_MAGIC;
973 source->type = ENTROPY_SOURCETYPE_SAMPLE;
974 source->ent = ent;
975 source->total = 0;
976 memset(source->name, 0, sizeof(source->name));
977 ISC_LINK_INIT(source, link);
980 * Hook it into the entropy system.
982 ISC_LIST_APPEND(ent->sources, source, link);
983 ent->nsources++;
985 *sourcep = source;
987 UNLOCK(&ent->lock);
988 return (ISC_R_SUCCESS);
990 errout:
991 if (source != NULL)
992 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
994 UNLOCK(&ent->lock);
996 return (result);
1000 * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1001 * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1002 * queue was full when this function was called.
1004 static isc_result_t
1005 addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
1006 if (sq->nsamples >= RND_EVENTQSIZE)
1007 return (ISC_R_NOMORE);
1009 sq->samples[sq->nsamples] = sample;
1010 sq->extra[sq->nsamples] = extra;
1011 sq->nsamples++;
1013 if (sq->nsamples >= RND_EVENTQSIZE)
1014 return (ISC_R_QUEUEFULL);
1016 return (ISC_R_SUCCESS);
1019 isc_result_t
1020 isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
1021 isc_uint32_t extra)
1023 isc_entropy_t *ent;
1024 sample_queue_t *sq;
1025 unsigned int entropy;
1026 isc_result_t result;
1028 REQUIRE(VALID_SOURCE(source));
1030 ent = source->ent;
1032 LOCK(&ent->lock);
1034 sq = &source->sources.sample.samplequeue;
1035 result = addsample(sq, sample, extra);
1036 if (result == ISC_R_QUEUEFULL) {
1037 entropy = crunchsamples(ent, sq);
1038 add_entropy(ent, entropy);
1041 UNLOCK(&ent->lock);
1043 return (result);
1046 isc_result_t
1047 isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
1048 isc_uint32_t extra)
1050 sample_queue_t *sq;
1051 isc_result_t result;
1053 REQUIRE(VALID_SOURCE(source));
1054 REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
1056 sq = &source->sources.callback.samplequeue;
1057 result = addsample(sq, sample, extra);
1059 return (result);
1062 void
1063 isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
1064 isc_uint32_t entropy)
1066 REQUIRE(VALID_ENTROPY(ent));
1068 LOCK(&ent->lock);
1070 entropypool_adddata(ent, data, length, entropy);
1072 if (ent->initialized < THRESHOLD_BITS)
1073 ent->initialized = THRESHOLD_BITS;
1075 UNLOCK(&ent->lock);
1078 static void
1079 dumpstats(isc_entropy_t *ent, FILE *out) {
1080 fprintf(out,
1081 isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
1082 ISC_MSG_ENTROPYSTATS,
1083 "Entropy pool %p: refcnt %u cursor %u,"
1084 " rotate %u entropy %u pseudo %u nsources %u"
1085 " nextsource %p initialized %u initcount %u\n"),
1086 ent, ent->refcnt,
1087 ent->pool.cursor, ent->pool.rotate,
1088 ent->pool.entropy, ent->pool.pseudo,
1089 ent->nsources, ent->nextsource, ent->initialized,
1090 ent->initcount);
1094 * This function ignores locking. Use at your own risk.
1096 void
1097 isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
1098 REQUIRE(VALID_ENTROPY(ent));
1100 LOCK(&ent->lock);
1101 dumpstats(ent, out);
1102 UNLOCK(&ent->lock);
1105 unsigned int
1106 isc_entropy_status(isc_entropy_t *ent) {
1107 unsigned int estimate;
1109 LOCK(&ent->lock);
1110 estimate = ent->pool.entropy;
1111 UNLOCK(&ent->lock);
1113 return estimate;
1116 void
1117 isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
1118 REQUIRE(VALID_ENTROPY(ent));
1119 REQUIRE(entp != NULL && *entp == NULL);
1121 LOCK(&ent->lock);
1123 ent->refcnt++;
1124 *entp = ent;
1126 UNLOCK(&ent->lock);
1129 void
1130 isc_entropy_detach(isc_entropy_t **entp) {
1131 isc_entropy_t *ent;
1132 isc_boolean_t killit;
1134 REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
1135 ent = *entp;
1136 *entp = NULL;
1138 LOCK(&ent->lock);
1140 REQUIRE(ent->refcnt > 0);
1141 ent->refcnt--;
1143 killit = destroy_check(ent);
1145 UNLOCK(&ent->lock);
1147 if (killit)
1148 destroy(&ent);
1151 static isc_result_t
1152 kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1154 * The intent of "first" is to provide a warning message only once
1155 * during the run of a program that might try to gather keyboard
1156 * entropy multiple times.
1158 static isc_boolean_t first = ISC_TRUE;
1160 UNUSED(arg);
1162 if (! blocking)
1163 return (ISC_R_NOENTROPY);
1165 if (first) {
1166 if (source->warn_keyboard)
1167 fprintf(stderr, "You must use the keyboard to create "
1168 "entropy, since your system is lacking\n"
1169 "/dev/random (or equivalent)\n\n");
1170 first = ISC_FALSE;
1172 fprintf(stderr, "start typing:\n");
1174 return (isc_keyboard_open(&source->kbd));
1177 static void
1178 kbdstop(isc_entropysource_t *source, void *arg) {
1180 UNUSED(arg);
1182 if (! isc_keyboard_canceled(&source->kbd))
1183 fprintf(stderr, "stop typing.\r\n");
1185 (void)isc_keyboard_close(&source->kbd, 3);
1188 static isc_result_t
1189 kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1190 isc_result_t result;
1191 isc_time_t t;
1192 isc_uint32_t sample;
1193 isc_uint32_t extra;
1194 unsigned char c;
1196 UNUSED(arg);
1198 if (!blocking)
1199 return (ISC_R_NOTBLOCKING);
1201 result = isc_keyboard_getchar(&source->kbd, &c);
1202 if (result != ISC_R_SUCCESS)
1203 return (result);
1205 TIME_NOW(&t);
1207 sample = isc_time_nanoseconds(&t);
1208 extra = c;
1210 result = isc_entropy_addcallbacksample(source, sample, extra);
1211 if (result != ISC_R_SUCCESS) {
1212 fprintf(stderr, "\r\n");
1213 return (result);
1216 fprintf(stderr, ".");
1217 fflush(stderr);
1219 return (result);
1222 isc_result_t
1223 isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
1224 const char *randomfile, int use_keyboard)
1226 isc_result_t result;
1227 isc_result_t final_result = ISC_R_NOENTROPY;
1228 isc_boolean_t userfile = ISC_TRUE;
1230 REQUIRE(VALID_ENTROPY(ectx));
1231 REQUIRE(source != NULL && *source == NULL);
1232 REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
1233 use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
1234 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
1236 #ifdef PATH_RANDOMDEV
1237 if (randomfile == NULL) {
1238 randomfile = PATH_RANDOMDEV;
1239 userfile = ISC_FALSE;
1241 #endif
1243 if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
1244 result = isc_entropy_createfilesource(ectx, randomfile);
1245 if (result == ISC_R_SUCCESS &&
1246 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
1247 use_keyboard = ISC_ENTROPY_KEYBOARDNO;
1248 if (result != ISC_R_SUCCESS && userfile)
1249 return (result);
1251 final_result = result;
1254 if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
1255 result = isc_entropy_createcallbacksource(ectx, kbdstart,
1256 kbdget, kbdstop,
1257 NULL, source);
1258 if (result == ISC_R_SUCCESS)
1259 (*source)->warn_keyboard =
1260 ISC_TF(use_keyboard ==
1261 ISC_ENTROPY_KEYBOARDMAYBE);
1263 if (final_result != ISC_R_SUCCESS)
1264 final_result = result;
1268 * final_result is ISC_R_SUCCESS if at least one source of entropy
1269 * could be started, otherwise it is the error from the most recently
1270 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1271 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1273 return (final_result);