1258945Sroberto/* 2280849Scy * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 2000-2003 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18280849Scy/* $Id: entropy.c,v 1.22 2010/08/10 23:48:19 tbox Exp $ */ 19258945Sroberto 20258945Sroberto/*! \file 21258945Sroberto * \brief 22258945Sroberto * This is the system independent part of the entropy module. It is 23258945Sroberto * compiled via inclusion from the relevant OS source file, ie, 24258945Sroberto * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c. 25258945Sroberto * 26258945Sroberto * \author Much of this code is modeled after the NetBSD /dev/random implementation, 27258945Sroberto * written by Michael Graff <explorer@netbsd.org>. 28258945Sroberto */ 29258945Sroberto 30258945Sroberto#include <errno.h> 31258945Sroberto#include <fcntl.h> 32258945Sroberto#include <stdio.h> 33258945Sroberto 34258945Sroberto#include <isc/buffer.h> 35258945Sroberto#include <isc/entropy.h> 36258945Sroberto#include <isc/keyboard.h> 37258945Sroberto#include <isc/list.h> 38258945Sroberto#include <isc/magic.h> 39258945Sroberto#include <isc/mem.h> 40258945Sroberto#include <isc/msgs.h> 41258945Sroberto#include <isc/mutex.h> 42258945Sroberto#include <isc/platform.h> 43258945Sroberto#include <isc/region.h> 44258945Sroberto#include <isc/sha1.h> 45258945Sroberto#include <isc/string.h> 46258945Sroberto#include <isc/time.h> 47258945Sroberto#include <isc/util.h> 48258945Sroberto 49258945Sroberto 50258945Sroberto#define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e') 51258945Sroberto#define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's') 52258945Sroberto 53258945Sroberto#define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC) 54258945Sroberto#define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC) 55258945Sroberto 56258945Sroberto/*** 57258945Sroberto *** "constants." Do not change these unless you _really_ know what 58258945Sroberto *** you are doing. 59258945Sroberto ***/ 60258945Sroberto 61258945Sroberto/*% 62258945Sroberto * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2. 63258945Sroberto */ 64258945Sroberto#define RND_POOLWORDS 128 65258945Sroberto/*% Pool in bytes. */ 66258945Sroberto#define RND_POOLBYTES (RND_POOLWORDS * 4) 67258945Sroberto/*% Pool in bits. */ 68258945Sroberto#define RND_POOLBITS (RND_POOLWORDS * 32) 69258945Sroberto 70258945Sroberto/*% 71258945Sroberto * Number of bytes returned per hash. This must be true: 72258945Sroberto * threshold * 2 <= digest_size_in_bytes 73258945Sroberto */ 74258945Sroberto#define RND_ENTROPY_THRESHOLD 10 75258945Sroberto#define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8) 76258945Sroberto 77258945Sroberto/*% 78258945Sroberto * Size of the input event queue in samples. 79258945Sroberto */ 80258945Sroberto#define RND_EVENTQSIZE 32 81258945Sroberto 82258945Sroberto/*% 83258945Sroberto * The number of times we'll "reseed" for pseudorandom seeds. This is an 84258945Sroberto * extremely weak pseudorandom seed. If the caller is using lots of 85258945Sroberto * pseudorandom data and they cannot provide a stronger random source, 86258945Sroberto * there is little we can do other than hope they're smart enough to 87258945Sroberto * call _adddata() with something better than we can come up with. 88258945Sroberto */ 89258945Sroberto#define RND_INITIALIZE 128 90258945Sroberto 91258945Sroberto/*% Entropy Pool */ 92258945Srobertotypedef struct { 93258945Sroberto isc_uint32_t cursor; /*%< current add point in the pool */ 94258945Sroberto isc_uint32_t entropy; /*%< current entropy estimate in bits */ 95258945Sroberto isc_uint32_t pseudo; /*%< bits extracted in pseudorandom */ 96258945Sroberto isc_uint32_t rotate; /*%< how many bits to rotate by */ 97258945Sroberto isc_uint32_t pool[RND_POOLWORDS]; /*%< random pool data */ 98258945Sroberto} isc_entropypool_t; 99258945Sroberto 100258945Srobertostruct isc_entropy { 101258945Sroberto unsigned int magic; 102258945Sroberto isc_mem_t *mctx; 103258945Sroberto isc_mutex_t lock; 104258945Sroberto unsigned int refcnt; 105258945Sroberto isc_uint32_t initialized; 106258945Sroberto isc_uint32_t initcount; 107258945Sroberto isc_entropypool_t pool; 108258945Sroberto unsigned int nsources; 109258945Sroberto isc_entropysource_t *nextsource; 110258945Sroberto ISC_LIST(isc_entropysource_t) sources; 111258945Sroberto}; 112258945Sroberto 113258945Sroberto/*% Sample Queue */ 114258945Srobertotypedef struct { 115258945Sroberto isc_uint32_t last_time; /*%< last time recorded */ 116258945Sroberto isc_uint32_t last_delta; /*%< last delta value */ 117258945Sroberto isc_uint32_t last_delta2; /*%< last delta2 value */ 118258945Sroberto isc_uint32_t nsamples; /*%< number of samples filled in */ 119258945Sroberto isc_uint32_t *samples; /*%< the samples */ 120258945Sroberto isc_uint32_t *extra; /*%< extra samples added in */ 121258945Sroberto} sample_queue_t; 122258945Sroberto 123258945Srobertotypedef struct { 124258945Sroberto sample_queue_t samplequeue; 125258945Sroberto} isc_entropysamplesource_t; 126258945Sroberto 127258945Srobertotypedef struct { 128258945Sroberto isc_boolean_t start_called; 129258945Sroberto isc_entropystart_t startfunc; 130258945Sroberto isc_entropyget_t getfunc; 131258945Sroberto isc_entropystop_t stopfunc; 132258945Sroberto void *arg; 133258945Sroberto sample_queue_t samplequeue; 134258945Sroberto} isc_cbsource_t; 135258945Sroberto 136258945Srobertotypedef struct { 137258945Sroberto FILESOURCE_HANDLE_TYPE handle; 138258945Sroberto} isc_entropyfilesource_t; 139258945Sroberto 140258945Srobertostruct isc_entropysource { 141258945Sroberto unsigned int magic; 142258945Sroberto unsigned int type; 143258945Sroberto isc_entropy_t *ent; 144258945Sroberto isc_uint32_t total; /*%< entropy from this source */ 145258945Sroberto ISC_LINK(isc_entropysource_t) link; 146258945Sroberto char name[32]; 147258945Sroberto isc_boolean_t bad; 148258945Sroberto isc_boolean_t warn_keyboard; 149258945Sroberto isc_keyboard_t kbd; 150258945Sroberto union { 151258945Sroberto isc_entropysamplesource_t sample; 152258945Sroberto isc_entropyfilesource_t file; 153258945Sroberto isc_cbsource_t callback; 154258945Sroberto isc_entropyusocketsource_t usocket; 155258945Sroberto } sources; 156258945Sroberto}; 157258945Sroberto 158258945Sroberto#define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */ 159258945Sroberto#define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */ 160258945Sroberto#define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */ 161258945Sroberto#define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */ 162258945Sroberto 163258945Sroberto/*@{*/ 164258945Sroberto/*% 165258945Sroberto * The random pool "taps" 166258945Sroberto */ 167258945Sroberto#define TAP1 99 168258945Sroberto#define TAP2 59 169258945Sroberto#define TAP3 31 170258945Sroberto#define TAP4 9 171258945Sroberto#define TAP5 7 172258945Sroberto/*@}*/ 173258945Sroberto 174258945Sroberto/*@{*/ 175258945Sroberto/*% 176258945Sroberto * Declarations for function provided by the system dependent sources that 177258945Sroberto * include this file. 178258945Sroberto */ 179258945Srobertostatic void 180258945Srobertofillpool(isc_entropy_t *, unsigned int, isc_boolean_t); 181258945Sroberto 182258945Srobertostatic int 183258945Srobertowait_for_sources(isc_entropy_t *); 184258945Sroberto 185258945Srobertostatic void 186258945Srobertodestroyfilesource(isc_entropyfilesource_t *source); 187258945Sroberto 188258945Srobertostatic void 189258945Srobertodestroyusocketsource(isc_entropyusocketsource_t *source); 190258945Sroberto 191258945Sroberto/*@}*/ 192258945Sroberto 193258945Srobertostatic void 194258945Srobertosamplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) { 195258945Sroberto REQUIRE(sq->samples != NULL); 196258945Sroberto REQUIRE(sq->extra != NULL); 197258945Sroberto 198258945Sroberto isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4); 199258945Sroberto isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4); 200258945Sroberto sq->samples = NULL; 201258945Sroberto sq->extra = NULL; 202258945Sroberto} 203258945Sroberto 204258945Srobertostatic isc_result_t 205258945Srobertosamplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) { 206258945Sroberto sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4); 207258945Sroberto if (sq->samples == NULL) 208258945Sroberto return (ISC_R_NOMEMORY); 209258945Sroberto 210258945Sroberto sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4); 211258945Sroberto if (sq->extra == NULL) { 212258945Sroberto isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4); 213258945Sroberto sq->samples = NULL; 214258945Sroberto return (ISC_R_NOMEMORY); 215258945Sroberto } 216258945Sroberto 217258945Sroberto sq->nsamples = 0; 218258945Sroberto 219258945Sroberto return (ISC_R_SUCCESS); 220258945Sroberto} 221258945Sroberto 222258945Sroberto/*% 223258945Sroberto * Add in entropy, even when the value we're adding in could be 224258945Sroberto * very large. 225258945Sroberto */ 226258945Srobertostatic inline void 227258945Srobertoadd_entropy(isc_entropy_t *ent, isc_uint32_t entropy) { 228258945Sroberto /* clamp input. Yes, this must be done. */ 229258945Sroberto entropy = ISC_MIN(entropy, RND_POOLBITS); 230258945Sroberto /* Add in the entropy we already have. */ 231258945Sroberto entropy += ent->pool.entropy; 232258945Sroberto /* Clamp. */ 233258945Sroberto ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS); 234258945Sroberto} 235258945Sroberto 236258945Sroberto/*% 237258945Sroberto * Decrement the amount of entropy the pool has. 238258945Sroberto */ 239258945Srobertostatic inline void 240258945Srobertosubtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) { 241258945Sroberto entropy = ISC_MIN(entropy, ent->pool.entropy); 242258945Sroberto ent->pool.entropy -= entropy; 243258945Sroberto} 244258945Sroberto 245258945Sroberto/*! 246258945Sroberto * Add in entropy, even when the value we're adding in could be 247258945Sroberto * very large. 248258945Sroberto */ 249258945Srobertostatic inline void 250258945Srobertoadd_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) { 251258945Sroberto /* clamp input. Yes, this must be done. */ 252258945Sroberto pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8); 253258945Sroberto /* Add in the pseudo we already have. */ 254258945Sroberto pseudo += ent->pool.pseudo; 255258945Sroberto /* Clamp. */ 256258945Sroberto ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8); 257258945Sroberto} 258258945Sroberto 259258945Sroberto/*! 260258945Sroberto * Decrement the amount of pseudo the pool has. 261258945Sroberto */ 262258945Srobertostatic inline void 263258945Srobertosubtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) { 264258945Sroberto pseudo = ISC_MIN(pseudo, ent->pool.pseudo); 265258945Sroberto ent->pool.pseudo -= pseudo; 266258945Sroberto} 267258945Sroberto 268258945Sroberto/*! 269258945Sroberto * Add one word to the pool, rotating the input as needed. 270258945Sroberto */ 271258945Srobertostatic inline void 272258945Srobertoentropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) { 273258945Sroberto /* 274258945Sroberto * Steal some values out of the pool, and xor them into the 275258945Sroberto * word we were given. 276258945Sroberto * 277258945Sroberto * Mix the new value into the pool using xor. This will 278258945Sroberto * prevent the actual values from being known to the caller 279258945Sroberto * since the previous values are assumed to be unknown as well. 280258945Sroberto */ 281258945Sroberto val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)]; 282258945Sroberto val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)]; 283258945Sroberto val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)]; 284258945Sroberto val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)]; 285258945Sroberto val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)]; 286280849Scy if (rp->rotate == 0) 287280849Scy rp->pool[rp->cursor++] ^= val; 288280849Scy else 289280849Scy rp->pool[rp->cursor++] ^= 290280849Scy ((val << rp->rotate) | (val >> (32 - rp->rotate))); 291258945Sroberto 292258945Sroberto /* 293258945Sroberto * If we have looped around the pool, increment the rotate 294258945Sroberto * variable so the next value will get xored in rotated to 295258945Sroberto * a different position. 296258945Sroberto * Increment by a value that is relatively prime to the word size 297258945Sroberto * to try to spread the bits throughout the pool quickly when the 298258945Sroberto * pool is empty. 299258945Sroberto */ 300258945Sroberto if (rp->cursor == RND_POOLWORDS) { 301258945Sroberto rp->cursor = 0; 302258945Sroberto rp->rotate = (rp->rotate + 7) & 31; 303258945Sroberto } 304258945Sroberto} 305258945Sroberto 306258945Sroberto/*! 307258945Sroberto * Add a buffer's worth of data to the pool. 308258945Sroberto * 309258945Sroberto * Requires that the lock is held on the entropy pool. 310258945Sroberto */ 311258945Srobertostatic void 312258945Srobertoentropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len, 313258945Sroberto isc_uint32_t entropy) 314258945Sroberto{ 315258945Sroberto isc_uint32_t val; 316258945Sroberto unsigned long addr; 317258945Sroberto isc_uint8_t *buf; 318258945Sroberto 319258945Sroberto addr = (unsigned long)p; 320258945Sroberto buf = p; 321258945Sroberto 322258945Sroberto if ((addr & 0x03U) != 0U) { 323258945Sroberto val = 0; 324258945Sroberto switch (len) { 325258945Sroberto case 3: 326258945Sroberto val = *buf++; 327258945Sroberto len--; 328258945Sroberto case 2: 329258945Sroberto val = val << 8 | *buf++; 330258945Sroberto len--; 331258945Sroberto case 1: 332258945Sroberto val = val << 8 | *buf++; 333258945Sroberto len--; 334258945Sroberto } 335258945Sroberto 336258945Sroberto entropypool_add_word(&ent->pool, val); 337258945Sroberto } 338258945Sroberto 339258945Sroberto for (; len > 3; len -= 4) { 340258945Sroberto val = *((isc_uint32_t *)buf); 341258945Sroberto 342258945Sroberto entropypool_add_word(&ent->pool, val); 343258945Sroberto buf += 4; 344258945Sroberto } 345258945Sroberto 346258945Sroberto if (len != 0) { 347258945Sroberto val = 0; 348258945Sroberto switch (len) { 349258945Sroberto case 3: 350258945Sroberto val = *buf++; 351258945Sroberto case 2: 352258945Sroberto val = val << 8 | *buf++; 353258945Sroberto case 1: 354258945Sroberto val = val << 8 | *buf++; 355258945Sroberto } 356258945Sroberto 357258945Sroberto entropypool_add_word(&ent->pool, val); 358258945Sroberto } 359258945Sroberto 360258945Sroberto add_entropy(ent, entropy); 361258945Sroberto subtract_pseudo(ent, entropy); 362258945Sroberto} 363258945Sroberto 364258945Srobertostatic inline void 365258945Srobertoreseed(isc_entropy_t *ent) { 366258945Sroberto isc_time_t t; 367258945Sroberto pid_t pid; 368258945Sroberto 369258945Sroberto if (ent->initcount == 0) { 370258945Sroberto pid = getpid(); 371258945Sroberto entropypool_adddata(ent, &pid, sizeof(pid), 0); 372258945Sroberto pid = getppid(); 373258945Sroberto entropypool_adddata(ent, &pid, sizeof(pid), 0); 374258945Sroberto } 375258945Sroberto 376258945Sroberto /*! 377258945Sroberto * After we've reseeded 100 times, only add new timing info every 378258945Sroberto * 50 requests. This will keep us from using lots and lots of 379258945Sroberto * CPU just to return bad pseudorandom data anyway. 380258945Sroberto */ 381258945Sroberto if (ent->initcount > 100) 382258945Sroberto if ((ent->initcount % 50) != 0) 383258945Sroberto return; 384258945Sroberto 385258945Sroberto TIME_NOW(&t); 386258945Sroberto entropypool_adddata(ent, &t, sizeof(t), 0); 387258945Sroberto ent->initcount++; 388258945Sroberto} 389258945Sroberto 390258945Srobertostatic inline unsigned int 391258945Srobertoestimate_entropy(sample_queue_t *sq, isc_uint32_t t) { 392258945Sroberto isc_int32_t delta; 393258945Sroberto isc_int32_t delta2; 394258945Sroberto isc_int32_t delta3; 395258945Sroberto 396258945Sroberto /*! 397258945Sroberto * If the time counter has overflowed, calculate the real difference. 398258945Sroberto * If it has not, it is simpler. 399258945Sroberto */ 400258945Sroberto if (t < sq->last_time) 401258945Sroberto delta = UINT_MAX - sq->last_time + t; 402258945Sroberto else 403258945Sroberto delta = sq->last_time - t; 404258945Sroberto 405258945Sroberto if (delta < 0) 406258945Sroberto delta = -delta; 407258945Sroberto 408258945Sroberto /* 409258945Sroberto * Calculate the second and third order differentials 410258945Sroberto */ 411258945Sroberto delta2 = sq->last_delta - delta; 412258945Sroberto if (delta2 < 0) 413258945Sroberto delta2 = -delta2; 414258945Sroberto 415258945Sroberto delta3 = sq->last_delta2 - delta2; 416258945Sroberto if (delta3 < 0) 417258945Sroberto delta3 = -delta3; 418258945Sroberto 419258945Sroberto sq->last_time = t; 420258945Sroberto sq->last_delta = delta; 421258945Sroberto sq->last_delta2 = delta2; 422258945Sroberto 423258945Sroberto /* 424258945Sroberto * If any delta is 0, we got no entropy. If all are non-zero, we 425258945Sroberto * might have something. 426258945Sroberto */ 427258945Sroberto if (delta == 0 || delta2 == 0 || delta3 == 0) 428258945Sroberto return 0; 429258945Sroberto 430258945Sroberto /* 431258945Sroberto * We could find the smallest delta and claim we got log2(delta) 432258945Sroberto * bits, but for now return that we found 1 bit. 433258945Sroberto */ 434258945Sroberto return 1; 435258945Sroberto} 436258945Sroberto 437258945Srobertostatic unsigned int 438258945Srobertocrunchsamples(isc_entropy_t *ent, sample_queue_t *sq) { 439258945Sroberto unsigned int ns; 440258945Sroberto unsigned int added; 441258945Sroberto 442258945Sroberto if (sq->nsamples < 6) 443258945Sroberto return (0); 444258945Sroberto 445258945Sroberto added = 0; 446258945Sroberto sq->last_time = sq->samples[0]; 447258945Sroberto sq->last_delta = 0; 448258945Sroberto sq->last_delta2 = 0; 449258945Sroberto 450258945Sroberto /* 451258945Sroberto * Prime the values by adding in the first 4 samples in. This 452258945Sroberto * should completely initialize the delta calculations. 453258945Sroberto */ 454258945Sroberto for (ns = 0; ns < 4; ns++) 455258945Sroberto (void)estimate_entropy(sq, sq->samples[ns]); 456258945Sroberto 457258945Sroberto for (ns = 4; ns < sq->nsamples; ns++) 458258945Sroberto added += estimate_entropy(sq, sq->samples[ns]); 459258945Sroberto 460258945Sroberto entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added); 461258945Sroberto entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0); 462258945Sroberto 463258945Sroberto /* 464258945Sroberto * Move the last 4 samples into the first 4 positions, and start 465258945Sroberto * adding new samples from that point. 466258945Sroberto */ 467258945Sroberto for (ns = 0; ns < 4; ns++) { 468258945Sroberto sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns]; 469258945Sroberto sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns]; 470258945Sroberto } 471258945Sroberto 472258945Sroberto sq->nsamples = 4; 473258945Sroberto 474258945Sroberto return (added); 475258945Sroberto} 476258945Sroberto 477258945Srobertostatic unsigned int 478258945Srobertoget_from_callback(isc_entropysource_t *source, unsigned int desired, 479258945Sroberto isc_boolean_t blocking) 480258945Sroberto{ 481258945Sroberto isc_entropy_t *ent = source->ent; 482258945Sroberto isc_cbsource_t *cbs = &source->sources.callback; 483258945Sroberto unsigned int added; 484258945Sroberto unsigned int got; 485258945Sroberto isc_result_t result; 486258945Sroberto 487258945Sroberto if (desired == 0) 488258945Sroberto return (0); 489258945Sroberto 490258945Sroberto if (source->bad) 491258945Sroberto return (0); 492258945Sroberto 493258945Sroberto if (!cbs->start_called && cbs->startfunc != NULL) { 494258945Sroberto result = cbs->startfunc(source, cbs->arg, blocking); 495258945Sroberto if (result != ISC_R_SUCCESS) 496258945Sroberto return (0); 497258945Sroberto cbs->start_called = ISC_TRUE; 498258945Sroberto } 499258945Sroberto 500258945Sroberto added = 0; 501258945Sroberto result = ISC_R_SUCCESS; 502258945Sroberto while (desired > 0 && result == ISC_R_SUCCESS) { 503258945Sroberto result = cbs->getfunc(source, cbs->arg, blocking); 504258945Sroberto if (result == ISC_R_QUEUEFULL) { 505258945Sroberto got = crunchsamples(ent, &cbs->samplequeue); 506258945Sroberto added += got; 507258945Sroberto desired -= ISC_MIN(got, desired); 508258945Sroberto result = ISC_R_SUCCESS; 509258945Sroberto } else if (result != ISC_R_SUCCESS && 510258945Sroberto result != ISC_R_NOTBLOCKING) 511258945Sroberto source->bad = ISC_TRUE; 512258945Sroberto 513258945Sroberto } 514258945Sroberto 515258945Sroberto return (added); 516258945Sroberto} 517258945Sroberto 518258945Sroberto/* 519258945Sroberto * Extract some number of bytes from the random pool, decreasing the 520258945Sroberto * estimate of randomness as each byte is extracted. 521258945Sroberto * 522258945Sroberto * Do this by stiring the pool and returning a part of hash as randomness. 523258945Sroberto * Note that no secrets are given away here since parts of the hash are 524258945Sroberto * xored together before returned. 525258945Sroberto * 526258945Sroberto * Honor the request from the caller to only return good data, any data, 527258945Sroberto * etc. 528258945Sroberto */ 529258945Srobertoisc_result_t 530258945Srobertoisc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length, 531258945Sroberto unsigned int *returned, unsigned int flags) 532258945Sroberto{ 533258945Sroberto unsigned int i; 534258945Sroberto isc_sha1_t hash; 535258945Sroberto unsigned char digest[ISC_SHA1_DIGESTLENGTH]; 536258945Sroberto isc_uint32_t remain, deltae, count, total; 537258945Sroberto isc_uint8_t *buf; 538258945Sroberto isc_boolean_t goodonly, partial, blocking; 539258945Sroberto 540258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 541258945Sroberto REQUIRE(data != NULL); 542258945Sroberto REQUIRE(length > 0); 543258945Sroberto 544258945Sroberto goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0); 545258945Sroberto partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0); 546258945Sroberto blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0); 547258945Sroberto 548258945Sroberto REQUIRE(!partial || returned != NULL); 549258945Sroberto 550258945Sroberto LOCK(&ent->lock); 551258945Sroberto 552258945Sroberto remain = length; 553258945Sroberto buf = data; 554258945Sroberto total = 0; 555258945Sroberto while (remain != 0) { 556258945Sroberto count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD); 557258945Sroberto 558258945Sroberto /* 559258945Sroberto * If we are extracting good data only, make certain we 560258945Sroberto * have enough data in our pool for this pass. If we don't, 561258945Sroberto * get some, and fail if we can't, and partial returns 562258945Sroberto * are not ok. 563258945Sroberto */ 564258945Sroberto if (goodonly) { 565258945Sroberto unsigned int fillcount; 566258945Sroberto 567258945Sroberto fillcount = ISC_MAX(remain * 8, count * 8); 568258945Sroberto 569258945Sroberto /* 570258945Sroberto * If, however, we have at least THRESHOLD_BITS 571258945Sroberto * of entropy in the pool, don't block here. It is 572258945Sroberto * better to drain the pool once in a while and 573258945Sroberto * then refill it than it is to constantly keep the 574258945Sroberto * pool full. 575258945Sroberto */ 576258945Sroberto if (ent->pool.entropy >= THRESHOLD_BITS) 577258945Sroberto fillpool(ent, fillcount, ISC_FALSE); 578258945Sroberto else 579258945Sroberto fillpool(ent, fillcount, blocking); 580258945Sroberto 581258945Sroberto /* 582258945Sroberto * Verify that we got enough entropy to do one 583258945Sroberto * extraction. If we didn't, bail. 584258945Sroberto */ 585258945Sroberto if (ent->pool.entropy < THRESHOLD_BITS) { 586258945Sroberto if (!partial) 587258945Sroberto goto zeroize; 588258945Sroberto else 589258945Sroberto goto partial_output; 590258945Sroberto } 591258945Sroberto } else { 592258945Sroberto /* 593258945Sroberto * If we've extracted half our pool size in bits 594258945Sroberto * since the last refresh, try to refresh here. 595258945Sroberto */ 596258945Sroberto if (ent->initialized < THRESHOLD_BITS) 597258945Sroberto fillpool(ent, THRESHOLD_BITS, blocking); 598258945Sroberto else 599258945Sroberto fillpool(ent, 0, ISC_FALSE); 600258945Sroberto 601258945Sroberto /* 602258945Sroberto * If we've not initialized with enough good random 603258945Sroberto * data, seed with our crappy code. 604258945Sroberto */ 605258945Sroberto if (ent->initialized < THRESHOLD_BITS) 606258945Sroberto reseed(ent); 607258945Sroberto } 608258945Sroberto 609258945Sroberto isc_sha1_init(&hash); 610258945Sroberto isc_sha1_update(&hash, (void *)(ent->pool.pool), 611258945Sroberto RND_POOLBYTES); 612258945Sroberto isc_sha1_final(&hash, digest); 613258945Sroberto 614258945Sroberto /* 615258945Sroberto * Stir the extracted data (all of it) back into the pool. 616258945Sroberto */ 617258945Sroberto entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0); 618258945Sroberto 619258945Sroberto for (i = 0; i < count; i++) 620258945Sroberto buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD]; 621258945Sroberto 622258945Sroberto buf += count; 623258945Sroberto remain -= count; 624258945Sroberto 625258945Sroberto deltae = count * 8; 626258945Sroberto deltae = ISC_MIN(deltae, ent->pool.entropy); 627258945Sroberto total += deltae; 628258945Sroberto subtract_entropy(ent, deltae); 629258945Sroberto add_pseudo(ent, count * 8); 630258945Sroberto } 631258945Sroberto 632258945Sroberto partial_output: 633258945Sroberto memset(digest, 0, sizeof(digest)); 634258945Sroberto 635258945Sroberto if (returned != NULL) 636258945Sroberto *returned = (length - remain); 637258945Sroberto 638258945Sroberto UNLOCK(&ent->lock); 639258945Sroberto 640258945Sroberto return (ISC_R_SUCCESS); 641258945Sroberto 642258945Sroberto zeroize: 643258945Sroberto /* put the entropy we almost extracted back */ 644258945Sroberto add_entropy(ent, total); 645258945Sroberto memset(data, 0, length); 646258945Sroberto memset(digest, 0, sizeof(digest)); 647258945Sroberto if (returned != NULL) 648258945Sroberto *returned = 0; 649258945Sroberto 650258945Sroberto UNLOCK(&ent->lock); 651258945Sroberto 652258945Sroberto return (ISC_R_NOENTROPY); 653258945Sroberto} 654258945Sroberto 655258945Srobertostatic void 656258945Srobertoisc_entropypool_init(isc_entropypool_t *pool) { 657258945Sroberto pool->cursor = RND_POOLWORDS - 1; 658258945Sroberto pool->entropy = 0; 659258945Sroberto pool->pseudo = 0; 660258945Sroberto pool->rotate = 0; 661258945Sroberto memset(pool->pool, 0, RND_POOLBYTES); 662258945Sroberto} 663258945Sroberto 664258945Srobertostatic void 665258945Srobertoisc_entropypool_invalidate(isc_entropypool_t *pool) { 666258945Sroberto pool->cursor = 0; 667258945Sroberto pool->entropy = 0; 668258945Sroberto pool->pseudo = 0; 669258945Sroberto pool->rotate = 0; 670258945Sroberto memset(pool->pool, 0, RND_POOLBYTES); 671258945Sroberto} 672258945Sroberto 673258945Srobertoisc_result_t 674258945Srobertoisc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) { 675258945Sroberto isc_result_t result; 676258945Sroberto isc_entropy_t *ent; 677258945Sroberto 678258945Sroberto REQUIRE(mctx != NULL); 679258945Sroberto REQUIRE(entp != NULL && *entp == NULL); 680258945Sroberto 681258945Sroberto ent = isc_mem_get(mctx, sizeof(isc_entropy_t)); 682258945Sroberto if (ent == NULL) 683258945Sroberto return (ISC_R_NOMEMORY); 684258945Sroberto 685258945Sroberto /* 686258945Sroberto * We need a lock. 687258945Sroberto */ 688258945Sroberto result = isc_mutex_init(&ent->lock); 689258945Sroberto if (result != ISC_R_SUCCESS) 690258945Sroberto goto errout; 691258945Sroberto 692258945Sroberto /* 693258945Sroberto * From here down, no failures will/can occur. 694258945Sroberto */ 695258945Sroberto ISC_LIST_INIT(ent->sources); 696258945Sroberto ent->nextsource = NULL; 697258945Sroberto ent->nsources = 0; 698258945Sroberto ent->mctx = NULL; 699258945Sroberto isc_mem_attach(mctx, &ent->mctx); 700258945Sroberto ent->refcnt = 1; 701258945Sroberto ent->initialized = 0; 702258945Sroberto ent->initcount = 0; 703258945Sroberto ent->magic = ENTROPY_MAGIC; 704258945Sroberto 705258945Sroberto isc_entropypool_init(&ent->pool); 706258945Sroberto 707258945Sroberto *entp = ent; 708258945Sroberto return (ISC_R_SUCCESS); 709258945Sroberto 710258945Sroberto errout: 711258945Sroberto isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); 712258945Sroberto 713258945Sroberto return (result); 714258945Sroberto} 715258945Sroberto 716258945Sroberto/*! 717258945Sroberto * Requires "ent" be locked. 718258945Sroberto */ 719258945Srobertostatic void 720258945Srobertodestroysource(isc_entropysource_t **sourcep) { 721258945Sroberto isc_entropysource_t *source; 722258945Sroberto isc_entropy_t *ent; 723258945Sroberto isc_cbsource_t *cbs; 724258945Sroberto 725258945Sroberto source = *sourcep; 726258945Sroberto *sourcep = NULL; 727258945Sroberto ent = source->ent; 728258945Sroberto 729258945Sroberto ISC_LIST_UNLINK(ent->sources, source, link); 730258945Sroberto ent->nextsource = NULL; 731258945Sroberto REQUIRE(ent->nsources > 0); 732258945Sroberto ent->nsources--; 733258945Sroberto 734258945Sroberto switch (source->type) { 735258945Sroberto case ENTROPY_SOURCETYPE_FILE: 736258945Sroberto if (! source->bad) 737258945Sroberto destroyfilesource(&source->sources.file); 738258945Sroberto break; 739258945Sroberto case ENTROPY_SOURCETYPE_USOCKET: 740258945Sroberto if (! source->bad) 741258945Sroberto destroyusocketsource(&source->sources.usocket); 742258945Sroberto break; 743258945Sroberto case ENTROPY_SOURCETYPE_SAMPLE: 744258945Sroberto samplequeue_release(ent, &source->sources.sample.samplequeue); 745258945Sroberto break; 746258945Sroberto case ENTROPY_SOURCETYPE_CALLBACK: 747258945Sroberto cbs = &source->sources.callback; 748258945Sroberto if (cbs->start_called && cbs->stopfunc != NULL) { 749258945Sroberto cbs->stopfunc(source, cbs->arg); 750258945Sroberto cbs->start_called = ISC_FALSE; 751258945Sroberto } 752258945Sroberto samplequeue_release(ent, &cbs->samplequeue); 753258945Sroberto break; 754258945Sroberto } 755258945Sroberto 756258945Sroberto memset(source, 0, sizeof(isc_entropysource_t)); 757258945Sroberto 758258945Sroberto isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); 759258945Sroberto} 760258945Sroberto 761258945Srobertostatic inline isc_boolean_t 762258945Srobertodestroy_check(isc_entropy_t *ent) { 763258945Sroberto isc_entropysource_t *source; 764258945Sroberto 765258945Sroberto if (ent->refcnt > 0) 766258945Sroberto return (ISC_FALSE); 767258945Sroberto 768258945Sroberto source = ISC_LIST_HEAD(ent->sources); 769258945Sroberto while (source != NULL) { 770258945Sroberto switch (source->type) { 771258945Sroberto case ENTROPY_SOURCETYPE_FILE: 772258945Sroberto case ENTROPY_SOURCETYPE_USOCKET: 773258945Sroberto break; 774258945Sroberto default: 775258945Sroberto return (ISC_FALSE); 776258945Sroberto } 777258945Sroberto source = ISC_LIST_NEXT(source, link); 778258945Sroberto } 779258945Sroberto 780258945Sroberto return (ISC_TRUE); 781258945Sroberto} 782258945Sroberto 783258945Srobertostatic void 784258945Srobertodestroy(isc_entropy_t **entp) { 785258945Sroberto isc_entropy_t *ent; 786258945Sroberto isc_entropysource_t *source; 787258945Sroberto isc_mem_t *mctx; 788258945Sroberto 789258945Sroberto REQUIRE(entp != NULL && *entp != NULL); 790258945Sroberto ent = *entp; 791258945Sroberto *entp = NULL; 792258945Sroberto 793258945Sroberto LOCK(&ent->lock); 794258945Sroberto 795258945Sroberto REQUIRE(ent->refcnt == 0); 796258945Sroberto 797258945Sroberto /* 798258945Sroberto * Here, detach non-sample sources. 799258945Sroberto */ 800258945Sroberto source = ISC_LIST_HEAD(ent->sources); 801258945Sroberto while (source != NULL) { 802258945Sroberto switch(source->type) { 803258945Sroberto case ENTROPY_SOURCETYPE_FILE: 804258945Sroberto case ENTROPY_SOURCETYPE_USOCKET: 805258945Sroberto destroysource(&source); 806258945Sroberto break; 807258945Sroberto } 808258945Sroberto source = ISC_LIST_HEAD(ent->sources); 809258945Sroberto } 810258945Sroberto 811258945Sroberto /* 812258945Sroberto * If there are other types of sources, we've found a bug. 813258945Sroberto */ 814258945Sroberto REQUIRE(ISC_LIST_EMPTY(ent->sources)); 815258945Sroberto 816258945Sroberto mctx = ent->mctx; 817258945Sroberto 818258945Sroberto isc_entropypool_invalidate(&ent->pool); 819258945Sroberto 820258945Sroberto UNLOCK(&ent->lock); 821258945Sroberto 822258945Sroberto DESTROYLOCK(&ent->lock); 823258945Sroberto 824258945Sroberto memset(ent, 0, sizeof(isc_entropy_t)); 825258945Sroberto isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); 826258945Sroberto isc_mem_detach(&mctx); 827258945Sroberto} 828258945Sroberto 829258945Srobertovoid 830258945Srobertoisc_entropy_destroysource(isc_entropysource_t **sourcep) { 831258945Sroberto isc_entropysource_t *source; 832258945Sroberto isc_entropy_t *ent; 833258945Sroberto isc_boolean_t killit; 834258945Sroberto 835258945Sroberto REQUIRE(sourcep != NULL); 836258945Sroberto REQUIRE(VALID_SOURCE(*sourcep)); 837258945Sroberto 838258945Sroberto source = *sourcep; 839258945Sroberto *sourcep = NULL; 840258945Sroberto 841258945Sroberto ent = source->ent; 842258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 843258945Sroberto 844258945Sroberto LOCK(&ent->lock); 845258945Sroberto 846258945Sroberto destroysource(&source); 847258945Sroberto 848258945Sroberto killit = destroy_check(ent); 849258945Sroberto 850258945Sroberto UNLOCK(&ent->lock); 851258945Sroberto 852258945Sroberto if (killit) 853258945Sroberto destroy(&ent); 854258945Sroberto} 855258945Sroberto 856258945Srobertoisc_result_t 857258945Srobertoisc_entropy_createcallbacksource(isc_entropy_t *ent, 858258945Sroberto isc_entropystart_t start, 859258945Sroberto isc_entropyget_t get, 860258945Sroberto isc_entropystop_t stop, 861258945Sroberto void *arg, 862258945Sroberto isc_entropysource_t **sourcep) 863258945Sroberto{ 864258945Sroberto isc_result_t result; 865258945Sroberto isc_entropysource_t *source; 866258945Sroberto isc_cbsource_t *cbs; 867258945Sroberto 868258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 869258945Sroberto REQUIRE(get != NULL); 870258945Sroberto REQUIRE(sourcep != NULL && *sourcep == NULL); 871258945Sroberto 872258945Sroberto LOCK(&ent->lock); 873258945Sroberto 874258945Sroberto source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); 875258945Sroberto if (source == NULL) { 876258945Sroberto result = ISC_R_NOMEMORY; 877258945Sroberto goto errout; 878258945Sroberto } 879258945Sroberto source->bad = ISC_FALSE; 880258945Sroberto 881258945Sroberto cbs = &source->sources.callback; 882258945Sroberto 883258945Sroberto result = samplesource_allocate(ent, &cbs->samplequeue); 884258945Sroberto if (result != ISC_R_SUCCESS) 885258945Sroberto goto errout; 886258945Sroberto 887258945Sroberto cbs->start_called = ISC_FALSE; 888258945Sroberto cbs->startfunc = start; 889258945Sroberto cbs->getfunc = get; 890258945Sroberto cbs->stopfunc = stop; 891258945Sroberto cbs->arg = arg; 892258945Sroberto 893258945Sroberto /* 894258945Sroberto * From here down, no failures can occur. 895258945Sroberto */ 896258945Sroberto source->magic = SOURCE_MAGIC; 897258945Sroberto source->type = ENTROPY_SOURCETYPE_CALLBACK; 898258945Sroberto source->ent = ent; 899258945Sroberto source->total = 0; 900258945Sroberto memset(source->name, 0, sizeof(source->name)); 901258945Sroberto ISC_LINK_INIT(source, link); 902258945Sroberto 903258945Sroberto /* 904258945Sroberto * Hook it into the entropy system. 905258945Sroberto */ 906258945Sroberto ISC_LIST_APPEND(ent->sources, source, link); 907258945Sroberto ent->nsources++; 908258945Sroberto 909258945Sroberto *sourcep = source; 910258945Sroberto 911258945Sroberto UNLOCK(&ent->lock); 912258945Sroberto return (ISC_R_SUCCESS); 913258945Sroberto 914258945Sroberto errout: 915258945Sroberto if (source != NULL) 916258945Sroberto isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); 917258945Sroberto 918258945Sroberto UNLOCK(&ent->lock); 919258945Sroberto 920258945Sroberto return (result); 921258945Sroberto} 922258945Sroberto 923258945Srobertovoid 924258945Srobertoisc_entropy_stopcallbacksources(isc_entropy_t *ent) { 925258945Sroberto isc_entropysource_t *source; 926258945Sroberto isc_cbsource_t *cbs; 927258945Sroberto 928258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 929258945Sroberto 930258945Sroberto LOCK(&ent->lock); 931258945Sroberto 932258945Sroberto source = ISC_LIST_HEAD(ent->sources); 933258945Sroberto while (source != NULL) { 934258945Sroberto if (source->type == ENTROPY_SOURCETYPE_CALLBACK) { 935258945Sroberto cbs = &source->sources.callback; 936258945Sroberto if (cbs->start_called && cbs->stopfunc != NULL) { 937258945Sroberto cbs->stopfunc(source, cbs->arg); 938258945Sroberto cbs->start_called = ISC_FALSE; 939258945Sroberto } 940258945Sroberto } 941258945Sroberto 942258945Sroberto source = ISC_LIST_NEXT(source, link); 943258945Sroberto } 944258945Sroberto 945258945Sroberto UNLOCK(&ent->lock); 946258945Sroberto} 947258945Sroberto 948258945Srobertoisc_result_t 949258945Srobertoisc_entropy_createsamplesource(isc_entropy_t *ent, 950258945Sroberto isc_entropysource_t **sourcep) 951258945Sroberto{ 952258945Sroberto isc_result_t result; 953258945Sroberto isc_entropysource_t *source; 954258945Sroberto sample_queue_t *sq; 955258945Sroberto 956258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 957258945Sroberto REQUIRE(sourcep != NULL && *sourcep == NULL); 958258945Sroberto 959258945Sroberto LOCK(&ent->lock); 960258945Sroberto 961258945Sroberto source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); 962258945Sroberto if (source == NULL) { 963258945Sroberto result = ISC_R_NOMEMORY; 964258945Sroberto goto errout; 965258945Sroberto } 966258945Sroberto 967258945Sroberto sq = &source->sources.sample.samplequeue; 968258945Sroberto result = samplesource_allocate(ent, sq); 969258945Sroberto if (result != ISC_R_SUCCESS) 970258945Sroberto goto errout; 971258945Sroberto 972258945Sroberto /* 973258945Sroberto * From here down, no failures can occur. 974258945Sroberto */ 975258945Sroberto source->magic = SOURCE_MAGIC; 976258945Sroberto source->type = ENTROPY_SOURCETYPE_SAMPLE; 977258945Sroberto source->ent = ent; 978258945Sroberto source->total = 0; 979258945Sroberto memset(source->name, 0, sizeof(source->name)); 980258945Sroberto ISC_LINK_INIT(source, link); 981258945Sroberto 982258945Sroberto /* 983258945Sroberto * Hook it into the entropy system. 984258945Sroberto */ 985258945Sroberto ISC_LIST_APPEND(ent->sources, source, link); 986258945Sroberto ent->nsources++; 987258945Sroberto 988258945Sroberto *sourcep = source; 989258945Sroberto 990258945Sroberto UNLOCK(&ent->lock); 991258945Sroberto return (ISC_R_SUCCESS); 992258945Sroberto 993258945Sroberto errout: 994258945Sroberto if (source != NULL) 995258945Sroberto isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); 996258945Sroberto 997258945Sroberto UNLOCK(&ent->lock); 998258945Sroberto 999258945Sroberto return (result); 1000258945Sroberto} 1001258945Sroberto 1002258945Sroberto/*! 1003258945Sroberto * Add a sample, and return ISC_R_SUCCESS if the queue has become full, 1004258945Sroberto * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the 1005258945Sroberto * queue was full when this function was called. 1006258945Sroberto */ 1007258945Srobertostatic isc_result_t 1008258945Srobertoaddsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) { 1009258945Sroberto if (sq->nsamples >= RND_EVENTQSIZE) 1010258945Sroberto return (ISC_R_NOMORE); 1011258945Sroberto 1012258945Sroberto sq->samples[sq->nsamples] = sample; 1013258945Sroberto sq->extra[sq->nsamples] = extra; 1014258945Sroberto sq->nsamples++; 1015258945Sroberto 1016258945Sroberto if (sq->nsamples >= RND_EVENTQSIZE) 1017258945Sroberto return (ISC_R_QUEUEFULL); 1018258945Sroberto 1019258945Sroberto return (ISC_R_SUCCESS); 1020258945Sroberto} 1021258945Sroberto 1022258945Srobertoisc_result_t 1023258945Srobertoisc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample, 1024258945Sroberto isc_uint32_t extra) 1025258945Sroberto{ 1026258945Sroberto isc_entropy_t *ent; 1027258945Sroberto sample_queue_t *sq; 1028258945Sroberto unsigned int entropy; 1029258945Sroberto isc_result_t result; 1030258945Sroberto 1031258945Sroberto REQUIRE(VALID_SOURCE(source)); 1032258945Sroberto 1033258945Sroberto ent = source->ent; 1034258945Sroberto 1035258945Sroberto LOCK(&ent->lock); 1036258945Sroberto 1037258945Sroberto sq = &source->sources.sample.samplequeue; 1038258945Sroberto result = addsample(sq, sample, extra); 1039258945Sroberto if (result == ISC_R_QUEUEFULL) { 1040258945Sroberto entropy = crunchsamples(ent, sq); 1041258945Sroberto add_entropy(ent, entropy); 1042258945Sroberto } 1043258945Sroberto 1044258945Sroberto UNLOCK(&ent->lock); 1045258945Sroberto 1046258945Sroberto return (result); 1047258945Sroberto} 1048258945Sroberto 1049258945Srobertoisc_result_t 1050258945Srobertoisc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample, 1051258945Sroberto isc_uint32_t extra) 1052258945Sroberto{ 1053258945Sroberto sample_queue_t *sq; 1054258945Sroberto isc_result_t result; 1055258945Sroberto 1056258945Sroberto REQUIRE(VALID_SOURCE(source)); 1057258945Sroberto REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK); 1058258945Sroberto 1059258945Sroberto sq = &source->sources.callback.samplequeue; 1060258945Sroberto result = addsample(sq, sample, extra); 1061258945Sroberto 1062258945Sroberto return (result); 1063258945Sroberto} 1064258945Sroberto 1065258945Srobertovoid 1066258945Srobertoisc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length, 1067258945Sroberto isc_uint32_t entropy) 1068258945Sroberto{ 1069258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 1070258945Sroberto 1071258945Sroberto LOCK(&ent->lock); 1072258945Sroberto 1073258945Sroberto entropypool_adddata(ent, data, length, entropy); 1074258945Sroberto 1075258945Sroberto if (ent->initialized < THRESHOLD_BITS) 1076258945Sroberto ent->initialized = THRESHOLD_BITS; 1077258945Sroberto 1078258945Sroberto UNLOCK(&ent->lock); 1079258945Sroberto} 1080258945Sroberto 1081258945Srobertostatic void 1082258945Srobertodumpstats(isc_entropy_t *ent, FILE *out) { 1083258945Sroberto fprintf(out, 1084258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY, 1085258945Sroberto ISC_MSG_ENTROPYSTATS, 1086258945Sroberto "Entropy pool %p: refcnt %u cursor %u," 1087258945Sroberto " rotate %u entropy %u pseudo %u nsources %u" 1088258945Sroberto " nextsource %p initialized %u initcount %u\n"), 1089258945Sroberto ent, ent->refcnt, 1090258945Sroberto ent->pool.cursor, ent->pool.rotate, 1091258945Sroberto ent->pool.entropy, ent->pool.pseudo, 1092258945Sroberto ent->nsources, ent->nextsource, ent->initialized, 1093258945Sroberto ent->initcount); 1094258945Sroberto} 1095258945Sroberto 1096258945Sroberto/* 1097258945Sroberto * This function ignores locking. Use at your own risk. 1098258945Sroberto */ 1099258945Srobertovoid 1100258945Srobertoisc_entropy_stats(isc_entropy_t *ent, FILE *out) { 1101258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 1102258945Sroberto 1103258945Sroberto LOCK(&ent->lock); 1104258945Sroberto dumpstats(ent, out); 1105258945Sroberto UNLOCK(&ent->lock); 1106258945Sroberto} 1107258945Sroberto 1108258945Srobertounsigned int 1109258945Srobertoisc_entropy_status(isc_entropy_t *ent) { 1110258945Sroberto unsigned int estimate; 1111258945Sroberto 1112258945Sroberto LOCK(&ent->lock); 1113258945Sroberto estimate = ent->pool.entropy; 1114258945Sroberto UNLOCK(&ent->lock); 1115258945Sroberto 1116258945Sroberto return estimate; 1117258945Sroberto} 1118258945Sroberto 1119258945Srobertovoid 1120258945Srobertoisc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) { 1121258945Sroberto REQUIRE(VALID_ENTROPY(ent)); 1122258945Sroberto REQUIRE(entp != NULL && *entp == NULL); 1123258945Sroberto 1124258945Sroberto LOCK(&ent->lock); 1125258945Sroberto 1126258945Sroberto ent->refcnt++; 1127258945Sroberto *entp = ent; 1128258945Sroberto 1129258945Sroberto UNLOCK(&ent->lock); 1130258945Sroberto} 1131258945Sroberto 1132258945Srobertovoid 1133258945Srobertoisc_entropy_detach(isc_entropy_t **entp) { 1134258945Sroberto isc_entropy_t *ent; 1135258945Sroberto isc_boolean_t killit; 1136258945Sroberto 1137258945Sroberto REQUIRE(entp != NULL && VALID_ENTROPY(*entp)); 1138258945Sroberto ent = *entp; 1139258945Sroberto *entp = NULL; 1140258945Sroberto 1141258945Sroberto LOCK(&ent->lock); 1142258945Sroberto 1143258945Sroberto REQUIRE(ent->refcnt > 0); 1144258945Sroberto ent->refcnt--; 1145258945Sroberto 1146258945Sroberto killit = destroy_check(ent); 1147258945Sroberto 1148258945Sroberto UNLOCK(&ent->lock); 1149258945Sroberto 1150258945Sroberto if (killit) 1151258945Sroberto destroy(&ent); 1152258945Sroberto} 1153258945Sroberto 1154258945Srobertostatic isc_result_t 1155258945Srobertokbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { 1156258945Sroberto /* 1157258945Sroberto * The intent of "first" is to provide a warning message only once 1158258945Sroberto * during the run of a program that might try to gather keyboard 1159258945Sroberto * entropy multiple times. 1160258945Sroberto */ 1161258945Sroberto static isc_boolean_t first = ISC_TRUE; 1162258945Sroberto 1163258945Sroberto UNUSED(arg); 1164258945Sroberto 1165258945Sroberto if (! blocking) 1166258945Sroberto return (ISC_R_NOENTROPY); 1167258945Sroberto 1168258945Sroberto if (first) { 1169258945Sroberto if (source->warn_keyboard) 1170258945Sroberto fprintf(stderr, "You must use the keyboard to create " 1171258945Sroberto "entropy, since your system is lacking\n" 1172258945Sroberto "/dev/random (or equivalent)\n\n"); 1173258945Sroberto first = ISC_FALSE; 1174258945Sroberto } 1175258945Sroberto fprintf(stderr, "start typing:\n"); 1176258945Sroberto 1177258945Sroberto return (isc_keyboard_open(&source->kbd)); 1178258945Sroberto} 1179258945Sroberto 1180258945Srobertostatic void 1181258945Srobertokbdstop(isc_entropysource_t *source, void *arg) { 1182258945Sroberto 1183258945Sroberto UNUSED(arg); 1184258945Sroberto 1185258945Sroberto if (! isc_keyboard_canceled(&source->kbd)) 1186258945Sroberto fprintf(stderr, "stop typing.\r\n"); 1187258945Sroberto 1188258945Sroberto (void)isc_keyboard_close(&source->kbd, 3); 1189258945Sroberto} 1190258945Sroberto 1191258945Srobertostatic isc_result_t 1192258945Srobertokbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { 1193258945Sroberto isc_result_t result; 1194258945Sroberto isc_time_t t; 1195258945Sroberto isc_uint32_t sample; 1196258945Sroberto isc_uint32_t extra; 1197258945Sroberto unsigned char c; 1198258945Sroberto 1199258945Sroberto UNUSED(arg); 1200258945Sroberto 1201258945Sroberto if (!blocking) 1202258945Sroberto return (ISC_R_NOTBLOCKING); 1203258945Sroberto 1204258945Sroberto result = isc_keyboard_getchar(&source->kbd, &c); 1205258945Sroberto if (result != ISC_R_SUCCESS) 1206258945Sroberto return (result); 1207258945Sroberto 1208258945Sroberto TIME_NOW(&t); 1209258945Sroberto 1210258945Sroberto sample = isc_time_nanoseconds(&t); 1211258945Sroberto extra = c; 1212258945Sroberto 1213258945Sroberto result = isc_entropy_addcallbacksample(source, sample, extra); 1214258945Sroberto if (result != ISC_R_SUCCESS) { 1215258945Sroberto fprintf(stderr, "\r\n"); 1216258945Sroberto return (result); 1217258945Sroberto } 1218258945Sroberto 1219258945Sroberto fprintf(stderr, "."); 1220258945Sroberto fflush(stderr); 1221258945Sroberto 1222258945Sroberto return (result); 1223258945Sroberto} 1224258945Sroberto 1225258945Srobertoisc_result_t 1226258945Srobertoisc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source, 1227258945Sroberto const char *randomfile, int use_keyboard) 1228258945Sroberto{ 1229258945Sroberto isc_result_t result; 1230258945Sroberto isc_result_t final_result = ISC_R_NOENTROPY; 1231258945Sroberto isc_boolean_t userfile = ISC_TRUE; 1232258945Sroberto 1233258945Sroberto REQUIRE(VALID_ENTROPY(ectx)); 1234258945Sroberto REQUIRE(source != NULL && *source == NULL); 1235258945Sroberto REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES || 1236258945Sroberto use_keyboard == ISC_ENTROPY_KEYBOARDNO || 1237258945Sroberto use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE); 1238258945Sroberto 1239258945Sroberto#ifdef PATH_RANDOMDEV 1240258945Sroberto if (randomfile == NULL) { 1241258945Sroberto randomfile = PATH_RANDOMDEV; 1242258945Sroberto userfile = ISC_FALSE; 1243258945Sroberto } 1244258945Sroberto#endif 1245258945Sroberto 1246258945Sroberto if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) { 1247258945Sroberto result = isc_entropy_createfilesource(ectx, randomfile); 1248258945Sroberto if (result == ISC_R_SUCCESS && 1249258945Sroberto use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE) 1250258945Sroberto use_keyboard = ISC_ENTROPY_KEYBOARDNO; 1251258945Sroberto if (result != ISC_R_SUCCESS && userfile) 1252258945Sroberto return (result); 1253258945Sroberto 1254258945Sroberto final_result = result; 1255258945Sroberto } 1256258945Sroberto 1257258945Sroberto if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) { 1258258945Sroberto result = isc_entropy_createcallbacksource(ectx, kbdstart, 1259258945Sroberto kbdget, kbdstop, 1260258945Sroberto NULL, source); 1261258945Sroberto if (result == ISC_R_SUCCESS) 1262258945Sroberto (*source)->warn_keyboard = 1263258945Sroberto ISC_TF(use_keyboard == 1264258945Sroberto ISC_ENTROPY_KEYBOARDMAYBE); 1265258945Sroberto 1266258945Sroberto if (final_result != ISC_R_SUCCESS) 1267258945Sroberto final_result = result; 1268258945Sroberto } 1269258945Sroberto 1270258945Sroberto /* 1271258945Sroberto * final_result is ISC_R_SUCCESS if at least one source of entropy 1272258945Sroberto * could be started, otherwise it is the error from the most recently 1273258945Sroberto * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not 1274258945Sroberto * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO). 1275258945Sroberto */ 1276258945Sroberto return (final_result); 1277258945Sroberto} 1278