entropy.c revision 135446
1135446Strhodes/* 2135446Strhodes * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5135446Strhodes * Permission to use, copy, modify, and distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18135446Strhodes/* $Id: entropy.c,v 1.3.2.2.2.7 2004/03/08 09:04:48 marka Exp $ */ 19135446Strhodes 20135446Strhodes/* 21135446Strhodes * This is the system independent part of the entropy module. It is 22135446Strhodes * compiled via inclusion from the relevant OS source file, ie, 23135446Strhodes * unix/entropy.c or win32/entropy.c. 24135446Strhodes */ 25135446Strhodes 26135446Strhodes#include <errno.h> 27135446Strhodes#include <fcntl.h> 28135446Strhodes#include <stdio.h> 29135446Strhodes 30135446Strhodes#include <isc/buffer.h> 31135446Strhodes#include <isc/entropy.h> 32135446Strhodes#include <isc/keyboard.h> 33135446Strhodes#include <isc/list.h> 34135446Strhodes#include <isc/magic.h> 35135446Strhodes#include <isc/mem.h> 36135446Strhodes#include <isc/msgs.h> 37135446Strhodes#include <isc/mutex.h> 38135446Strhodes#include <isc/platform.h> 39135446Strhodes#include <isc/region.h> 40135446Strhodes#include <isc/sha1.h> 41135446Strhodes#include <isc/string.h> 42135446Strhodes#include <isc/time.h> 43135446Strhodes#include <isc/util.h> 44135446Strhodes 45135446Strhodes/* 46135446Strhodes * Much of this code is modeled after the NetBSD /dev/random implementation, 47135446Strhodes * written by Michael Graff <explorer@netbsd.org>. 48135446Strhodes */ 49135446Strhodes 50135446Strhodes#define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e') 51135446Strhodes#define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's') 52135446Strhodes 53135446Strhodes#define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC) 54135446Strhodes#define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC) 55135446Strhodes 56135446Strhodes/*** 57135446Strhodes *** "constants." Do not change these unless you _really_ know what 58135446Strhodes *** you are doing. 59135446Strhodes ***/ 60135446Strhodes 61135446Strhodes/* 62135446Strhodes * size of entropy pool in 32-bit words. This _MUST_ be a power of 2. 63135446Strhodes */ 64135446Strhodes#define RND_POOLWORDS 128 65135446Strhodes#define RND_POOLBYTES (RND_POOLWORDS * 4) 66135446Strhodes#define RND_POOLBITS (RND_POOLWORDS * 32) 67135446Strhodes 68135446Strhodes/* 69135446Strhodes * Number of bytes returned per hash. This must be true: 70135446Strhodes * threshold * 2 <= digest_size_in_bytes 71135446Strhodes */ 72135446Strhodes#define RND_ENTROPY_THRESHOLD 10 73135446Strhodes#define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8) 74135446Strhodes 75135446Strhodes/* 76135446Strhodes * Size of the input event queue in samples. 77135446Strhodes */ 78135446Strhodes#define RND_EVENTQSIZE 32 79135446Strhodes 80135446Strhodes/* 81135446Strhodes * The number of times we'll "reseed" for pseudorandom seeds. This is an 82135446Strhodes * extremely weak pseudorandom seed. If the caller is using lots of 83135446Strhodes * pseudorandom data and they cannot provide a stronger random source, 84135446Strhodes * there is little we can do other than hope they're smart enough to 85135446Strhodes * call _adddata() with something better than we can come up with. 86135446Strhodes */ 87135446Strhodes#define RND_INITIALIZE 128 88135446Strhodes 89135446Strhodestypedef struct { 90135446Strhodes isc_uint32_t cursor; /* current add point in the pool */ 91135446Strhodes isc_uint32_t entropy; /* current entropy estimate in bits */ 92135446Strhodes isc_uint32_t pseudo; /* bits extracted in pseudorandom */ 93135446Strhodes isc_uint32_t rotate; /* how many bits to rotate by */ 94135446Strhodes isc_uint32_t pool[RND_POOLWORDS]; /* random pool data */ 95135446Strhodes} isc_entropypool_t; 96135446Strhodes 97135446Strhodesstruct isc_entropy { 98135446Strhodes unsigned int magic; 99135446Strhodes isc_mem_t *mctx; 100135446Strhodes isc_mutex_t lock; 101135446Strhodes unsigned int refcnt; 102135446Strhodes isc_uint32_t initialized; 103135446Strhodes isc_uint32_t initcount; 104135446Strhodes isc_entropypool_t pool; 105135446Strhodes unsigned int nsources; 106135446Strhodes isc_entropysource_t *nextsource; 107135446Strhodes ISC_LIST(isc_entropysource_t) sources; 108135446Strhodes}; 109135446Strhodes 110135446Strhodestypedef struct { 111135446Strhodes isc_uint32_t last_time; /* last time recorded */ 112135446Strhodes isc_uint32_t last_delta; /* last delta value */ 113135446Strhodes isc_uint32_t last_delta2; /* last delta2 value */ 114135446Strhodes isc_uint32_t nsamples; /* number of samples filled in */ 115135446Strhodes isc_uint32_t *samples; /* the samples */ 116135446Strhodes isc_uint32_t *extra; /* extra samples added in */ 117135446Strhodes} sample_queue_t; 118135446Strhodes 119135446Strhodestypedef struct { 120135446Strhodes sample_queue_t samplequeue; 121135446Strhodes} isc_entropysamplesource_t; 122135446Strhodes 123135446Strhodestypedef struct { 124135446Strhodes isc_boolean_t start_called; 125135446Strhodes isc_entropystart_t startfunc; 126135446Strhodes isc_entropyget_t getfunc; 127135446Strhodes isc_entropystop_t stopfunc; 128135446Strhodes void *arg; 129135446Strhodes sample_queue_t samplequeue; 130135446Strhodes} isc_cbsource_t; 131135446Strhodes 132135446Strhodestypedef struct { 133135446Strhodes FILESOURCE_HANDLE_TYPE handle; 134135446Strhodes} isc_entropyfilesource_t; 135135446Strhodes 136135446Strhodesstruct isc_entropysource { 137135446Strhodes unsigned int magic; 138135446Strhodes unsigned int type; 139135446Strhodes isc_entropy_t *ent; 140135446Strhodes isc_uint32_t total; /* entropy from this source */ 141135446Strhodes ISC_LINK(isc_entropysource_t) link; 142135446Strhodes char name[32]; 143135446Strhodes isc_boolean_t bad; 144135446Strhodes isc_boolean_t warn_keyboard; 145135446Strhodes isc_keyboard_t kbd; 146135446Strhodes union { 147135446Strhodes isc_entropysamplesource_t sample; 148135446Strhodes isc_entropyfilesource_t file; 149135446Strhodes isc_cbsource_t callback; 150135446Strhodes isc_entropyusocketsource_t usocket; 151135446Strhodes } sources; 152135446Strhodes}; 153135446Strhodes 154135446Strhodes#define ENTROPY_SOURCETYPE_SAMPLE 1 /* Type is a sample source */ 155135446Strhodes#define ENTROPY_SOURCETYPE_FILE 2 /* Type is a file source */ 156135446Strhodes#define ENTROPY_SOURCETYPE_CALLBACK 3 /* Type is a callback source */ 157135446Strhodes#define ENTROPY_SOURCETYPE_USOCKET 4 /* Type is a Unix socket source */ 158135446Strhodes 159135446Strhodes/* 160135446Strhodes * The random pool "taps" 161135446Strhodes */ 162135446Strhodes#define TAP1 99 163135446Strhodes#define TAP2 59 164135446Strhodes#define TAP3 31 165135446Strhodes#define TAP4 9 166135446Strhodes#define TAP5 7 167135446Strhodes 168135446Strhodes/* 169135446Strhodes * Declarations for function provided by the system dependent sources that 170135446Strhodes * include this file. 171135446Strhodes */ 172135446Strhodesstatic void 173135446Strhodesfillpool(isc_entropy_t *, unsigned int, isc_boolean_t); 174135446Strhodes 175135446Strhodesstatic int 176135446Strhodeswait_for_sources(isc_entropy_t *); 177135446Strhodes 178135446Strhodesstatic void 179135446Strhodesdestroyfilesource(isc_entropyfilesource_t *source); 180135446Strhodes 181135446Strhodesstatic void 182135446Strhodesdestroyusocketsource(isc_entropyusocketsource_t *source); 183135446Strhodes 184135446Strhodes 185135446Strhodesstatic void 186135446Strhodessamplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) { 187135446Strhodes REQUIRE(sq->samples != NULL); 188135446Strhodes REQUIRE(sq->extra != NULL); 189135446Strhodes 190135446Strhodes isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4); 191135446Strhodes isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4); 192135446Strhodes sq->samples = NULL; 193135446Strhodes sq->extra = NULL; 194135446Strhodes} 195135446Strhodes 196135446Strhodesstatic isc_result_t 197135446Strhodessamplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) { 198135446Strhodes sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4); 199135446Strhodes if (sq->samples == NULL) 200135446Strhodes return (ISC_R_NOMEMORY); 201135446Strhodes 202135446Strhodes sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4); 203135446Strhodes if (sq->extra == NULL) { 204135446Strhodes isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4); 205135446Strhodes sq->samples = NULL; 206135446Strhodes return (ISC_R_NOMEMORY); 207135446Strhodes } 208135446Strhodes 209135446Strhodes sq->nsamples = 0; 210135446Strhodes 211135446Strhodes return (ISC_R_SUCCESS); 212135446Strhodes} 213135446Strhodes 214135446Strhodes/* 215135446Strhodes * Add in entropy, even when the value we're adding in could be 216135446Strhodes * very large. 217135446Strhodes */ 218135446Strhodesstatic inline void 219135446Strhodesadd_entropy(isc_entropy_t *ent, isc_uint32_t entropy) { 220135446Strhodes /* clamp input. Yes, this must be done. */ 221135446Strhodes entropy = ISC_MIN(entropy, RND_POOLBITS); 222135446Strhodes /* Add in the entropy we already have. */ 223135446Strhodes entropy += ent->pool.entropy; 224135446Strhodes /* Clamp. */ 225135446Strhodes ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS); 226135446Strhodes} 227135446Strhodes 228135446Strhodes/* 229135446Strhodes * Decrement the amount of entropy the pool has. 230135446Strhodes */ 231135446Strhodesstatic inline void 232135446Strhodessubtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) { 233135446Strhodes entropy = ISC_MIN(entropy, ent->pool.entropy); 234135446Strhodes ent->pool.entropy -= entropy; 235135446Strhodes} 236135446Strhodes 237135446Strhodes/* 238135446Strhodes * Add in entropy, even when the value we're adding in could be 239135446Strhodes * very large. 240135446Strhodes */ 241135446Strhodesstatic inline void 242135446Strhodesadd_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) { 243135446Strhodes /* clamp input. Yes, this must be done. */ 244135446Strhodes pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8); 245135446Strhodes /* Add in the pseudo we already have. */ 246135446Strhodes pseudo += ent->pool.pseudo; 247135446Strhodes /* Clamp. */ 248135446Strhodes ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8); 249135446Strhodes} 250135446Strhodes 251135446Strhodes/* 252135446Strhodes * Decrement the amount of pseudo the pool has. 253135446Strhodes */ 254135446Strhodesstatic inline void 255135446Strhodessubtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) { 256135446Strhodes pseudo = ISC_MIN(pseudo, ent->pool.pseudo); 257135446Strhodes ent->pool.pseudo -= pseudo; 258135446Strhodes} 259135446Strhodes 260135446Strhodes/* 261135446Strhodes * Add one word to the pool, rotating the input as needed. 262135446Strhodes */ 263135446Strhodesstatic inline void 264135446Strhodesentropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) { 265135446Strhodes /* 266135446Strhodes * Steal some values out of the pool, and xor them into the 267135446Strhodes * word we were given. 268135446Strhodes * 269135446Strhodes * Mix the new value into the pool using xor. This will 270135446Strhodes * prevent the actual values from being known to the caller 271135446Strhodes * since the previous values are assumed to be unknown as well. 272135446Strhodes */ 273135446Strhodes val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)]; 274135446Strhodes val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)]; 275135446Strhodes val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)]; 276135446Strhodes val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)]; 277135446Strhodes val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)]; 278135446Strhodes rp->pool[rp->cursor++] ^= 279135446Strhodes ((val << rp->rotate) | (val >> (32 - rp->rotate))); 280135446Strhodes 281135446Strhodes /* 282135446Strhodes * If we have looped around the pool, increment the rotate 283135446Strhodes * variable so the next value will get xored in rotated to 284135446Strhodes * a different position. 285135446Strhodes * Increment by a value that is relativly prime to the word size 286135446Strhodes * to try to spread the bits throughout the pool quickly when the 287135446Strhodes * pool is empty. 288135446Strhodes */ 289135446Strhodes if (rp->cursor == RND_POOLWORDS) { 290135446Strhodes rp->cursor = 0; 291135446Strhodes rp->rotate = (rp->rotate + 7) & 31; 292135446Strhodes } 293135446Strhodes} 294135446Strhodes 295135446Strhodes/* 296135446Strhodes * Add a buffer's worth of data to the pool. 297135446Strhodes * 298135446Strhodes * Requires that the lock is held on the entropy pool. 299135446Strhodes */ 300135446Strhodesstatic void 301135446Strhodesentropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len, 302135446Strhodes isc_uint32_t entropy) 303135446Strhodes{ 304135446Strhodes isc_uint32_t val; 305135446Strhodes unsigned long addr; 306135446Strhodes isc_uint8_t *buf; 307135446Strhodes 308135446Strhodes addr = (unsigned long)p; 309135446Strhodes buf = p; 310135446Strhodes 311135446Strhodes if ((addr & 0x03U) != 0U) { 312135446Strhodes val = 0; 313135446Strhodes switch (len) { 314135446Strhodes case 3: 315135446Strhodes val = *buf++; 316135446Strhodes len--; 317135446Strhodes case 2: 318135446Strhodes val = val << 8 | *buf++; 319135446Strhodes len--; 320135446Strhodes case 1: 321135446Strhodes val = val << 8 | *buf++; 322135446Strhodes len--; 323135446Strhodes } 324135446Strhodes 325135446Strhodes entropypool_add_word(&ent->pool, val); 326135446Strhodes } 327135446Strhodes 328135446Strhodes for (; len > 3; len -= 4) { 329135446Strhodes val = *((isc_uint32_t *)buf); 330135446Strhodes 331135446Strhodes entropypool_add_word(&ent->pool, val); 332135446Strhodes buf += 4; 333135446Strhodes } 334135446Strhodes 335135446Strhodes if (len != 0) { 336135446Strhodes val = 0; 337135446Strhodes switch (len) { 338135446Strhodes case 3: 339135446Strhodes val = *buf++; 340135446Strhodes case 2: 341135446Strhodes val = val << 8 | *buf++; 342135446Strhodes case 1: 343135446Strhodes val = val << 8 | *buf++; 344135446Strhodes } 345135446Strhodes 346135446Strhodes entropypool_add_word(&ent->pool, val); 347135446Strhodes } 348135446Strhodes 349135446Strhodes add_entropy(ent, entropy); 350135446Strhodes subtract_pseudo(ent, entropy); 351135446Strhodes} 352135446Strhodes 353135446Strhodesstatic inline void 354135446Strhodesreseed(isc_entropy_t *ent) { 355135446Strhodes isc_time_t t; 356135446Strhodes pid_t pid; 357135446Strhodes 358135446Strhodes if (ent->initcount == 0) { 359135446Strhodes pid = getpid(); 360135446Strhodes entropypool_adddata(ent, &pid, sizeof(pid), 0); 361135446Strhodes pid = getppid(); 362135446Strhodes entropypool_adddata(ent, &pid, sizeof(pid), 0); 363135446Strhodes } 364135446Strhodes 365135446Strhodes /* 366135446Strhodes * After we've reseeded 100 times, only add new timing info every 367135446Strhodes * 50 requests. This will keep us from using lots and lots of 368135446Strhodes * CPU just to return bad pseudorandom data anyway. 369135446Strhodes */ 370135446Strhodes if (ent->initcount > 100) 371135446Strhodes if ((ent->initcount % 50) != 0) 372135446Strhodes return; 373135446Strhodes 374135446Strhodes TIME_NOW(&t); 375135446Strhodes entropypool_adddata(ent, &t, sizeof(t), 0); 376135446Strhodes ent->initcount++; 377135446Strhodes} 378135446Strhodes 379135446Strhodesstatic inline unsigned int 380135446Strhodesestimate_entropy(sample_queue_t *sq, isc_uint32_t t) { 381135446Strhodes isc_int32_t delta; 382135446Strhodes isc_int32_t delta2; 383135446Strhodes isc_int32_t delta3; 384135446Strhodes 385135446Strhodes /* 386135446Strhodes * If the time counter has overflowed, calculate the real difference. 387135446Strhodes * If it has not, it is simpler. 388135446Strhodes */ 389135446Strhodes if (t < sq->last_time) 390135446Strhodes delta = UINT_MAX - sq->last_time + t; 391135446Strhodes else 392135446Strhodes delta = sq->last_time - t; 393135446Strhodes 394135446Strhodes if (delta < 0) 395135446Strhodes delta = -delta; 396135446Strhodes 397135446Strhodes /* 398135446Strhodes * Calculate the second and third order differentials 399135446Strhodes */ 400135446Strhodes delta2 = sq->last_delta - delta; 401135446Strhodes if (delta2 < 0) 402135446Strhodes delta2 = -delta2; 403135446Strhodes 404135446Strhodes delta3 = sq->last_delta2 - delta2; 405135446Strhodes if (delta3 < 0) 406135446Strhodes delta3 = -delta3; 407135446Strhodes 408135446Strhodes sq->last_time = t; 409135446Strhodes sq->last_delta = delta; 410135446Strhodes sq->last_delta2 = delta2; 411135446Strhodes 412135446Strhodes /* 413135446Strhodes * If any delta is 0, we got no entropy. If all are non-zero, we 414135446Strhodes * might have something. 415135446Strhodes */ 416135446Strhodes if (delta == 0 || delta2 == 0 || delta3 == 0) 417135446Strhodes return 0; 418135446Strhodes 419135446Strhodes /* 420135446Strhodes * We could find the smallest delta and claim we got log2(delta) 421135446Strhodes * bits, but for now return that we found 1 bit. 422135446Strhodes */ 423135446Strhodes return 1; 424135446Strhodes} 425135446Strhodes 426135446Strhodesstatic unsigned int 427135446Strhodescrunchsamples(isc_entropy_t *ent, sample_queue_t *sq) { 428135446Strhodes unsigned int ns; 429135446Strhodes unsigned int added; 430135446Strhodes 431135446Strhodes if (sq->nsamples < 6) 432135446Strhodes return (0); 433135446Strhodes 434135446Strhodes added = 0; 435135446Strhodes sq->last_time = sq->samples[0]; 436135446Strhodes sq->last_delta = 0; 437135446Strhodes sq->last_delta2 = 0; 438135446Strhodes 439135446Strhodes /* 440135446Strhodes * Prime the values by adding in the first 4 samples in. This 441135446Strhodes * should completely initialize the delta calculations. 442135446Strhodes */ 443135446Strhodes for (ns = 0; ns < 4; ns++) 444135446Strhodes (void)estimate_entropy(sq, sq->samples[ns]); 445135446Strhodes 446135446Strhodes for (ns = 4; ns < sq->nsamples; ns++) 447135446Strhodes added += estimate_entropy(sq, sq->samples[ns]); 448135446Strhodes 449135446Strhodes entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added); 450135446Strhodes entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0); 451135446Strhodes 452135446Strhodes /* 453135446Strhodes * Move the last 4 samples into the first 4 positions, and start 454135446Strhodes * adding new samples from that point. 455135446Strhodes */ 456135446Strhodes for (ns = 0; ns < 4; ns++) { 457135446Strhodes sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns]; 458135446Strhodes sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns]; 459135446Strhodes } 460135446Strhodes 461135446Strhodes sq->nsamples = 4; 462135446Strhodes 463135446Strhodes return (added); 464135446Strhodes} 465135446Strhodes 466135446Strhodesstatic unsigned int 467135446Strhodesget_from_callback(isc_entropysource_t *source, unsigned int desired, 468135446Strhodes isc_boolean_t blocking) 469135446Strhodes{ 470135446Strhodes isc_entropy_t *ent = source->ent; 471135446Strhodes isc_cbsource_t *cbs = &source->sources.callback; 472135446Strhodes unsigned int added; 473135446Strhodes unsigned int got; 474135446Strhodes isc_result_t result; 475135446Strhodes 476135446Strhodes if (desired == 0) 477135446Strhodes return (0); 478135446Strhodes 479135446Strhodes if (source->bad) 480135446Strhodes return (0); 481135446Strhodes 482135446Strhodes if (!cbs->start_called && cbs->startfunc != NULL) { 483135446Strhodes result = cbs->startfunc(source, cbs->arg, blocking); 484135446Strhodes if (result != ISC_R_SUCCESS) 485135446Strhodes return (0); 486135446Strhodes cbs->start_called = ISC_TRUE; 487135446Strhodes } 488135446Strhodes 489135446Strhodes added = 0; 490135446Strhodes result = ISC_R_SUCCESS; 491135446Strhodes while (desired > 0 && result == ISC_R_SUCCESS) { 492135446Strhodes result = cbs->getfunc(source, cbs->arg, blocking); 493135446Strhodes if (result == ISC_R_QUEUEFULL) { 494135446Strhodes got = crunchsamples(ent, &cbs->samplequeue); 495135446Strhodes added += got; 496135446Strhodes desired -= ISC_MIN(got, desired); 497135446Strhodes result = ISC_R_SUCCESS; 498135446Strhodes } else if (result != ISC_R_SUCCESS && 499135446Strhodes result != ISC_R_NOTBLOCKING) 500135446Strhodes source->bad = ISC_TRUE; 501135446Strhodes 502135446Strhodes } 503135446Strhodes 504135446Strhodes return (added); 505135446Strhodes} 506135446Strhodes 507135446Strhodes/* 508135446Strhodes * Extract some number of bytes from the random pool, decreasing the 509135446Strhodes * estimate of randomness as each byte is extracted. 510135446Strhodes * 511135446Strhodes * Do this by stiring the pool and returning a part of hash as randomness. 512135446Strhodes * Note that no secrets are given away here since parts of the hash are 513135446Strhodes * xored together before returned. 514135446Strhodes * 515135446Strhodes * Honor the request from the caller to only return good data, any data, 516135446Strhodes * etc. 517135446Strhodes */ 518135446Strhodesisc_result_t 519135446Strhodesisc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length, 520135446Strhodes unsigned int *returned, unsigned int flags) 521135446Strhodes{ 522135446Strhodes unsigned int i; 523135446Strhodes isc_sha1_t hash; 524135446Strhodes unsigned char digest[ISC_SHA1_DIGESTLENGTH]; 525135446Strhodes isc_uint32_t remain, deltae, count, total; 526135446Strhodes isc_uint8_t *buf; 527135446Strhodes isc_boolean_t goodonly, partial, blocking; 528135446Strhodes 529135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 530135446Strhodes REQUIRE(data != NULL); 531135446Strhodes REQUIRE(length > 0); 532135446Strhodes 533135446Strhodes goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0); 534135446Strhodes partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0); 535135446Strhodes blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0); 536135446Strhodes 537135446Strhodes REQUIRE(!partial || returned != NULL); 538135446Strhodes 539135446Strhodes LOCK(&ent->lock); 540135446Strhodes 541135446Strhodes remain = length; 542135446Strhodes buf = data; 543135446Strhodes total = 0; 544135446Strhodes while (remain != 0) { 545135446Strhodes count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD); 546135446Strhodes 547135446Strhodes /* 548135446Strhodes * If we are extracting good data only, make certain we 549135446Strhodes * have enough data in our pool for this pass. If we don't, 550135446Strhodes * get some, and fail if we can't, and partial returns 551135446Strhodes * are not ok. 552135446Strhodes */ 553135446Strhodes if (goodonly) { 554135446Strhodes unsigned int fillcount; 555135446Strhodes 556135446Strhodes fillcount = ISC_MAX(remain * 8, count * 8); 557135446Strhodes 558135446Strhodes /* 559135446Strhodes * If, however, we have at least THRESHOLD_BITS 560135446Strhodes * of entropy in the pool, don't block here. It is 561135446Strhodes * better to drain the pool once in a while and 562135446Strhodes * then refill it than it is to constantly keep the 563135446Strhodes * pool full. 564135446Strhodes */ 565135446Strhodes if (ent->pool.entropy >= THRESHOLD_BITS) 566135446Strhodes fillpool(ent, fillcount, ISC_FALSE); 567135446Strhodes else 568135446Strhodes fillpool(ent, fillcount, blocking); 569135446Strhodes 570135446Strhodes /* 571135446Strhodes * Verify that we got enough entropy to do one 572135446Strhodes * extraction. If we didn't, bail. 573135446Strhodes */ 574135446Strhodes if (ent->pool.entropy < THRESHOLD_BITS) { 575135446Strhodes if (!partial) 576135446Strhodes goto zeroize; 577135446Strhodes else 578135446Strhodes goto partial_output; 579135446Strhodes } 580135446Strhodes } else { 581135446Strhodes /* 582135446Strhodes * If we've extracted half our pool size in bits 583135446Strhodes * since the last refresh, try to refresh here. 584135446Strhodes */ 585135446Strhodes if (ent->initialized < THRESHOLD_BITS) 586135446Strhodes fillpool(ent, THRESHOLD_BITS, blocking); 587135446Strhodes else 588135446Strhodes fillpool(ent, 0, ISC_FALSE); 589135446Strhodes 590135446Strhodes /* 591135446Strhodes * If we've not initialized with enough good random 592135446Strhodes * data, seed with our crappy code. 593135446Strhodes */ 594135446Strhodes if (ent->initialized < THRESHOLD_BITS) 595135446Strhodes reseed(ent); 596135446Strhodes } 597135446Strhodes 598135446Strhodes isc_sha1_init(&hash); 599135446Strhodes isc_sha1_update(&hash, (void *)(ent->pool.pool), 600135446Strhodes RND_POOLBYTES); 601135446Strhodes isc_sha1_final(&hash, digest); 602135446Strhodes 603135446Strhodes /* 604135446Strhodes * Stir the extracted data (all of it) back into the pool. 605135446Strhodes */ 606135446Strhodes entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0); 607135446Strhodes 608135446Strhodes for (i = 0; i < count; i++) 609135446Strhodes buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD]; 610135446Strhodes 611135446Strhodes buf += count; 612135446Strhodes remain -= count; 613135446Strhodes 614135446Strhodes deltae = count * 8; 615135446Strhodes deltae = ISC_MIN(deltae, ent->pool.entropy); 616135446Strhodes total += deltae; 617135446Strhodes subtract_entropy(ent, deltae); 618135446Strhodes add_pseudo(ent, count * 8); 619135446Strhodes } 620135446Strhodes 621135446Strhodes partial_output: 622135446Strhodes memset(digest, 0, sizeof(digest)); 623135446Strhodes 624135446Strhodes if (returned != NULL) 625135446Strhodes *returned = (length - remain); 626135446Strhodes 627135446Strhodes UNLOCK(&ent->lock); 628135446Strhodes 629135446Strhodes return (ISC_R_SUCCESS); 630135446Strhodes 631135446Strhodes zeroize: 632135446Strhodes /* put the entropy we almost extracted back */ 633135446Strhodes add_entropy(ent, total); 634135446Strhodes memset(data, 0, length); 635135446Strhodes memset(digest, 0, sizeof(digest)); 636135446Strhodes if (returned != NULL) 637135446Strhodes *returned = 0; 638135446Strhodes 639135446Strhodes UNLOCK(&ent->lock); 640135446Strhodes 641135446Strhodes return (ISC_R_NOENTROPY); 642135446Strhodes} 643135446Strhodes 644135446Strhodesstatic void 645135446Strhodesisc_entropypool_init(isc_entropypool_t *pool) { 646135446Strhodes pool->cursor = RND_POOLWORDS - 1; 647135446Strhodes pool->entropy = 0; 648135446Strhodes pool->pseudo = 0; 649135446Strhodes pool->rotate = 0; 650135446Strhodes memset(pool->pool, 0, RND_POOLBYTES); 651135446Strhodes} 652135446Strhodes 653135446Strhodesstatic void 654135446Strhodesisc_entropypool_invalidate(isc_entropypool_t *pool) { 655135446Strhodes pool->cursor = 0; 656135446Strhodes pool->entropy = 0; 657135446Strhodes pool->pseudo = 0; 658135446Strhodes pool->rotate = 0; 659135446Strhodes memset(pool->pool, 0, RND_POOLBYTES); 660135446Strhodes} 661135446Strhodes 662135446Strhodesisc_result_t 663135446Strhodesisc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) { 664135446Strhodes isc_result_t ret; 665135446Strhodes isc_entropy_t *ent; 666135446Strhodes 667135446Strhodes REQUIRE(mctx != NULL); 668135446Strhodes REQUIRE(entp != NULL && *entp == NULL); 669135446Strhodes 670135446Strhodes ent = isc_mem_get(mctx, sizeof(isc_entropy_t)); 671135446Strhodes if (ent == NULL) 672135446Strhodes return (ISC_R_NOMEMORY); 673135446Strhodes 674135446Strhodes /* 675135446Strhodes * We need a lock. 676135446Strhodes */ 677135446Strhodes if (isc_mutex_init(&ent->lock) != ISC_R_SUCCESS) { 678135446Strhodes ret = ISC_R_UNEXPECTED; 679135446Strhodes goto errout; 680135446Strhodes } 681135446Strhodes 682135446Strhodes /* 683135446Strhodes * From here down, no failures will/can occur. 684135446Strhodes */ 685135446Strhodes ISC_LIST_INIT(ent->sources); 686135446Strhodes ent->nextsource = NULL; 687135446Strhodes ent->nsources = 0; 688135446Strhodes ent->mctx = NULL; 689135446Strhodes isc_mem_attach(mctx, &ent->mctx); 690135446Strhodes ent->refcnt = 1; 691135446Strhodes ent->initialized = 0; 692135446Strhodes ent->initcount = 0; 693135446Strhodes ent->magic = ENTROPY_MAGIC; 694135446Strhodes 695135446Strhodes isc_entropypool_init(&ent->pool); 696135446Strhodes 697135446Strhodes *entp = ent; 698135446Strhodes return (ISC_R_SUCCESS); 699135446Strhodes 700135446Strhodes errout: 701135446Strhodes isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); 702135446Strhodes 703135446Strhodes return (ret); 704135446Strhodes} 705135446Strhodes 706135446Strhodes/* 707135446Strhodes * Requires "ent" be locked. 708135446Strhodes */ 709135446Strhodesstatic void 710135446Strhodesdestroysource(isc_entropysource_t **sourcep) { 711135446Strhodes isc_entropysource_t *source; 712135446Strhodes isc_entropy_t *ent; 713135446Strhodes isc_cbsource_t *cbs; 714135446Strhodes 715135446Strhodes source = *sourcep; 716135446Strhodes *sourcep = NULL; 717135446Strhodes ent = source->ent; 718135446Strhodes 719135446Strhodes ISC_LIST_UNLINK(ent->sources, source, link); 720135446Strhodes ent->nextsource = NULL; 721135446Strhodes REQUIRE(ent->nsources > 0); 722135446Strhodes ent->nsources--; 723135446Strhodes 724135446Strhodes switch (source->type) { 725135446Strhodes case ENTROPY_SOURCETYPE_FILE: 726135446Strhodes if (! source->bad) 727135446Strhodes destroyfilesource(&source->sources.file); 728135446Strhodes break; 729135446Strhodes case ENTROPY_SOURCETYPE_USOCKET: 730135446Strhodes if (! source->bad) 731135446Strhodes destroyusocketsource(&source->sources.usocket); 732135446Strhodes break; 733135446Strhodes case ENTROPY_SOURCETYPE_SAMPLE: 734135446Strhodes samplequeue_release(ent, &source->sources.sample.samplequeue); 735135446Strhodes break; 736135446Strhodes case ENTROPY_SOURCETYPE_CALLBACK: 737135446Strhodes cbs = &source->sources.callback; 738135446Strhodes if (cbs->start_called && cbs->stopfunc != NULL) { 739135446Strhodes cbs->stopfunc(source, cbs->arg); 740135446Strhodes cbs->start_called = ISC_FALSE; 741135446Strhodes } 742135446Strhodes samplequeue_release(ent, &cbs->samplequeue); 743135446Strhodes break; 744135446Strhodes } 745135446Strhodes 746135446Strhodes memset(source, 0, sizeof(isc_entropysource_t)); 747135446Strhodes 748135446Strhodes isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); 749135446Strhodes} 750135446Strhodes 751135446Strhodesstatic inline isc_boolean_t 752135446Strhodesdestroy_check(isc_entropy_t *ent) { 753135446Strhodes isc_entropysource_t *source; 754135446Strhodes 755135446Strhodes if (ent->refcnt > 0) 756135446Strhodes return (ISC_FALSE); 757135446Strhodes 758135446Strhodes source = ISC_LIST_HEAD(ent->sources); 759135446Strhodes while (source != NULL) { 760135446Strhodes switch (source->type) { 761135446Strhodes case ENTROPY_SOURCETYPE_FILE: 762135446Strhodes case ENTROPY_SOURCETYPE_USOCKET: 763135446Strhodes break; 764135446Strhodes default: 765135446Strhodes return (ISC_FALSE); 766135446Strhodes } 767135446Strhodes source = ISC_LIST_NEXT(source, link); 768135446Strhodes } 769135446Strhodes 770135446Strhodes return (ISC_TRUE); 771135446Strhodes} 772135446Strhodes 773135446Strhodesstatic void 774135446Strhodesdestroy(isc_entropy_t **entp) { 775135446Strhodes isc_entropy_t *ent; 776135446Strhodes isc_entropysource_t *source; 777135446Strhodes isc_mem_t *mctx; 778135446Strhodes 779135446Strhodes REQUIRE(entp != NULL && *entp != NULL); 780135446Strhodes ent = *entp; 781135446Strhodes *entp = NULL; 782135446Strhodes 783135446Strhodes LOCK(&ent->lock); 784135446Strhodes 785135446Strhodes REQUIRE(ent->refcnt == 0); 786135446Strhodes 787135446Strhodes /* 788135446Strhodes * Here, detach non-sample sources. 789135446Strhodes */ 790135446Strhodes source = ISC_LIST_HEAD(ent->sources); 791135446Strhodes while (source != NULL) { 792135446Strhodes switch(source->type) { 793135446Strhodes case ENTROPY_SOURCETYPE_FILE: 794135446Strhodes case ENTROPY_SOURCETYPE_USOCKET: 795135446Strhodes destroysource(&source); 796135446Strhodes break; 797135446Strhodes } 798135446Strhodes source = ISC_LIST_HEAD(ent->sources); 799135446Strhodes } 800135446Strhodes 801135446Strhodes /* 802135446Strhodes * If there are other types of sources, we've found a bug. 803135446Strhodes */ 804135446Strhodes REQUIRE(ISC_LIST_EMPTY(ent->sources)); 805135446Strhodes 806135446Strhodes mctx = ent->mctx; 807135446Strhodes 808135446Strhodes isc_entropypool_invalidate(&ent->pool); 809135446Strhodes 810135446Strhodes UNLOCK(&ent->lock); 811135446Strhodes 812135446Strhodes DESTROYLOCK(&ent->lock); 813135446Strhodes 814135446Strhodes memset(ent, 0, sizeof(isc_entropy_t)); 815135446Strhodes isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); 816135446Strhodes isc_mem_detach(&mctx); 817135446Strhodes} 818135446Strhodes 819135446Strhodesvoid 820135446Strhodesisc_entropy_destroysource(isc_entropysource_t **sourcep) { 821135446Strhodes isc_entropysource_t *source; 822135446Strhodes isc_entropy_t *ent; 823135446Strhodes isc_boolean_t killit; 824135446Strhodes 825135446Strhodes REQUIRE(sourcep != NULL); 826135446Strhodes REQUIRE(VALID_SOURCE(*sourcep)); 827135446Strhodes 828135446Strhodes source = *sourcep; 829135446Strhodes *sourcep = NULL; 830135446Strhodes 831135446Strhodes ent = source->ent; 832135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 833135446Strhodes 834135446Strhodes LOCK(&ent->lock); 835135446Strhodes 836135446Strhodes destroysource(&source); 837135446Strhodes 838135446Strhodes killit = destroy_check(ent); 839135446Strhodes 840135446Strhodes UNLOCK(&ent->lock); 841135446Strhodes 842135446Strhodes if (killit) 843135446Strhodes destroy(&ent); 844135446Strhodes} 845135446Strhodes 846135446Strhodesisc_result_t 847135446Strhodesisc_entropy_createcallbacksource(isc_entropy_t *ent, 848135446Strhodes isc_entropystart_t start, 849135446Strhodes isc_entropyget_t get, 850135446Strhodes isc_entropystop_t stop, 851135446Strhodes void *arg, 852135446Strhodes isc_entropysource_t **sourcep) 853135446Strhodes{ 854135446Strhodes isc_result_t ret; 855135446Strhodes isc_entropysource_t *source; 856135446Strhodes isc_cbsource_t *cbs; 857135446Strhodes 858135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 859135446Strhodes REQUIRE(get != NULL); 860135446Strhodes REQUIRE(sourcep != NULL && *sourcep == NULL); 861135446Strhodes 862135446Strhodes LOCK(&ent->lock); 863135446Strhodes 864135446Strhodes source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); 865135446Strhodes if (source == NULL) { 866135446Strhodes ret = ISC_R_NOMEMORY; 867135446Strhodes goto errout; 868135446Strhodes } 869135446Strhodes source->bad = ISC_FALSE; 870135446Strhodes 871135446Strhodes cbs = &source->sources.callback; 872135446Strhodes 873135446Strhodes ret = samplesource_allocate(ent, &cbs->samplequeue); 874135446Strhodes if (ret != ISC_R_SUCCESS) 875135446Strhodes goto errout; 876135446Strhodes 877135446Strhodes cbs->start_called = ISC_FALSE; 878135446Strhodes cbs->startfunc = start; 879135446Strhodes cbs->getfunc = get; 880135446Strhodes cbs->stopfunc = stop; 881135446Strhodes cbs->arg = arg; 882135446Strhodes 883135446Strhodes /* 884135446Strhodes * From here down, no failures can occur. 885135446Strhodes */ 886135446Strhodes source->magic = SOURCE_MAGIC; 887135446Strhodes source->type = ENTROPY_SOURCETYPE_CALLBACK; 888135446Strhodes source->ent = ent; 889135446Strhodes source->total = 0; 890135446Strhodes memset(source->name, 0, sizeof(source->name)); 891135446Strhodes ISC_LINK_INIT(source, link); 892135446Strhodes 893135446Strhodes /* 894135446Strhodes * Hook it into the entropy system. 895135446Strhodes */ 896135446Strhodes ISC_LIST_APPEND(ent->sources, source, link); 897135446Strhodes ent->nsources++; 898135446Strhodes 899135446Strhodes *sourcep = source; 900135446Strhodes 901135446Strhodes UNLOCK(&ent->lock); 902135446Strhodes return (ISC_R_SUCCESS); 903135446Strhodes 904135446Strhodes errout: 905135446Strhodes if (source != NULL) 906135446Strhodes isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); 907135446Strhodes 908135446Strhodes UNLOCK(&ent->lock); 909135446Strhodes 910135446Strhodes return (ret); 911135446Strhodes} 912135446Strhodes 913135446Strhodesvoid 914135446Strhodesisc_entropy_stopcallbacksources(isc_entropy_t *ent) { 915135446Strhodes isc_entropysource_t *source; 916135446Strhodes isc_cbsource_t *cbs; 917135446Strhodes 918135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 919135446Strhodes 920135446Strhodes LOCK(&ent->lock); 921135446Strhodes 922135446Strhodes source = ISC_LIST_HEAD(ent->sources); 923135446Strhodes while (source != NULL) { 924135446Strhodes if (source->type == ENTROPY_SOURCETYPE_CALLBACK) { 925135446Strhodes cbs = &source->sources.callback; 926135446Strhodes if (cbs->start_called && cbs->stopfunc != NULL) { 927135446Strhodes cbs->stopfunc(source, cbs->arg); 928135446Strhodes cbs->start_called = ISC_FALSE; 929135446Strhodes } 930135446Strhodes } 931135446Strhodes 932135446Strhodes source = ISC_LIST_NEXT(source, link); 933135446Strhodes } 934135446Strhodes 935135446Strhodes UNLOCK(&ent->lock); 936135446Strhodes} 937135446Strhodes 938135446Strhodesisc_result_t 939135446Strhodesisc_entropy_createsamplesource(isc_entropy_t *ent, 940135446Strhodes isc_entropysource_t **sourcep) 941135446Strhodes{ 942135446Strhodes isc_result_t ret; 943135446Strhodes isc_entropysource_t *source; 944135446Strhodes sample_queue_t *sq; 945135446Strhodes 946135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 947135446Strhodes REQUIRE(sourcep != NULL && *sourcep == NULL); 948135446Strhodes 949135446Strhodes LOCK(&ent->lock); 950135446Strhodes 951135446Strhodes source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); 952135446Strhodes if (source == NULL) { 953135446Strhodes ret = ISC_R_NOMEMORY; 954135446Strhodes goto errout; 955135446Strhodes } 956135446Strhodes 957135446Strhodes sq = &source->sources.sample.samplequeue; 958135446Strhodes ret = samplesource_allocate(ent, sq); 959135446Strhodes if (ret != ISC_R_SUCCESS) 960135446Strhodes goto errout; 961135446Strhodes 962135446Strhodes /* 963135446Strhodes * From here down, no failures can occur. 964135446Strhodes */ 965135446Strhodes source->magic = SOURCE_MAGIC; 966135446Strhodes source->type = ENTROPY_SOURCETYPE_SAMPLE; 967135446Strhodes source->ent = ent; 968135446Strhodes source->total = 0; 969135446Strhodes memset(source->name, 0, sizeof(source->name)); 970135446Strhodes ISC_LINK_INIT(source, link); 971135446Strhodes 972135446Strhodes /* 973135446Strhodes * Hook it into the entropy system. 974135446Strhodes */ 975135446Strhodes ISC_LIST_APPEND(ent->sources, source, link); 976135446Strhodes ent->nsources++; 977135446Strhodes 978135446Strhodes *sourcep = source; 979135446Strhodes 980135446Strhodes UNLOCK(&ent->lock); 981135446Strhodes return (ISC_R_SUCCESS); 982135446Strhodes 983135446Strhodes errout: 984135446Strhodes if (source != NULL) 985135446Strhodes isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); 986135446Strhodes 987135446Strhodes UNLOCK(&ent->lock); 988135446Strhodes 989135446Strhodes return (ret); 990135446Strhodes} 991135446Strhodes 992135446Strhodes/* 993135446Strhodes * Add a sample, and return ISC_R_SUCCESS if the queue has become full, 994135446Strhodes * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the 995135446Strhodes * queue was full when this function was called. 996135446Strhodes */ 997135446Strhodesstatic isc_result_t 998135446Strhodesaddsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) { 999135446Strhodes if (sq->nsamples >= RND_EVENTQSIZE) 1000135446Strhodes return (ISC_R_NOMORE); 1001135446Strhodes 1002135446Strhodes sq->samples[sq->nsamples] = sample; 1003135446Strhodes sq->extra[sq->nsamples] = extra; 1004135446Strhodes sq->nsamples++; 1005135446Strhodes 1006135446Strhodes if (sq->nsamples >= RND_EVENTQSIZE) 1007135446Strhodes return (ISC_R_QUEUEFULL); 1008135446Strhodes 1009135446Strhodes return (ISC_R_SUCCESS); 1010135446Strhodes} 1011135446Strhodes 1012135446Strhodesisc_result_t 1013135446Strhodesisc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample, 1014135446Strhodes isc_uint32_t extra) 1015135446Strhodes{ 1016135446Strhodes isc_entropy_t *ent; 1017135446Strhodes sample_queue_t *sq; 1018135446Strhodes unsigned int entropy; 1019135446Strhodes isc_result_t result; 1020135446Strhodes 1021135446Strhodes REQUIRE(VALID_SOURCE(source)); 1022135446Strhodes 1023135446Strhodes ent = source->ent; 1024135446Strhodes 1025135446Strhodes LOCK(&ent->lock); 1026135446Strhodes 1027135446Strhodes sq = &source->sources.sample.samplequeue; 1028135446Strhodes result = addsample(sq, sample, extra); 1029135446Strhodes if (result == ISC_R_QUEUEFULL) { 1030135446Strhodes entropy = crunchsamples(ent, sq); 1031135446Strhodes add_entropy(ent, entropy); 1032135446Strhodes } 1033135446Strhodes 1034135446Strhodes UNLOCK(&ent->lock); 1035135446Strhodes 1036135446Strhodes return (result); 1037135446Strhodes} 1038135446Strhodes 1039135446Strhodesisc_result_t 1040135446Strhodesisc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample, 1041135446Strhodes isc_uint32_t extra) 1042135446Strhodes{ 1043135446Strhodes sample_queue_t *sq; 1044135446Strhodes isc_result_t result; 1045135446Strhodes 1046135446Strhodes REQUIRE(VALID_SOURCE(source)); 1047135446Strhodes REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK); 1048135446Strhodes 1049135446Strhodes sq = &source->sources.callback.samplequeue; 1050135446Strhodes result = addsample(sq, sample, extra); 1051135446Strhodes 1052135446Strhodes return (result); 1053135446Strhodes} 1054135446Strhodes 1055135446Strhodesvoid 1056135446Strhodesisc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length, 1057135446Strhodes isc_uint32_t entropy) 1058135446Strhodes{ 1059135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 1060135446Strhodes 1061135446Strhodes LOCK(&ent->lock); 1062135446Strhodes 1063135446Strhodes entropypool_adddata(ent, data, length, entropy); 1064135446Strhodes 1065135446Strhodes if (ent->initialized < THRESHOLD_BITS) 1066135446Strhodes ent->initialized = THRESHOLD_BITS; 1067135446Strhodes 1068135446Strhodes UNLOCK(&ent->lock); 1069135446Strhodes} 1070135446Strhodes 1071135446Strhodesstatic void 1072135446Strhodesdumpstats(isc_entropy_t *ent, FILE *out) { 1073135446Strhodes fprintf(out, 1074135446Strhodes isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY, 1075135446Strhodes ISC_MSG_ENTROPYSTATS, 1076135446Strhodes "Entropy pool %p: refcnt %u cursor %u," 1077135446Strhodes " rotate %u entropy %u pseudo %u nsources %u" 1078135446Strhodes " nextsource %p initialized %u initcount %u\n"), 1079135446Strhodes ent, ent->refcnt, 1080135446Strhodes ent->pool.cursor, ent->pool.rotate, 1081135446Strhodes ent->pool.entropy, ent->pool.pseudo, 1082135446Strhodes ent->nsources, ent->nextsource, ent->initialized, 1083135446Strhodes ent->initcount); 1084135446Strhodes} 1085135446Strhodes 1086135446Strhodes/* 1087135446Strhodes * This function ignores locking. Use at your own risk. 1088135446Strhodes */ 1089135446Strhodesvoid 1090135446Strhodesisc_entropy_stats(isc_entropy_t *ent, FILE *out) { 1091135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 1092135446Strhodes 1093135446Strhodes LOCK(&ent->lock); 1094135446Strhodes dumpstats(ent, out); 1095135446Strhodes UNLOCK(&ent->lock); 1096135446Strhodes} 1097135446Strhodes 1098135446Strhodesvoid 1099135446Strhodesisc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) { 1100135446Strhodes REQUIRE(VALID_ENTROPY(ent)); 1101135446Strhodes REQUIRE(entp != NULL && *entp == NULL); 1102135446Strhodes 1103135446Strhodes LOCK(&ent->lock); 1104135446Strhodes 1105135446Strhodes ent->refcnt++; 1106135446Strhodes *entp = ent; 1107135446Strhodes 1108135446Strhodes UNLOCK(&ent->lock); 1109135446Strhodes} 1110135446Strhodes 1111135446Strhodesvoid 1112135446Strhodesisc_entropy_detach(isc_entropy_t **entp) { 1113135446Strhodes isc_entropy_t *ent; 1114135446Strhodes isc_boolean_t killit; 1115135446Strhodes 1116135446Strhodes REQUIRE(entp != NULL && VALID_ENTROPY(*entp)); 1117135446Strhodes ent = *entp; 1118135446Strhodes *entp = NULL; 1119135446Strhodes 1120135446Strhodes LOCK(&ent->lock); 1121135446Strhodes 1122135446Strhodes REQUIRE(ent->refcnt > 0); 1123135446Strhodes ent->refcnt--; 1124135446Strhodes 1125135446Strhodes killit = destroy_check(ent); 1126135446Strhodes 1127135446Strhodes UNLOCK(&ent->lock); 1128135446Strhodes 1129135446Strhodes if (killit) 1130135446Strhodes destroy(&ent); 1131135446Strhodes} 1132135446Strhodes 1133135446Strhodesstatic isc_result_t 1134135446Strhodeskbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { 1135135446Strhodes /* 1136135446Strhodes * The intent of "first" is to provide a warning message only once 1137135446Strhodes * during the run of a program that might try to gather keyboard 1138135446Strhodes * entropy multiple times. 1139135446Strhodes */ 1140135446Strhodes static isc_boolean_t first = ISC_TRUE; 1141135446Strhodes 1142135446Strhodes UNUSED(arg); 1143135446Strhodes 1144135446Strhodes if (! blocking) 1145135446Strhodes return (ISC_R_NOENTROPY); 1146135446Strhodes 1147135446Strhodes if (first) { 1148135446Strhodes if (source->warn_keyboard) 1149135446Strhodes fprintf(stderr, "You must use the keyboard to create " 1150135446Strhodes "entropy, since your system is lacking\n" 1151135446Strhodes "/dev/random (or equivalent)\n\n"); 1152135446Strhodes first = ISC_FALSE; 1153135446Strhodes } 1154135446Strhodes fprintf(stderr, "start typing:\n"); 1155135446Strhodes 1156135446Strhodes return (isc_keyboard_open(&source->kbd)); 1157135446Strhodes} 1158135446Strhodes 1159135446Strhodesstatic void 1160135446Strhodeskbdstop(isc_entropysource_t *source, void *arg) { 1161135446Strhodes 1162135446Strhodes UNUSED(arg); 1163135446Strhodes 1164135446Strhodes if (! isc_keyboard_canceled(&source->kbd)) 1165135446Strhodes fprintf(stderr, "stop typing.\r\n"); 1166135446Strhodes 1167135446Strhodes (void)isc_keyboard_close(&source->kbd, 3); 1168135446Strhodes} 1169135446Strhodes 1170135446Strhodesstatic isc_result_t 1171135446Strhodeskbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { 1172135446Strhodes isc_result_t result; 1173135446Strhodes isc_time_t t; 1174135446Strhodes isc_uint32_t sample; 1175135446Strhodes isc_uint32_t extra; 1176135446Strhodes unsigned char c; 1177135446Strhodes 1178135446Strhodes UNUSED(arg); 1179135446Strhodes 1180135446Strhodes if (!blocking) 1181135446Strhodes return (ISC_R_NOTBLOCKING); 1182135446Strhodes 1183135446Strhodes result = isc_keyboard_getchar(&source->kbd, &c); 1184135446Strhodes if (result != ISC_R_SUCCESS) 1185135446Strhodes return (result); 1186135446Strhodes 1187135446Strhodes TIME_NOW(&t); 1188135446Strhodes 1189135446Strhodes sample = isc_time_nanoseconds(&t); 1190135446Strhodes extra = c; 1191135446Strhodes 1192135446Strhodes result = isc_entropy_addcallbacksample(source, sample, extra); 1193135446Strhodes if (result != ISC_R_SUCCESS) { 1194135446Strhodes fprintf(stderr, "\r\n"); 1195135446Strhodes return (result); 1196135446Strhodes } 1197135446Strhodes 1198135446Strhodes fprintf(stderr, "."); 1199135446Strhodes fflush(stderr); 1200135446Strhodes 1201135446Strhodes return (result); 1202135446Strhodes} 1203135446Strhodes 1204135446Strhodesisc_result_t 1205135446Strhodesisc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source, 1206135446Strhodes const char *randomfile, int use_keyboard) 1207135446Strhodes{ 1208135446Strhodes isc_result_t result; 1209135446Strhodes isc_result_t final_result = ISC_R_NOENTROPY; 1210135446Strhodes isc_boolean_t userfile = ISC_TRUE; 1211135446Strhodes 1212135446Strhodes REQUIRE(VALID_ENTROPY(ectx)); 1213135446Strhodes REQUIRE(source != NULL && *source == NULL); 1214135446Strhodes REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES || 1215135446Strhodes use_keyboard == ISC_ENTROPY_KEYBOARDNO || 1216135446Strhodes use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE); 1217135446Strhodes 1218135446Strhodes#ifdef PATH_RANDOMDEV 1219135446Strhodes if (randomfile == NULL) { 1220135446Strhodes randomfile = PATH_RANDOMDEV; 1221135446Strhodes userfile = ISC_FALSE; 1222135446Strhodes } 1223135446Strhodes#endif 1224135446Strhodes 1225135446Strhodes if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) { 1226135446Strhodes result = isc_entropy_createfilesource(ectx, randomfile); 1227135446Strhodes if (result == ISC_R_SUCCESS && 1228135446Strhodes use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE) 1229135446Strhodes use_keyboard = ISC_ENTROPY_KEYBOARDNO; 1230135446Strhodes if (result != ISC_R_SUCCESS && userfile) 1231135446Strhodes return (result); 1232135446Strhodes 1233135446Strhodes final_result = result; 1234135446Strhodes } 1235135446Strhodes 1236135446Strhodes if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) { 1237135446Strhodes result = isc_entropy_createcallbacksource(ectx, kbdstart, 1238135446Strhodes kbdget, kbdstop, 1239135446Strhodes NULL, source); 1240135446Strhodes if (result == ISC_R_SUCCESS) 1241135446Strhodes (*source)->warn_keyboard = 1242135446Strhodes ISC_TF(use_keyboard == 1243135446Strhodes ISC_ENTROPY_KEYBOARDMAYBE); 1244135446Strhodes 1245135446Strhodes if (final_result != ISC_R_SUCCESS) 1246135446Strhodes final_result = result; 1247135446Strhodes } 1248135446Strhodes 1249135446Strhodes /* 1250135446Strhodes * final_result is ISC_R_SUCCESS if at least one source of entropy 1251135446Strhodes * could be started, otherwise it is the error from the most recently 1252135446Strhodes * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not 1253135446Strhodes * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO). 1254135446Strhodes */ 1255135446Strhodes return (final_result); 1256135446Strhodes} 1257