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