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