00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <errno.h>
00031 #include <fcntl.h>
00032 #include <stdio.h>
00033
00034 #include <isc/buffer.h>
00035 #include <isc/entropy.h>
00036 #include <isc/keyboard.h>
00037 #include <isc/list.h>
00038 #include <isc/magic.h>
00039 #include <isc/mem.h>
00040 #include <isc/msgs.h>
00041 #include <isc/mutex.h>
00042 #include <isc/platform.h>
00043 #include <isc/region.h>
00044 #include <isc/sha1.h>
00045 #include <isc/string.h>
00046 #include <isc/time.h>
00047 #include <isc/util.h>
00048
00049 #ifdef PKCS11CRYPTO
00050 #include <pk11/pk11.h>
00051 #endif
00052
00053 #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
00054 #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
00055
00056 #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
00057 #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 #define RND_POOLWORDS 128
00068
00069 #define RND_POOLBYTES (RND_POOLWORDS * 4)
00070
00071 #define RND_POOLBITS (RND_POOLWORDS * 32)
00072
00073
00074
00075
00076
00077 #define RND_ENTROPY_THRESHOLD 10
00078 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
00079
00080
00081
00082
00083 #define RND_EVENTQSIZE 32
00084
00085
00086
00087
00088
00089
00090
00091
00092 #define RND_INITIALIZE 128
00093
00094
00095 typedef struct {
00096 isc_uint32_t cursor;
00097 isc_uint32_t entropy;
00098 isc_uint32_t pseudo;
00099 isc_uint32_t rotate;
00100 isc_uint32_t pool[RND_POOLWORDS];
00101 } isc_entropypool_t;
00102
00103 struct isc_entropy {
00104 unsigned int magic;
00105 isc_mem_t *mctx;
00106 isc_mutex_t lock;
00107 unsigned int refcnt;
00108 isc_uint32_t initialized;
00109 isc_uint32_t initcount;
00110 isc_entropypool_t pool;
00111 unsigned int nsources;
00112 isc_entropysource_t *nextsource;
00113 ISC_LIST(isc_entropysource_t) sources;
00114 };
00115
00116
00117 typedef struct {
00118 isc_uint32_t last_time;
00119 isc_uint32_t last_delta;
00120 isc_uint32_t last_delta2;
00121 isc_uint32_t nsamples;
00122 isc_uint32_t *samples;
00123 isc_uint32_t *extra;
00124 } sample_queue_t;
00125
00126 typedef struct {
00127 sample_queue_t samplequeue;
00128 } isc_entropysamplesource_t;
00129
00130 typedef struct {
00131 isc_boolean_t start_called;
00132 isc_entropystart_t startfunc;
00133 isc_entropyget_t getfunc;
00134 isc_entropystop_t stopfunc;
00135 void *arg;
00136 sample_queue_t samplequeue;
00137 } isc_cbsource_t;
00138
00139 typedef struct {
00140 FILESOURCE_HANDLE_TYPE handle;
00141 } isc_entropyfilesource_t;
00142
00143 struct isc_entropysource {
00144 unsigned int magic;
00145 unsigned int type;
00146 isc_entropy_t *ent;
00147 isc_uint32_t total;
00148 ISC_LINK(isc_entropysource_t) link;
00149 char name[32];
00150 isc_boolean_t bad;
00151 isc_boolean_t warn_keyboard;
00152 isc_keyboard_t kbd;
00153 union {
00154 isc_entropysamplesource_t sample;
00155 isc_entropyfilesource_t file;
00156 isc_cbsource_t callback;
00157 isc_entropyusocketsource_t usocket;
00158 } sources;
00159 };
00160
00161 #define ENTROPY_SOURCETYPE_SAMPLE 1
00162 #define ENTROPY_SOURCETYPE_FILE 2
00163 #define ENTROPY_SOURCETYPE_CALLBACK 3
00164 #define ENTROPY_SOURCETYPE_USOCKET 4
00165
00166
00167
00168
00169
00170 #define TAP1 99
00171 #define TAP2 59
00172 #define TAP3 31
00173 #define TAP4 9
00174 #define TAP5 7
00175
00176
00177
00178
00179
00180
00181
00182 static void
00183 fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
00184
00185 static int
00186 wait_for_sources(isc_entropy_t *);
00187
00188 static void
00189 destroyfilesource(isc_entropyfilesource_t *source);
00190
00191 static void
00192 destroyusocketsource(isc_entropyusocketsource_t *source);
00193
00194
00195
00196 static void
00197 samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
00198 REQUIRE(sq->samples != NULL);
00199 REQUIRE(sq->extra != NULL);
00200
00201 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
00202 isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
00203 sq->samples = NULL;
00204 sq->extra = NULL;
00205 }
00206
00207 static isc_result_t
00208 samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
00209 sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
00210 if (sq->samples == NULL)
00211 return (ISC_R_NOMEMORY);
00212
00213 sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
00214 if (sq->extra == NULL) {
00215 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
00216 sq->samples = NULL;
00217 return (ISC_R_NOMEMORY);
00218 }
00219
00220 sq->nsamples = 0;
00221
00222 return (ISC_R_SUCCESS);
00223 }
00224
00225
00226
00227
00228
00229 static inline void
00230 add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
00231
00232 entropy = ISC_MIN(entropy, RND_POOLBITS);
00233
00234 entropy += ent->pool.entropy;
00235
00236 ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
00237 }
00238
00239
00240
00241
00242 static inline void
00243 subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
00244 entropy = ISC_MIN(entropy, ent->pool.entropy);
00245 ent->pool.entropy -= entropy;
00246 }
00247
00248
00249
00250
00251
00252 static inline void
00253 add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
00254
00255 pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
00256
00257 pseudo += ent->pool.pseudo;
00258
00259 ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
00260 }
00261
00262
00263
00264
00265 static inline void
00266 subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
00267 pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
00268 ent->pool.pseudo -= pseudo;
00269 }
00270
00271
00272
00273
00274 static inline void
00275 entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
00276
00277
00278
00279
00280
00281
00282
00283
00284 val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
00285 val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
00286 val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
00287 val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
00288 val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
00289 if (rp->rotate == 0)
00290 rp->pool[rp->cursor++] ^= val;
00291 else
00292 rp->pool[rp->cursor++] ^=
00293 ((val << rp->rotate) | (val >> (32 - rp->rotate)));
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 if (rp->cursor == RND_POOLWORDS) {
00304 rp->cursor = 0;
00305 rp->rotate = (rp->rotate + 7) & 31;
00306 }
00307 }
00308
00309
00310
00311
00312
00313
00314 static void
00315 entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
00316 isc_uint32_t entropy)
00317 {
00318 isc_uint32_t val;
00319 unsigned long addr;
00320 isc_uint8_t *buf;
00321
00322
00323 #ifdef _WIN64
00324 addr = (unsigned long)((unsigned long long)p);
00325 #else
00326 addr = (unsigned long)p;
00327 #endif
00328 buf = p;
00329
00330 if ((addr & 0x03U) != 0U) {
00331 val = 0;
00332 switch (len) {
00333 case 3:
00334 val = *buf++;
00335 len--;
00336 case 2:
00337 val = val << 8 | *buf++;
00338 len--;
00339 case 1:
00340 val = val << 8 | *buf++;
00341 len--;
00342 }
00343
00344 entropypool_add_word(&ent->pool, val);
00345 }
00346
00347 for (; len > 3; len -= 4) {
00348 val = *((isc_uint32_t *)buf);
00349
00350 entropypool_add_word(&ent->pool, val);
00351 buf += 4;
00352 }
00353
00354 if (len != 0) {
00355 val = 0;
00356 switch (len) {
00357 case 3:
00358 val = *buf++;
00359 case 2:
00360 val = val << 8 | *buf++;
00361 case 1:
00362 val = val << 8 | *buf++;
00363 }
00364
00365 entropypool_add_word(&ent->pool, val);
00366 }
00367
00368 add_entropy(ent, entropy);
00369 subtract_pseudo(ent, entropy);
00370 }
00371
00372 static inline void
00373 reseed(isc_entropy_t *ent) {
00374 isc_time_t t;
00375 pid_t pid;
00376
00377 if (ent->initcount == 0) {
00378 pid = getpid();
00379 entropypool_adddata(ent, &pid, sizeof(pid), 0);
00380 pid = getppid();
00381 entropypool_adddata(ent, &pid, sizeof(pid), 0);
00382 }
00383
00384
00385
00386
00387
00388
00389 if (ent->initcount > 100)
00390 if ((ent->initcount % 50) != 0)
00391 return;
00392
00393 TIME_NOW(&t);
00394 entropypool_adddata(ent, &t, sizeof(t), 0);
00395 ent->initcount++;
00396 }
00397
00398 static inline unsigned int
00399 estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
00400 isc_int32_t delta;
00401 isc_int32_t delta2;
00402 isc_int32_t delta3;
00403
00404
00405
00406
00407
00408 if (t < sq->last_time)
00409 delta = UINT_MAX - sq->last_time + t;
00410 else
00411 delta = sq->last_time - t;
00412
00413 if (delta < 0)
00414 delta = -delta;
00415
00416
00417
00418
00419 delta2 = sq->last_delta - delta;
00420 if (delta2 < 0)
00421 delta2 = -delta2;
00422
00423 delta3 = sq->last_delta2 - delta2;
00424 if (delta3 < 0)
00425 delta3 = -delta3;
00426
00427 sq->last_time = t;
00428 sq->last_delta = delta;
00429 sq->last_delta2 = delta2;
00430
00431
00432
00433
00434
00435 if (delta == 0 || delta2 == 0 || delta3 == 0)
00436 return 0;
00437
00438
00439
00440
00441
00442 return 1;
00443 }
00444
00445 static unsigned int
00446 crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
00447 unsigned int ns;
00448 unsigned int added;
00449
00450 if (sq->nsamples < 6)
00451 return (0);
00452
00453 added = 0;
00454 sq->last_time = sq->samples[0];
00455 sq->last_delta = 0;
00456 sq->last_delta2 = 0;
00457
00458
00459
00460
00461
00462 for (ns = 0; ns < 4; ns++)
00463 (void)estimate_entropy(sq, sq->samples[ns]);
00464
00465 for (ns = 4; ns < sq->nsamples; ns++)
00466 added += estimate_entropy(sq, sq->samples[ns]);
00467
00468 entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
00469 entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
00470
00471
00472
00473
00474
00475 for (ns = 0; ns < 4; ns++) {
00476 sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
00477 sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
00478 }
00479
00480 sq->nsamples = 4;
00481
00482 return (added);
00483 }
00484
00485 static unsigned int
00486 get_from_callback(isc_entropysource_t *source, unsigned int desired,
00487 isc_boolean_t blocking)
00488 {
00489 isc_entropy_t *ent = source->ent;
00490 isc_cbsource_t *cbs = &source->sources.callback;
00491 unsigned int added;
00492 unsigned int got;
00493 isc_result_t result;
00494
00495 if (desired == 0)
00496 return (0);
00497
00498 if (source->bad)
00499 return (0);
00500
00501 if (!cbs->start_called && cbs->startfunc != NULL) {
00502 result = cbs->startfunc(source, cbs->arg, blocking);
00503 if (result != ISC_R_SUCCESS)
00504 return (0);
00505 cbs->start_called = ISC_TRUE;
00506 }
00507
00508 added = 0;
00509 result = ISC_R_SUCCESS;
00510 while (desired > 0 && result == ISC_R_SUCCESS) {
00511 result = cbs->getfunc(source, cbs->arg, blocking);
00512 if (result == ISC_R_QUEUEFULL) {
00513 got = crunchsamples(ent, &cbs->samplequeue);
00514 added += got;
00515 desired -= ISC_MIN(got, desired);
00516 result = ISC_R_SUCCESS;
00517 } else if (result != ISC_R_SUCCESS &&
00518 result != ISC_R_NOTBLOCKING)
00519 source->bad = ISC_TRUE;
00520
00521 }
00522
00523 return (added);
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537 isc_result_t
00538 isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
00539 unsigned int *returned, unsigned int flags)
00540 {
00541 unsigned int i;
00542 isc_sha1_t hash;
00543 unsigned char digest[ISC_SHA1_DIGESTLENGTH];
00544 isc_uint32_t remain, deltae, count, total;
00545 isc_uint8_t *buf;
00546 isc_boolean_t goodonly, partial, blocking;
00547
00548 REQUIRE(VALID_ENTROPY(ent));
00549 REQUIRE(data != NULL);
00550 REQUIRE(length > 0);
00551
00552 goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
00553 partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
00554 blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
00555
00556 REQUIRE(!partial || returned != NULL);
00557
00558 LOCK(&ent->lock);
00559
00560 remain = length;
00561 buf = data;
00562 total = 0;
00563 while (remain != 0) {
00564 count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
00565
00566
00567
00568
00569
00570
00571
00572 if (goodonly) {
00573 unsigned int fillcount;
00574
00575 fillcount = ISC_MAX(remain * 8, count * 8);
00576
00577
00578
00579
00580
00581
00582
00583
00584 if (ent->pool.entropy >= THRESHOLD_BITS)
00585 fillpool(ent, fillcount, ISC_FALSE);
00586 else
00587 fillpool(ent, fillcount, blocking);
00588
00589
00590
00591
00592
00593 if (ent->pool.entropy < THRESHOLD_BITS) {
00594 if (!partial)
00595 goto zeroize;
00596 else
00597 goto partial_output;
00598 }
00599 } else {
00600
00601
00602
00603
00604 if (ent->initialized < THRESHOLD_BITS)
00605 fillpool(ent, THRESHOLD_BITS, blocking);
00606 else
00607 fillpool(ent, 0, ISC_FALSE);
00608
00609
00610
00611
00612
00613 if (ent->initialized < THRESHOLD_BITS)
00614 reseed(ent);
00615 }
00616
00617 isc_sha1_init(&hash);
00618 isc_sha1_update(&hash, (void *)(ent->pool.pool),
00619 RND_POOLBYTES);
00620 isc_sha1_final(&hash, digest);
00621
00622
00623
00624
00625 entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
00626
00627 for (i = 0; i < count; i++)
00628 buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
00629
00630 buf += count;
00631 remain -= count;
00632
00633 deltae = count * 8;
00634 deltae = ISC_MIN(deltae, ent->pool.entropy);
00635 total += deltae;
00636 subtract_entropy(ent, deltae);
00637 add_pseudo(ent, count * 8);
00638 }
00639
00640 partial_output:
00641 memset(digest, 0, sizeof(digest));
00642
00643 if (returned != NULL)
00644 *returned = (length - remain);
00645
00646 UNLOCK(&ent->lock);
00647
00648 return (ISC_R_SUCCESS);
00649
00650 zeroize:
00651
00652 add_entropy(ent, total);
00653 memset(data, 0, length);
00654 memset(digest, 0, sizeof(digest));
00655 if (returned != NULL)
00656 *returned = 0;
00657
00658 UNLOCK(&ent->lock);
00659
00660 return (ISC_R_NOENTROPY);
00661 }
00662
00663 static void
00664 isc_entropypool_init(isc_entropypool_t *pool) {
00665 pool->cursor = RND_POOLWORDS - 1;
00666 pool->entropy = 0;
00667 pool->pseudo = 0;
00668 pool->rotate = 0;
00669 memset(pool->pool, 0, RND_POOLBYTES);
00670 }
00671
00672 static void
00673 isc_entropypool_invalidate(isc_entropypool_t *pool) {
00674 pool->cursor = 0;
00675 pool->entropy = 0;
00676 pool->pseudo = 0;
00677 pool->rotate = 0;
00678 memset(pool->pool, 0, RND_POOLBYTES);
00679 }
00680
00681 isc_result_t
00682 isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
00683 isc_result_t result;
00684 isc_entropy_t *ent;
00685
00686 REQUIRE(mctx != NULL);
00687 REQUIRE(entp != NULL && *entp == NULL);
00688
00689 ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
00690 if (ent == NULL)
00691 return (ISC_R_NOMEMORY);
00692
00693
00694
00695
00696 result = isc_mutex_init(&ent->lock);
00697 if (result != ISC_R_SUCCESS)
00698 goto errout;
00699
00700
00701
00702
00703 ISC_LIST_INIT(ent->sources);
00704 ent->nextsource = NULL;
00705 ent->nsources = 0;
00706 ent->mctx = NULL;
00707 isc_mem_attach(mctx, &ent->mctx);
00708 ent->refcnt = 1;
00709 ent->initialized = 0;
00710 ent->initcount = 0;
00711 ent->magic = ENTROPY_MAGIC;
00712
00713 isc_entropypool_init(&ent->pool);
00714
00715 *entp = ent;
00716 return (ISC_R_SUCCESS);
00717
00718 errout:
00719 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
00720
00721 return (result);
00722 }
00723
00724
00725
00726
00727 static void
00728 destroysource(isc_entropysource_t **sourcep) {
00729 isc_entropysource_t *source;
00730 isc_entropy_t *ent;
00731 isc_cbsource_t *cbs;
00732
00733 source = *sourcep;
00734 *sourcep = NULL;
00735 ent = source->ent;
00736
00737 ISC_LIST_UNLINK(ent->sources, source, link);
00738 ent->nextsource = NULL;
00739 REQUIRE(ent->nsources > 0);
00740 ent->nsources--;
00741
00742 switch (source->type) {
00743 case ENTROPY_SOURCETYPE_FILE:
00744 if (! source->bad)
00745 destroyfilesource(&source->sources.file);
00746 break;
00747 case ENTROPY_SOURCETYPE_USOCKET:
00748 if (! source->bad)
00749 destroyusocketsource(&source->sources.usocket);
00750 break;
00751 case ENTROPY_SOURCETYPE_SAMPLE:
00752 samplequeue_release(ent, &source->sources.sample.samplequeue);
00753 break;
00754 case ENTROPY_SOURCETYPE_CALLBACK:
00755 cbs = &source->sources.callback;
00756 if (cbs->start_called && cbs->stopfunc != NULL) {
00757 cbs->stopfunc(source, cbs->arg);
00758 cbs->start_called = ISC_FALSE;
00759 }
00760 samplequeue_release(ent, &cbs->samplequeue);
00761 break;
00762 }
00763
00764 memset(source, 0, sizeof(isc_entropysource_t));
00765
00766 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
00767 }
00768
00769 static inline isc_boolean_t
00770 destroy_check(isc_entropy_t *ent) {
00771 isc_entropysource_t *source;
00772
00773 if (ent->refcnt > 0)
00774 return (ISC_FALSE);
00775
00776 source = ISC_LIST_HEAD(ent->sources);
00777 while (source != NULL) {
00778 switch (source->type) {
00779 case ENTROPY_SOURCETYPE_FILE:
00780 case ENTROPY_SOURCETYPE_USOCKET:
00781 break;
00782 default:
00783 return (ISC_FALSE);
00784 }
00785 source = ISC_LIST_NEXT(source, link);
00786 }
00787
00788 return (ISC_TRUE);
00789 }
00790
00791 static void
00792 destroy(isc_entropy_t **entp) {
00793 isc_entropy_t *ent;
00794 isc_entropysource_t *source;
00795 isc_mem_t *mctx;
00796
00797 REQUIRE(entp != NULL && *entp != NULL);
00798 ent = *entp;
00799 *entp = NULL;
00800
00801 LOCK(&ent->lock);
00802
00803 REQUIRE(ent->refcnt == 0);
00804
00805
00806
00807
00808 source = ISC_LIST_HEAD(ent->sources);
00809 while (source != NULL) {
00810 switch(source->type) {
00811 case ENTROPY_SOURCETYPE_FILE:
00812 case ENTROPY_SOURCETYPE_USOCKET:
00813 destroysource(&source);
00814 break;
00815 }
00816 source = ISC_LIST_HEAD(ent->sources);
00817 }
00818
00819
00820
00821
00822 REQUIRE(ISC_LIST_EMPTY(ent->sources));
00823
00824 mctx = ent->mctx;
00825
00826 isc_entropypool_invalidate(&ent->pool);
00827
00828 UNLOCK(&ent->lock);
00829
00830 DESTROYLOCK(&ent->lock);
00831
00832 memset(ent, 0, sizeof(isc_entropy_t));
00833 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
00834 isc_mem_detach(&mctx);
00835 }
00836
00837 void
00838 isc_entropy_destroysource(isc_entropysource_t **sourcep) {
00839 isc_entropysource_t *source;
00840 isc_entropy_t *ent;
00841 isc_boolean_t killit;
00842
00843 REQUIRE(sourcep != NULL);
00844 REQUIRE(VALID_SOURCE(*sourcep));
00845
00846 source = *sourcep;
00847 *sourcep = NULL;
00848
00849 ent = source->ent;
00850 REQUIRE(VALID_ENTROPY(ent));
00851
00852 LOCK(&ent->lock);
00853
00854 destroysource(&source);
00855
00856 killit = destroy_check(ent);
00857
00858 UNLOCK(&ent->lock);
00859
00860 if (killit)
00861 destroy(&ent);
00862 }
00863
00864 isc_result_t
00865 isc_entropy_createcallbacksource(isc_entropy_t *ent,
00866 isc_entropystart_t start,
00867 isc_entropyget_t get,
00868 isc_entropystop_t stop,
00869 void *arg,
00870 isc_entropysource_t **sourcep)
00871 {
00872 isc_result_t result;
00873 isc_entropysource_t *source;
00874 isc_cbsource_t *cbs;
00875
00876 REQUIRE(VALID_ENTROPY(ent));
00877 REQUIRE(get != NULL);
00878 REQUIRE(sourcep != NULL && *sourcep == NULL);
00879
00880 LOCK(&ent->lock);
00881
00882 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
00883 if (source == NULL) {
00884 result = ISC_R_NOMEMORY;
00885 goto errout;
00886 }
00887 source->bad = ISC_FALSE;
00888
00889 cbs = &source->sources.callback;
00890
00891 result = samplesource_allocate(ent, &cbs->samplequeue);
00892 if (result != ISC_R_SUCCESS)
00893 goto errout;
00894
00895 cbs->start_called = ISC_FALSE;
00896 cbs->startfunc = start;
00897 cbs->getfunc = get;
00898 cbs->stopfunc = stop;
00899 cbs->arg = arg;
00900
00901
00902
00903
00904 source->magic = SOURCE_MAGIC;
00905 source->type = ENTROPY_SOURCETYPE_CALLBACK;
00906 source->ent = ent;
00907 source->total = 0;
00908 memset(source->name, 0, sizeof(source->name));
00909 ISC_LINK_INIT(source, link);
00910
00911
00912
00913
00914 ISC_LIST_APPEND(ent->sources, source, link);
00915 ent->nsources++;
00916
00917 *sourcep = source;
00918
00919 UNLOCK(&ent->lock);
00920 return (ISC_R_SUCCESS);
00921
00922 errout:
00923 if (source != NULL)
00924 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
00925
00926 UNLOCK(&ent->lock);
00927
00928 return (result);
00929 }
00930
00931 void
00932 isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
00933 isc_entropysource_t *source;
00934 isc_cbsource_t *cbs;
00935
00936 REQUIRE(VALID_ENTROPY(ent));
00937
00938 LOCK(&ent->lock);
00939
00940 source = ISC_LIST_HEAD(ent->sources);
00941 while (source != NULL) {
00942 if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
00943 cbs = &source->sources.callback;
00944 if (cbs->start_called && cbs->stopfunc != NULL) {
00945 cbs->stopfunc(source, cbs->arg);
00946 cbs->start_called = ISC_FALSE;
00947 }
00948 }
00949
00950 source = ISC_LIST_NEXT(source, link);
00951 }
00952
00953 UNLOCK(&ent->lock);
00954 }
00955
00956 isc_result_t
00957 isc_entropy_createsamplesource(isc_entropy_t *ent,
00958 isc_entropysource_t **sourcep)
00959 {
00960 isc_result_t result;
00961 isc_entropysource_t *source;
00962 sample_queue_t *sq;
00963
00964 REQUIRE(VALID_ENTROPY(ent));
00965 REQUIRE(sourcep != NULL && *sourcep == NULL);
00966
00967 LOCK(&ent->lock);
00968
00969 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
00970 if (source == NULL) {
00971 result = ISC_R_NOMEMORY;
00972 goto errout;
00973 }
00974
00975 sq = &source->sources.sample.samplequeue;
00976 result = samplesource_allocate(ent, sq);
00977 if (result != ISC_R_SUCCESS)
00978 goto errout;
00979
00980
00981
00982
00983 source->magic = SOURCE_MAGIC;
00984 source->type = ENTROPY_SOURCETYPE_SAMPLE;
00985 source->ent = ent;
00986 source->total = 0;
00987 memset(source->name, 0, sizeof(source->name));
00988 ISC_LINK_INIT(source, link);
00989
00990
00991
00992
00993 ISC_LIST_APPEND(ent->sources, source, link);
00994 ent->nsources++;
00995
00996 *sourcep = source;
00997
00998 UNLOCK(&ent->lock);
00999 return (ISC_R_SUCCESS);
01000
01001 errout:
01002 if (source != NULL)
01003 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
01004
01005 UNLOCK(&ent->lock);
01006
01007 return (result);
01008 }
01009
01010
01011
01012
01013
01014
01015 static isc_result_t
01016 addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
01017 if (sq->nsamples >= RND_EVENTQSIZE)
01018 return (ISC_R_NOMORE);
01019
01020 sq->samples[sq->nsamples] = sample;
01021 sq->extra[sq->nsamples] = extra;
01022 sq->nsamples++;
01023
01024 if (sq->nsamples >= RND_EVENTQSIZE)
01025 return (ISC_R_QUEUEFULL);
01026
01027 return (ISC_R_SUCCESS);
01028 }
01029
01030 isc_result_t
01031 isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
01032 isc_uint32_t extra)
01033 {
01034 isc_entropy_t *ent;
01035 sample_queue_t *sq;
01036 unsigned int entropy;
01037 isc_result_t result;
01038
01039 REQUIRE(VALID_SOURCE(source));
01040
01041 ent = source->ent;
01042
01043 LOCK(&ent->lock);
01044
01045 sq = &source->sources.sample.samplequeue;
01046 result = addsample(sq, sample, extra);
01047 if (result == ISC_R_QUEUEFULL) {
01048 entropy = crunchsamples(ent, sq);
01049 add_entropy(ent, entropy);
01050 }
01051
01052 UNLOCK(&ent->lock);
01053
01054 return (result);
01055 }
01056
01057 isc_result_t
01058 isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
01059 isc_uint32_t extra)
01060 {
01061 sample_queue_t *sq;
01062 isc_result_t result;
01063
01064 REQUIRE(VALID_SOURCE(source));
01065 REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
01066
01067 sq = &source->sources.callback.samplequeue;
01068 result = addsample(sq, sample, extra);
01069
01070 return (result);
01071 }
01072
01073 void
01074 isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
01075 isc_uint32_t entropy)
01076 {
01077 REQUIRE(VALID_ENTROPY(ent));
01078
01079 LOCK(&ent->lock);
01080
01081 entropypool_adddata(ent, data, length, entropy);
01082
01083 if (ent->initialized < THRESHOLD_BITS)
01084 ent->initialized = THRESHOLD_BITS;
01085
01086 UNLOCK(&ent->lock);
01087 }
01088
01089 static void
01090 dumpstats(isc_entropy_t *ent, FILE *out) {
01091 fprintf(out,
01092 isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
01093 ISC_MSG_ENTROPYSTATS,
01094 "Entropy pool %p: refcnt %u cursor %u,"
01095 " rotate %u entropy %u pseudo %u nsources %u"
01096 " nextsource %p initialized %u initcount %u\n"),
01097 ent, ent->refcnt,
01098 ent->pool.cursor, ent->pool.rotate,
01099 ent->pool.entropy, ent->pool.pseudo,
01100 ent->nsources, ent->nextsource, ent->initialized,
01101 ent->initcount);
01102 }
01103
01104
01105
01106
01107 void
01108 isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
01109 REQUIRE(VALID_ENTROPY(ent));
01110
01111 LOCK(&ent->lock);
01112 dumpstats(ent, out);
01113 UNLOCK(&ent->lock);
01114 }
01115
01116 unsigned int
01117 isc_entropy_status(isc_entropy_t *ent) {
01118 unsigned int estimate;
01119
01120 LOCK(&ent->lock);
01121 estimate = ent->pool.entropy;
01122 UNLOCK(&ent->lock);
01123
01124 return estimate;
01125 }
01126
01127 void
01128 isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
01129 REQUIRE(VALID_ENTROPY(ent));
01130 REQUIRE(entp != NULL && *entp == NULL);
01131
01132 LOCK(&ent->lock);
01133
01134 ent->refcnt++;
01135 *entp = ent;
01136
01137 UNLOCK(&ent->lock);
01138 }
01139
01140 void
01141 isc_entropy_detach(isc_entropy_t **entp) {
01142 isc_entropy_t *ent;
01143 isc_boolean_t killit;
01144
01145 REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
01146 ent = *entp;
01147 *entp = NULL;
01148
01149 LOCK(&ent->lock);
01150
01151 REQUIRE(ent->refcnt > 0);
01152 ent->refcnt--;
01153
01154 killit = destroy_check(ent);
01155
01156 UNLOCK(&ent->lock);
01157
01158 if (killit)
01159 destroy(&ent);
01160 }
01161
01162 static isc_result_t
01163 kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
01164
01165
01166
01167
01168
01169 static isc_boolean_t first = ISC_TRUE;
01170
01171 UNUSED(arg);
01172
01173 if (! blocking)
01174 return (ISC_R_NOENTROPY);
01175
01176 if (first) {
01177 if (source->warn_keyboard)
01178 fprintf(stderr, "You must use the keyboard to create "
01179 "entropy, since your system is lacking\n"
01180 "/dev/random (or equivalent)\n\n");
01181 first = ISC_FALSE;
01182 }
01183 fprintf(stderr, "start typing:\n");
01184
01185 return (isc_keyboard_open(&source->kbd));
01186 }
01187
01188 static void
01189 kbdstop(isc_entropysource_t *source, void *arg) {
01190
01191 UNUSED(arg);
01192
01193 if (! isc_keyboard_canceled(&source->kbd))
01194 fprintf(stderr, "stop typing.\r\n");
01195
01196 (void)isc_keyboard_close(&source->kbd, 3);
01197 }
01198
01199 static isc_result_t
01200 kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
01201 isc_result_t result;
01202 isc_time_t t;
01203 isc_uint32_t sample;
01204 isc_uint32_t extra;
01205 unsigned char c;
01206
01207 UNUSED(arg);
01208
01209 if (!blocking)
01210 return (ISC_R_NOTBLOCKING);
01211
01212 result = isc_keyboard_getchar(&source->kbd, &c);
01213 if (result != ISC_R_SUCCESS)
01214 return (result);
01215
01216 TIME_NOW(&t);
01217
01218 sample = isc_time_nanoseconds(&t);
01219 extra = c;
01220
01221 result = isc_entropy_addcallbacksample(source, sample, extra);
01222 if (result != ISC_R_SUCCESS) {
01223 fprintf(stderr, "\r\n");
01224 return (result);
01225 }
01226
01227 fprintf(stderr, ".");
01228 fflush(stderr);
01229
01230 return (result);
01231 }
01232
01233 isc_result_t
01234 isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
01235 const char *randomfile, int use_keyboard)
01236 {
01237 isc_result_t result;
01238 isc_result_t final_result = ISC_R_NOENTROPY;
01239 isc_boolean_t userfile = ISC_TRUE;
01240
01241 REQUIRE(VALID_ENTROPY(ectx));
01242 REQUIRE(source != NULL && *source == NULL);
01243 REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
01244 use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
01245 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
01246
01247 #ifdef PKCS11CRYPTO
01248 if (randomfile != NULL)
01249 pk11_rand_seed_fromfile(randomfile);
01250 #endif
01251
01252 #ifdef PATH_RANDOMDEV
01253 if (randomfile == NULL) {
01254 randomfile = PATH_RANDOMDEV;
01255 userfile = ISC_FALSE;
01256 }
01257 #endif
01258
01259 if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
01260 result = isc_entropy_createfilesource(ectx, randomfile);
01261 if (result == ISC_R_SUCCESS &&
01262 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
01263 use_keyboard = ISC_ENTROPY_KEYBOARDNO;
01264 if (result != ISC_R_SUCCESS && userfile)
01265 return (result);
01266
01267 final_result = result;
01268 }
01269
01270 if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
01271 result = isc_entropy_createcallbacksource(ectx, kbdstart,
01272 kbdget, kbdstop,
01273 NULL, source);
01274 if (result == ISC_R_SUCCESS)
01275 (*source)->warn_keyboard =
01276 ISC_TF(use_keyboard ==
01277 ISC_ENTROPY_KEYBOARDMAYBE);
01278
01279 if (final_result != ISC_R_SUCCESS)
01280 final_result = result;
01281 }
01282
01283
01284
01285
01286
01287
01288
01289 return (final_result);
01290 }