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