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 */ 94typedef 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 102struct 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 */ 116typedef 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 125typedef struct { 126 sample_queue_t samplequeue; 127} isc_entropysamplesource_t; 128 129typedef 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 138typedef struct { 139 FILESOURCE_HANDLE_TYPE handle; 140} isc_entropyfilesource_t; 141 142struct 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 */ 181static void 182fillpool(isc_entropy_t *, unsigned int, isc_boolean_t); 183 184static int 185wait_for_sources(isc_entropy_t *); 186 187static void 188destroyfilesource(isc_entropyfilesource_t *source); 189 190static void 191destroyusocketsource(isc_entropyusocketsource_t *source); 192 193/*@}*/ 194 195static void 196samplequeue_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 206static isc_result_t 207samplesource_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 */ 228static inline void 229add_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 */ 241static inline void 242subtract_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 */ 251static inline void 252add_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 */ 264static inline void 265subtract_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 */ 273static inline void 274entropypool_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 */ 313static void 314entropypool_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 366static inline void 367reseed(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 392static inline unsigned int 393estimate_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 439static unsigned int 440crunchsamples(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 479static unsigned int 480get_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 */ 531isc_result_t 532isc_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 657static void 658isc_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 666static void 667isc_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 675isc_result_t 676isc_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 */ 721static void 722destroysource(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 763static inline isc_boolean_t 764destroy_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 785static void 786destroy(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 831void 832isc_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 858isc_result_t 859isc_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 925void 926isc_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 950isc_result_t 951isc_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 */ 1009static isc_result_t 1010addsample(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 1024isc_result_t 1025isc_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 1051isc_result_t 1052isc_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 1067void 1068isc_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 1083static void 1084dumpstats(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 */ 1101void 1102isc_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 1110unsigned int 1111isc_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 1121void 1122isc_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 1134void 1135isc_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 1156static isc_result_t 1157kbdstart(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 1182static void 1183kbdstop(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 1193static isc_result_t 1194kbdget(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 1227isc_result_t 1228isc_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