1 /* $NetBSD: entropy.c,v 1.6 2020/05/25 20:47:20 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2003 Internet Software Consortium.
6 *
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.
10 *
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.
18 */
19
20 /* Id: entropy.c,v 1.22 2010/08/10 23:48:19 tbox Exp */
21
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.
27 *
28 * \author Much of this code is modeled after the NetBSD /dev/random implementation,
29 * written by Michael Graff <explorer@netbsd.org>.
30 */
31
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35
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>
50
51
52 #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
53 #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
54
55 #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
56 #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
57
58 /***
59 *** "constants." Do not change these unless you _really_ know what
60 *** you are doing.
61 ***/
62
63 /*%
64 * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
65 */
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)
71
72 /*%
73 * Number of bytes returned per hash. This must be true:
74 * threshold * 2 <= digest_size_in_bytes
75 */
76 #define RND_ENTROPY_THRESHOLD 10
77 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
78
79 /*%
80 * Size of the input event queue in samples.
81 */
82 #define RND_EVENTQSIZE 32
83
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.
90 */
91 #define RND_INITIALIZE 128
92
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;
101
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;
113 };
114
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;
124
125 typedef struct {
126 sample_queue_t samplequeue;
127 } isc_entropysamplesource_t;
128
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;
137
138 typedef struct {
139 FILESOURCE_HANDLE_TYPE handle;
140 } isc_entropyfilesource_t;
141
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;
158 };
159
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 */
164
165 /*@{*/
166 /*%
167 * The random pool "taps"
168 */
169 #define TAP1 99
170 #define TAP2 59
171 #define TAP3 31
172 #define TAP4 9
173 #define TAP5 7
174 /*@}*/
175
176 /*@{*/
177 /*%
178 * Declarations for function provided by the system dependent sources that
179 * include this file.
180 */
181 static void
182 fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
183
184 static int
185 wait_for_sources(isc_entropy_t *);
186
187 static void
188 destroyfilesource(isc_entropyfilesource_t *source);
189
190 static void
191 destroyusocketsource(isc_entropyusocketsource_t *source);
192
193 /*@}*/
194
195 static void
samplequeue_release(isc_entropy_t * ent,sample_queue_t * sq)196 samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
197 REQUIRE(sq->samples != NULL);
198 REQUIRE(sq->extra != NULL);
199
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;
204 }
205
206 static isc_result_t
samplesource_allocate(isc_entropy_t * ent,sample_queue_t * sq)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);
211
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);
217 }
218
219 sq->nsamples = 0;
220
221 return (ISC_R_SUCCESS);
222 }
223
224 /*%
225 * Add in entropy, even when the value we're adding in could be
226 * very large.
227 */
228 static inline void
add_entropy(isc_entropy_t * ent,isc_uint32_t entropy)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);
236 }
237
238 /*%
239 * Decrement the amount of entropy the pool has.
240 */
241 static inline void
subtract_entropy(isc_entropy_t * ent,isc_uint32_t entropy)242 subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
243 entropy = ISC_MIN(entropy, ent->pool.entropy);
244 ent->pool.entropy -= entropy;
245 }
246
247 /*!
248 * Add in entropy, even when the value we're adding in could be
249 * very large.
250 */
251 static inline void
add_pseudo(isc_entropy_t * ent,isc_uint32_t pseudo)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);
259 }
260
261 /*!
262 * Decrement the amount of pseudo the pool has.
263 */
264 static inline void
subtract_pseudo(isc_entropy_t * ent,isc_uint32_t pseudo)265 subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
266 pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
267 ent->pool.pseudo -= pseudo;
268 }
269
270 /*!
271 * Add one word to the pool, rotating the input as needed.
272 */
273 static inline void
entropypool_add_word(isc_entropypool_t * rp,isc_uint32_t val)274 entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
275 /*
276 * Steal some values out of the pool, and xor them into the
277 * word we were given.
278 *
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.
282 */
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 if (rp->rotate == 0)
289 rp->pool[rp->cursor++] ^= val;
290 else
291 rp->pool[rp->cursor++] ^=
292 ((val << rp->rotate) | (val >> (32 - rp->rotate)));
293
294 /*
295 * If we have looped around the pool, increment the rotate
296 * variable so the next value will get xored in rotated to
297 * a different position.
298 * Increment by a value that is relatively prime to the word size
299 * to try to spread the bits throughout the pool quickly when the
300 * pool is empty.
301 */
302 if (rp->cursor == RND_POOLWORDS) {
303 rp->cursor = 0;
304 rp->rotate = (rp->rotate + 7) & 31;
305 }
306 }
307
308 /*!
309 * Add a buffer's worth of data to the pool.
310 *
311 * Requires that the lock is held on the entropy pool.
312 */
313 static void
entropypool_adddata(isc_entropy_t * ent,void * p,unsigned int len,isc_uint32_t entropy)314 entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
315 isc_uint32_t entropy)
316 {
317 isc_uint32_t val;
318 unsigned long addr;
319 isc_uint8_t *buf;
320
321 addr = (unsigned long)p;
322 buf = p;
323
324 if ((addr & 0x03U) != 0U) {
325 val = 0;
326 switch (len) {
327 case 3:
328 val = *buf++;
329 len--;
330 case 2:
331 val = val << 8 | *buf++;
332 len--;
333 case 1:
334 val = val << 8 | *buf++;
335 len--;
336 }
337
338 entropypool_add_word(&ent->pool, val);
339 }
340
341 for (; len > 3; len -= 4) {
342 val = *((isc_uint32_t *)buf);
343
344 entropypool_add_word(&ent->pool, val);
345 buf += 4;
346 }
347
348 if (len != 0) {
349 val = 0;
350 switch (len) {
351 case 3:
352 val = *buf++;
353 case 2:
354 val = val << 8 | *buf++;
355 case 1:
356 val = val << 8 | *buf++;
357 }
358
359 entropypool_add_word(&ent->pool, val);
360 }
361
362 add_entropy(ent, entropy);
363 subtract_pseudo(ent, entropy);
364 }
365
366 static inline void
reseed(isc_entropy_t * ent)367 reseed(isc_entropy_t *ent) {
368 isc_time_t t;
369 pid_t pid;
370
371 if (ent->initcount == 0) {
372 pid = getpid();
373 entropypool_adddata(ent, &pid, sizeof(pid), 0);
374 pid = getppid();
375 entropypool_adddata(ent, &pid, sizeof(pid), 0);
376 }
377
378 /*!
379 * After we've reseeded 100 times, only add new timing info every
380 * 50 requests. This will keep us from using lots and lots of
381 * CPU just to return bad pseudorandom data anyway.
382 */
383 if (ent->initcount > 100)
384 if ((ent->initcount % 50) != 0)
385 return;
386
387 TIME_NOW(&t);
388 entropypool_adddata(ent, &t, sizeof(t), 0);
389 ent->initcount++;
390 }
391
392 static inline unsigned int
estimate_entropy(sample_queue_t * sq,isc_uint32_t t)393 estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
394 isc_int32_t delta;
395 isc_int32_t delta2;
396 isc_int32_t delta3;
397
398 /*!
399 * If the time counter has overflowed, calculate the real difference.
400 * If it has not, it is simpler.
401 */
402 if (t < sq->last_time)
403 delta = UINT_MAX - sq->last_time + t;
404 else
405 delta = sq->last_time - t;
406
407 if (delta < 0)
408 delta = -delta;
409
410 /*
411 * Calculate the second and third order differentials
412 */
413 delta2 = sq->last_delta - delta;
414 if (delta2 < 0)
415 delta2 = -delta2;
416
417 delta3 = sq->last_delta2 - delta2;
418 if (delta3 < 0)
419 delta3 = -delta3;
420
421 sq->last_time = t;
422 sq->last_delta = delta;
423 sq->last_delta2 = delta2;
424
425 /*
426 * If any delta is 0, we got no entropy. If all are non-zero, we
427 * might have something.
428 */
429 if (delta == 0 || delta2 == 0 || delta3 == 0)
430 return 0;
431
432 /*
433 * We could find the smallest delta and claim we got log2(delta)
434 * bits, but for now return that we found 1 bit.
435 */
436 return 1;
437 }
438
439 static unsigned int
crunchsamples(isc_entropy_t * ent,sample_queue_t * sq)440 crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
441 unsigned int ns;
442 unsigned int added;
443
444 if (sq->nsamples < 6)
445 return (0);
446
447 added = 0;
448 sq->last_time = sq->samples[0];
449 sq->last_delta = 0;
450 sq->last_delta2 = 0;
451
452 /*
453 * Prime the values by adding in the first 4 samples in. This
454 * should completely initialize the delta calculations.
455 */
456 for (ns = 0; ns < 4; ns++)
457 (void)estimate_entropy(sq, sq->samples[ns]);
458
459 for (ns = 4; ns < sq->nsamples; ns++)
460 added += estimate_entropy(sq, sq->samples[ns]);
461
462 entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
463 entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
464
465 /*
466 * Move the last 4 samples into the first 4 positions, and start
467 * adding new samples from that point.
468 */
469 for (ns = 0; ns < 4; ns++) {
470 sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
471 sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
472 }
473
474 sq->nsamples = 4;
475
476 return (added);
477 }
478
479 static unsigned int
get_from_callback(isc_entropysource_t * source,unsigned int desired,isc_boolean_t blocking)480 get_from_callback(isc_entropysource_t *source, unsigned int desired,
481 isc_boolean_t blocking)
482 {
483 isc_entropy_t *ent = source->ent;
484 isc_cbsource_t *cbs = &source->sources.callback;
485 unsigned int added;
486 unsigned int got;
487 isc_result_t result;
488
489 if (desired == 0)
490 return (0);
491
492 if (source->bad)
493 return (0);
494
495 if (!cbs->start_called && cbs->startfunc != NULL) {
496 result = cbs->startfunc(source, cbs->arg, blocking);
497 if (result != ISC_R_SUCCESS)
498 return (0);
499 cbs->start_called = ISC_TRUE;
500 }
501
502 added = 0;
503 result = ISC_R_SUCCESS;
504 while (desired > 0 && result == ISC_R_SUCCESS) {
505 result = cbs->getfunc(source, cbs->arg, blocking);
506 if (result == ISC_R_QUEUEFULL) {
507 got = crunchsamples(ent, &cbs->samplequeue);
508 added += got;
509 desired -= ISC_MIN(got, desired);
510 result = ISC_R_SUCCESS;
511 } else if (result != ISC_R_SUCCESS &&
512 result != ISC_R_NOTBLOCKING)
513 source->bad = ISC_TRUE;
514
515 }
516
517 return (added);
518 }
519
520 /*
521 * Extract some number of bytes from the random pool, decreasing the
522 * estimate of randomness as each byte is extracted.
523 *
524 * Do this by stiring the pool and returning a part of hash as randomness.
525 * Note that no secrets are given away here since parts of the hash are
526 * xored together before returned.
527 *
528 * Honor the request from the caller to only return good data, any data,
529 * etc.
530 */
531 isc_result_t
isc_entropy_getdata(isc_entropy_t * ent,void * data,unsigned int length,unsigned int * returned,unsigned int flags)532 isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
533 unsigned int *returned, unsigned int flags)
534 {
535 unsigned int i;
536 isc_sha1_t hash;
537 unsigned char digest[ISC_SHA1_DIGESTLENGTH];
538 isc_uint32_t remain, deltae, count, total;
539 isc_uint8_t *buf;
540 isc_boolean_t goodonly, partial, blocking;
541
542 REQUIRE(VALID_ENTROPY(ent));
543 REQUIRE(data != NULL);
544 REQUIRE(length > 0);
545
546 goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
547 partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
548 blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
549
550 REQUIRE(!partial || returned != NULL);
551
552 LOCK(&ent->lock);
553
554 remain = length;
555 buf = data;
556 total = 0;
557 while (remain != 0) {
558 count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
559
560 /*
561 * If we are extracting good data only, make certain we
562 * have enough data in our pool for this pass. If we don't,
563 * get some, and fail if we can't, and partial returns
564 * are not ok.
565 */
566 if (goodonly) {
567 unsigned int fillcount;
568
569 fillcount = ISC_MAX(remain * 8, count * 8);
570
571 /*
572 * If, however, we have at least THRESHOLD_BITS
573 * of entropy in the pool, don't block here. It is
574 * better to drain the pool once in a while and
575 * then refill it than it is to constantly keep the
576 * pool full.
577 */
578 if (ent->pool.entropy >= THRESHOLD_BITS)
579 fillpool(ent, fillcount, ISC_FALSE);
580 else
581 fillpool(ent, fillcount, blocking);
582
583 /*
584 * Verify that we got enough entropy to do one
585 * extraction. If we didn't, bail.
586 */
587 if (ent->pool.entropy < THRESHOLD_BITS) {
588 if (!partial)
589 goto zeroize;
590 else
591 goto partial_output;
592 }
593 } else {
594 /*
595 * If we've extracted half our pool size in bits
596 * since the last refresh, try to refresh here.
597 */
598 if (ent->initialized < THRESHOLD_BITS)
599 fillpool(ent, THRESHOLD_BITS, blocking);
600 else
601 fillpool(ent, 0, ISC_FALSE);
602
603 /*
604 * If we've not initialized with enough good random
605 * data, seed with our crappy code.
606 */
607 if (ent->initialized < THRESHOLD_BITS)
608 reseed(ent);
609 }
610
611 isc_sha1_init(&hash);
612 isc_sha1_update(&hash, (void *)(ent->pool.pool),
613 RND_POOLBYTES);
614 isc_sha1_final(&hash, digest);
615
616 /*
617 * Stir the extracted data (all of it) back into the pool.
618 */
619 entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
620
621 for (i = 0; i < count; i++)
622 buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
623
624 buf += count;
625 remain -= count;
626
627 deltae = count * 8;
628 deltae = ISC_MIN(deltae, ent->pool.entropy);
629 total += deltae;
630 subtract_entropy(ent, deltae);
631 add_pseudo(ent, count * 8);
632 }
633
634 partial_output:
635 memset(digest, 0, sizeof(digest));
636
637 if (returned != NULL)
638 *returned = (length - remain);
639
640 UNLOCK(&ent->lock);
641
642 return (ISC_R_SUCCESS);
643
644 zeroize:
645 /* put the entropy we almost extracted back */
646 add_entropy(ent, total);
647 memset(data, 0, length);
648 memset(digest, 0, sizeof(digest));
649 if (returned != NULL)
650 *returned = 0;
651
652 UNLOCK(&ent->lock);
653
654 return (ISC_R_NOENTROPY);
655 }
656
657 static void
isc_entropypool_init(isc_entropypool_t * pool)658 isc_entropypool_init(isc_entropypool_t *pool) {
659 pool->cursor = RND_POOLWORDS - 1;
660 pool->entropy = 0;
661 pool->pseudo = 0;
662 pool->rotate = 0;
663 memset(pool->pool, 0, RND_POOLBYTES);
664 }
665
666 static void
isc_entropypool_invalidate(isc_entropypool_t * pool)667 isc_entropypool_invalidate(isc_entropypool_t *pool) {
668 pool->cursor = 0;
669 pool->entropy = 0;
670 pool->pseudo = 0;
671 pool->rotate = 0;
672 memset(pool->pool, 0, RND_POOLBYTES);
673 }
674
675 isc_result_t
isc_entropy_create(isc_mem_t * mctx,isc_entropy_t ** entp)676 isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
677 isc_result_t result;
678 isc_entropy_t *ent;
679
680 REQUIRE(mctx != NULL);
681 REQUIRE(entp != NULL && *entp == NULL);
682
683 ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
684 if (ent == NULL)
685 return (ISC_R_NOMEMORY);
686
687 /*
688 * We need a lock.
689 */
690 result = isc_mutex_init(&ent->lock);
691 if (result != ISC_R_SUCCESS)
692 goto errout;
693
694 /*
695 * From here down, no failures will/can occur.
696 */
697 ISC_LIST_INIT(ent->sources);
698 ent->nextsource = NULL;
699 ent->nsources = 0;
700 ent->mctx = NULL;
701 isc_mem_attach(mctx, &ent->mctx);
702 ent->refcnt = 1;
703 ent->initialized = 0;
704 ent->initcount = 0;
705 ent->magic = ENTROPY_MAGIC;
706
707 isc_entropypool_init(&ent->pool);
708
709 *entp = ent;
710 return (ISC_R_SUCCESS);
711
712 errout:
713 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
714
715 return (result);
716 }
717
718 /*!
719 * Requires "ent" be locked.
720 */
721 static void
destroysource(isc_entropysource_t ** sourcep)722 destroysource(isc_entropysource_t **sourcep) {
723 isc_entropysource_t *source;
724 isc_entropy_t *ent;
725 isc_cbsource_t *cbs;
726
727 source = *sourcep;
728 *sourcep = NULL;
729 ent = source->ent;
730
731 ISC_LIST_UNLINK(ent->sources, source, link);
732 ent->nextsource = NULL;
733 REQUIRE(ent->nsources > 0);
734 ent->nsources--;
735
736 switch (source->type) {
737 case ENTROPY_SOURCETYPE_FILE:
738 if (! source->bad)
739 destroyfilesource(&source->sources.file);
740 break;
741 case ENTROPY_SOURCETYPE_USOCKET:
742 if (! source->bad)
743 destroyusocketsource(&source->sources.usocket);
744 break;
745 case ENTROPY_SOURCETYPE_SAMPLE:
746 samplequeue_release(ent, &source->sources.sample.samplequeue);
747 break;
748 case ENTROPY_SOURCETYPE_CALLBACK:
749 cbs = &source->sources.callback;
750 if (cbs->start_called && cbs->stopfunc != NULL) {
751 cbs->stopfunc(source, cbs->arg);
752 cbs->start_called = ISC_FALSE;
753 }
754 samplequeue_release(ent, &cbs->samplequeue);
755 break;
756 }
757
758 memset(source, 0, sizeof(isc_entropysource_t));
759
760 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
761 }
762
763 static inline isc_boolean_t
destroy_check(isc_entropy_t * ent)764 destroy_check(isc_entropy_t *ent) {
765 isc_entropysource_t *source;
766
767 if (ent->refcnt > 0)
768 return (ISC_FALSE);
769
770 source = ISC_LIST_HEAD(ent->sources);
771 while (source != NULL) {
772 switch (source->type) {
773 case ENTROPY_SOURCETYPE_FILE:
774 case ENTROPY_SOURCETYPE_USOCKET:
775 break;
776 default:
777 return (ISC_FALSE);
778 }
779 source = ISC_LIST_NEXT(source, link);
780 }
781
782 return (ISC_TRUE);
783 }
784
785 static void
destroy(isc_entropy_t ** entp)786 destroy(isc_entropy_t **entp) {
787 isc_entropy_t *ent;
788 isc_entropysource_t *source;
789 isc_mem_t *mctx;
790
791 REQUIRE(entp != NULL && *entp != NULL);
792 ent = *entp;
793 *entp = NULL;
794
795 LOCK(&ent->lock);
796
797 REQUIRE(ent->refcnt == 0);
798
799 /*
800 * Here, detach non-sample sources.
801 */
802 source = ISC_LIST_HEAD(ent->sources);
803 while (source != NULL) {
804 switch(source->type) {
805 case ENTROPY_SOURCETYPE_FILE:
806 case ENTROPY_SOURCETYPE_USOCKET:
807 destroysource(&source);
808 break;
809 }
810 source = ISC_LIST_HEAD(ent->sources);
811 }
812
813 /*
814 * If there are other types of sources, we've found a bug.
815 */
816 REQUIRE(ISC_LIST_EMPTY(ent->sources));
817
818 mctx = ent->mctx;
819
820 isc_entropypool_invalidate(&ent->pool);
821
822 UNLOCK(&ent->lock);
823
824 DESTROYLOCK(&ent->lock);
825
826 memset(ent, 0, sizeof(isc_entropy_t));
827 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
828 isc_mem_detach(&mctx);
829 }
830
831 void
isc_entropy_destroysource(isc_entropysource_t ** sourcep)832 isc_entropy_destroysource(isc_entropysource_t **sourcep) {
833 isc_entropysource_t *source;
834 isc_entropy_t *ent;
835 isc_boolean_t killit;
836
837 REQUIRE(sourcep != NULL);
838 REQUIRE(VALID_SOURCE(*sourcep));
839
840 source = *sourcep;
841 *sourcep = NULL;
842
843 ent = source->ent;
844 REQUIRE(VALID_ENTROPY(ent));
845
846 LOCK(&ent->lock);
847
848 destroysource(&source);
849
850 killit = destroy_check(ent);
851
852 UNLOCK(&ent->lock);
853
854 if (killit)
855 destroy(&ent);
856 }
857
858 isc_result_t
isc_entropy_createcallbacksource(isc_entropy_t * ent,isc_entropystart_t start,isc_entropyget_t get,isc_entropystop_t stop,void * arg,isc_entropysource_t ** sourcep)859 isc_entropy_createcallbacksource(isc_entropy_t *ent,
860 isc_entropystart_t start,
861 isc_entropyget_t get,
862 isc_entropystop_t stop,
863 void *arg,
864 isc_entropysource_t **sourcep)
865 {
866 isc_result_t result;
867 isc_entropysource_t *source;
868 isc_cbsource_t *cbs;
869
870 REQUIRE(VALID_ENTROPY(ent));
871 REQUIRE(get != NULL);
872 REQUIRE(sourcep != NULL && *sourcep == NULL);
873
874 LOCK(&ent->lock);
875
876 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
877 if (source == NULL) {
878 result = ISC_R_NOMEMORY;
879 goto errout;
880 }
881 source->bad = ISC_FALSE;
882
883 cbs = &source->sources.callback;
884
885 result = samplesource_allocate(ent, &cbs->samplequeue);
886 if (result != ISC_R_SUCCESS)
887 goto errout;
888
889 cbs->start_called = ISC_FALSE;
890 cbs->startfunc = start;
891 cbs->getfunc = get;
892 cbs->stopfunc = stop;
893 cbs->arg = arg;
894
895 /*
896 * From here down, no failures can occur.
897 */
898 source->magic = SOURCE_MAGIC;
899 source->type = ENTROPY_SOURCETYPE_CALLBACK;
900 source->ent = ent;
901 source->total = 0;
902 memset(source->name, 0, sizeof(source->name));
903 ISC_LINK_INIT(source, link);
904
905 /*
906 * Hook it into the entropy system.
907 */
908 ISC_LIST_APPEND(ent->sources, source, link);
909 ent->nsources++;
910
911 *sourcep = source;
912
913 UNLOCK(&ent->lock);
914 return (ISC_R_SUCCESS);
915
916 errout:
917 if (source != NULL)
918 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
919
920 UNLOCK(&ent->lock);
921
922 return (result);
923 }
924
925 void
isc_entropy_stopcallbacksources(isc_entropy_t * ent)926 isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
927 isc_entropysource_t *source;
928 isc_cbsource_t *cbs;
929
930 REQUIRE(VALID_ENTROPY(ent));
931
932 LOCK(&ent->lock);
933
934 source = ISC_LIST_HEAD(ent->sources);
935 while (source != NULL) {
936 if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
937 cbs = &source->sources.callback;
938 if (cbs->start_called && cbs->stopfunc != NULL) {
939 cbs->stopfunc(source, cbs->arg);
940 cbs->start_called = ISC_FALSE;
941 }
942 }
943
944 source = ISC_LIST_NEXT(source, link);
945 }
946
947 UNLOCK(&ent->lock);
948 }
949
950 isc_result_t
isc_entropy_createsamplesource(isc_entropy_t * ent,isc_entropysource_t ** sourcep)951 isc_entropy_createsamplesource(isc_entropy_t *ent,
952 isc_entropysource_t **sourcep)
953 {
954 isc_result_t result;
955 isc_entropysource_t *source;
956 sample_queue_t *sq;
957
958 REQUIRE(VALID_ENTROPY(ent));
959 REQUIRE(sourcep != NULL && *sourcep == NULL);
960
961 LOCK(&ent->lock);
962
963 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
964 if (source == NULL) {
965 result = ISC_R_NOMEMORY;
966 goto errout;
967 }
968
969 sq = &source->sources.sample.samplequeue;
970 result = samplesource_allocate(ent, sq);
971 if (result != ISC_R_SUCCESS)
972 goto errout;
973
974 /*
975 * From here down, no failures can occur.
976 */
977 source->magic = SOURCE_MAGIC;
978 source->type = ENTROPY_SOURCETYPE_SAMPLE;
979 source->ent = ent;
980 source->total = 0;
981 memset(source->name, 0, sizeof(source->name));
982 ISC_LINK_INIT(source, link);
983
984 /*
985 * Hook it into the entropy system.
986 */
987 ISC_LIST_APPEND(ent->sources, source, link);
988 ent->nsources++;
989
990 *sourcep = source;
991
992 UNLOCK(&ent->lock);
993 return (ISC_R_SUCCESS);
994
995 errout:
996 if (source != NULL)
997 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
998
999 UNLOCK(&ent->lock);
1000
1001 return (result);
1002 }
1003
1004 /*!
1005 * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1006 * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1007 * queue was full when this function was called.
1008 */
1009 static isc_result_t
addsample(sample_queue_t * sq,isc_uint32_t sample,isc_uint32_t extra)1010 addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
1011 if (sq->nsamples >= RND_EVENTQSIZE)
1012 return (ISC_R_NOMORE);
1013
1014 sq->samples[sq->nsamples] = sample;
1015 sq->extra[sq->nsamples] = extra;
1016 sq->nsamples++;
1017
1018 if (sq->nsamples >= RND_EVENTQSIZE)
1019 return (ISC_R_QUEUEFULL);
1020
1021 return (ISC_R_SUCCESS);
1022 }
1023
1024 isc_result_t
isc_entropy_addsample(isc_entropysource_t * source,isc_uint32_t sample,isc_uint32_t extra)1025 isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
1026 isc_uint32_t extra)
1027 {
1028 isc_entropy_t *ent;
1029 sample_queue_t *sq;
1030 unsigned int entropy;
1031 isc_result_t result;
1032
1033 REQUIRE(VALID_SOURCE(source));
1034
1035 ent = source->ent;
1036
1037 LOCK(&ent->lock);
1038
1039 sq = &source->sources.sample.samplequeue;
1040 result = addsample(sq, sample, extra);
1041 if (result == ISC_R_QUEUEFULL) {
1042 entropy = crunchsamples(ent, sq);
1043 add_entropy(ent, entropy);
1044 }
1045
1046 UNLOCK(&ent->lock);
1047
1048 return (result);
1049 }
1050
1051 isc_result_t
isc_entropy_addcallbacksample(isc_entropysource_t * source,isc_uint32_t sample,isc_uint32_t extra)1052 isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
1053 isc_uint32_t extra)
1054 {
1055 sample_queue_t *sq;
1056 isc_result_t result;
1057
1058 REQUIRE(VALID_SOURCE(source));
1059 REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
1060
1061 sq = &source->sources.callback.samplequeue;
1062 result = addsample(sq, sample, extra);
1063
1064 return (result);
1065 }
1066
1067 void
isc_entropy_putdata(isc_entropy_t * ent,void * data,unsigned int length,isc_uint32_t entropy)1068 isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
1069 isc_uint32_t entropy)
1070 {
1071 REQUIRE(VALID_ENTROPY(ent));
1072
1073 LOCK(&ent->lock);
1074
1075 entropypool_adddata(ent, data, length, entropy);
1076
1077 if (ent->initialized < THRESHOLD_BITS)
1078 ent->initialized = THRESHOLD_BITS;
1079
1080 UNLOCK(&ent->lock);
1081 }
1082
1083 static void
dumpstats(isc_entropy_t * ent,FILE * out)1084 dumpstats(isc_entropy_t *ent, FILE *out) {
1085 fprintf(out,
1086 isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
1087 ISC_MSG_ENTROPYSTATS,
1088 "Entropy pool %p: refcnt %u cursor %u,"
1089 " rotate %u entropy %u pseudo %u nsources %u"
1090 " nextsource %p initialized %u initcount %u\n"),
1091 ent, ent->refcnt,
1092 ent->pool.cursor, ent->pool.rotate,
1093 ent->pool.entropy, ent->pool.pseudo,
1094 ent->nsources, ent->nextsource, ent->initialized,
1095 ent->initcount);
1096 }
1097
1098 /*
1099 * This function ignores locking. Use at your own risk.
1100 */
1101 void
isc_entropy_stats(isc_entropy_t * ent,FILE * out)1102 isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
1103 REQUIRE(VALID_ENTROPY(ent));
1104
1105 LOCK(&ent->lock);
1106 dumpstats(ent, out);
1107 UNLOCK(&ent->lock);
1108 }
1109
1110 unsigned int
isc_entropy_status(isc_entropy_t * ent)1111 isc_entropy_status(isc_entropy_t *ent) {
1112 unsigned int estimate;
1113
1114 LOCK(&ent->lock);
1115 estimate = ent->pool.entropy;
1116 UNLOCK(&ent->lock);
1117
1118 return estimate;
1119 }
1120
1121 void
isc_entropy_attach(isc_entropy_t * ent,isc_entropy_t ** entp)1122 isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
1123 REQUIRE(VALID_ENTROPY(ent));
1124 REQUIRE(entp != NULL && *entp == NULL);
1125
1126 LOCK(&ent->lock);
1127
1128 ent->refcnt++;
1129 *entp = ent;
1130
1131 UNLOCK(&ent->lock);
1132 }
1133
1134 void
isc_entropy_detach(isc_entropy_t ** entp)1135 isc_entropy_detach(isc_entropy_t **entp) {
1136 isc_entropy_t *ent;
1137 isc_boolean_t killit;
1138
1139 REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
1140 ent = *entp;
1141 *entp = NULL;
1142
1143 LOCK(&ent->lock);
1144
1145 REQUIRE(ent->refcnt > 0);
1146 ent->refcnt--;
1147
1148 killit = destroy_check(ent);
1149
1150 UNLOCK(&ent->lock);
1151
1152 if (killit)
1153 destroy(&ent);
1154 }
1155
1156 static isc_result_t
kbdstart(isc_entropysource_t * source,void * arg,isc_boolean_t blocking)1157 kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1158 /*
1159 * The intent of "first" is to provide a warning message only once
1160 * during the run of a program that might try to gather keyboard
1161 * entropy multiple times.
1162 */
1163 static isc_boolean_t first = ISC_TRUE;
1164
1165 UNUSED(arg);
1166
1167 if (! blocking)
1168 return (ISC_R_NOENTROPY);
1169
1170 if (first) {
1171 if (source->warn_keyboard)
1172 fprintf(stderr, "You must use the keyboard to create "
1173 "entropy, since your system is lacking\n"
1174 "/dev/random (or equivalent)\n\n");
1175 first = ISC_FALSE;
1176 }
1177 fprintf(stderr, "start typing:\n");
1178
1179 return (isc_keyboard_open(&source->kbd));
1180 }
1181
1182 static void
kbdstop(isc_entropysource_t * source,void * arg)1183 kbdstop(isc_entropysource_t *source, void *arg) {
1184
1185 UNUSED(arg);
1186
1187 if (! isc_keyboard_canceled(&source->kbd))
1188 fprintf(stderr, "stop typing.\r\n");
1189
1190 (void)isc_keyboard_close(&source->kbd, 3);
1191 }
1192
1193 static isc_result_t
kbdget(isc_entropysource_t * source,void * arg,isc_boolean_t blocking)1194 kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1195 isc_result_t result;
1196 isc_time_t t;
1197 isc_uint32_t sample;
1198 isc_uint32_t extra;
1199 unsigned char c;
1200
1201 UNUSED(arg);
1202
1203 if (!blocking)
1204 return (ISC_R_NOTBLOCKING);
1205
1206 result = isc_keyboard_getchar(&source->kbd, &c);
1207 if (result != ISC_R_SUCCESS)
1208 return (result);
1209
1210 TIME_NOW(&t);
1211
1212 sample = isc_time_nanoseconds(&t);
1213 extra = c;
1214
1215 result = isc_entropy_addcallbacksample(source, sample, extra);
1216 if (result != ISC_R_SUCCESS) {
1217 fprintf(stderr, "\r\n");
1218 return (result);
1219 }
1220
1221 fprintf(stderr, ".");
1222 fflush(stderr);
1223
1224 return (result);
1225 }
1226
1227 isc_result_t
isc_entropy_usebestsource(isc_entropy_t * ectx,isc_entropysource_t ** source,const char * randomfile,int use_keyboard)1228 isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
1229 const char *randomfile, int use_keyboard)
1230 {
1231 isc_result_t result;
1232 isc_result_t final_result = ISC_R_NOENTROPY;
1233 isc_boolean_t userfile = ISC_TRUE;
1234
1235 REQUIRE(VALID_ENTROPY(ectx));
1236 REQUIRE(source != NULL && *source == NULL);
1237 REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
1238 use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
1239 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
1240
1241 #ifdef PATH_RANDOMDEV
1242 if (randomfile == NULL) {
1243 randomfile = PATH_RANDOMDEV;
1244 userfile = ISC_FALSE;
1245 }
1246 #endif
1247
1248 if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
1249 result = isc_entropy_createfilesource(ectx, randomfile);
1250 if (result == ISC_R_SUCCESS &&
1251 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
1252 use_keyboard = ISC_ENTROPY_KEYBOARDNO;
1253 if (result != ISC_R_SUCCESS && userfile)
1254 return (result);
1255
1256 final_result = result;
1257 }
1258
1259 if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
1260 result = isc_entropy_createcallbacksource(ectx, kbdstart,
1261 kbdget, kbdstop,
1262 NULL, source);
1263 if (result == ISC_R_SUCCESS)
1264 (*source)->warn_keyboard =
1265 ISC_TF(use_keyboard ==
1266 ISC_ENTROPY_KEYBOARDMAYBE);
1267
1268 if (final_result != ISC_R_SUCCESS)
1269 final_result = result;
1270 }
1271
1272 /*
1273 * final_result is ISC_R_SUCCESS if at least one source of entropy
1274 * could be started, otherwise it is the error from the most recently
1275 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1276 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1277 */
1278 return (final_result);
1279 }
1280