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