Annotation of embedaddon/ntp/lib/isc/win32/entropy.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
! 3: * Copyright (C) 2000-2002 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.8.332.2 2009/01/18 23:47:41 tbox Exp $ */
! 19:
! 20: /*
! 21: * This is the system dependent part of the ISC entropy API.
! 22: */
! 23:
! 24: #include <config.h>
! 25:
! 26: #include <windows.h>
! 27: #include <wincrypt.h>
! 28:
! 29: #include <process.h>
! 30: #include <io.h>
! 31: #include <share.h>
! 32:
! 33: /*
! 34: * There is only one variable in the entropy data structures that is not
! 35: * system independent, but pulling the structure that uses it into this file
! 36: * ultimately means pulling several other independent structures here also to
! 37: * resolve their interdependencies. Thus only the problem variable's type
! 38: * is defined here.
! 39: */
! 40: #define FILESOURCE_HANDLE_TYPE HCRYPTPROV
! 41:
! 42: typedef struct {
! 43: int dummy;
! 44: } isc_entropyusocketsource_t;
! 45:
! 46: #include "../entropy.c"
! 47:
! 48: static unsigned int
! 49: get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
! 50: isc_entropy_t *ent = source->ent;
! 51: unsigned char buf[128];
! 52: HCRYPTPROV hcryptprov = source->sources.file.handle;
! 53: ssize_t ndesired;
! 54: unsigned int added;
! 55:
! 56: if (source->bad)
! 57: return (0);
! 58:
! 59: desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
! 60:
! 61: added = 0;
! 62: while (desired > 0) {
! 63: ndesired = ISC_MIN(desired, sizeof(buf));
! 64: if (!CryptGenRandom(hcryptprov, ndesired, buf)) {
! 65: CryptReleaseContext(hcryptprov, 0);
! 66: source->bad = ISC_TRUE;
! 67: goto out;
! 68: }
! 69:
! 70: entropypool_adddata(ent, buf, ndesired, ndesired * 8);
! 71: added += ndesired * 8;
! 72: desired -= ndesired;
! 73: }
! 74:
! 75: out:
! 76: return (added);
! 77: }
! 78:
! 79: /*
! 80: * Poll each source, trying to get data from it to stuff into the entropy
! 81: * pool.
! 82: */
! 83: static void
! 84: fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
! 85: unsigned int added;
! 86: unsigned int remaining;
! 87: unsigned int needed;
! 88: unsigned int nsource;
! 89: isc_entropysource_t *source;
! 90: isc_entropysource_t *firstsource;
! 91:
! 92: REQUIRE(VALID_ENTROPY(ent));
! 93:
! 94: needed = desired;
! 95:
! 96: /*
! 97: * This logic is a little strange, so an explanation is in order.
! 98: *
! 99: * If needed is 0, it means we are being asked to "fill to whatever
! 100: * we think is best." This means that if we have at least a
! 101: * partially full pool (say, > 1/4th of the pool) we probably don't
! 102: * need to add anything.
! 103: *
! 104: * Also, we will check to see if the "pseudo" count is too high.
! 105: * If it is, try to mix in better data. Too high is currently
! 106: * defined as 1/4th of the pool.
! 107: *
! 108: * Next, if we are asked to add a specific bit of entropy, make
! 109: * certain that we will do so. Clamp how much we try to add to
! 110: * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
! 111: *
! 112: * Note that if we are in a blocking mode, we will only try to
! 113: * get as much data as we need, not as much as we might want
! 114: * to build up.
! 115: */
! 116: if (needed == 0) {
! 117: REQUIRE(!blocking);
! 118:
! 119: if ((ent->pool.entropy >= RND_POOLBITS / 4)
! 120: && (ent->pool.pseudo <= RND_POOLBITS / 4))
! 121: return;
! 122:
! 123: needed = THRESHOLD_BITS * 4;
! 124: } else {
! 125: needed = ISC_MAX(needed, THRESHOLD_BITS);
! 126: needed = ISC_MIN(needed, RND_POOLBITS);
! 127: }
! 128:
! 129: /*
! 130: * In any case, clamp how much we need to how much we can add.
! 131: */
! 132: needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
! 133:
! 134: /*
! 135: * But wait! If we're not yet initialized, we need at least
! 136: * THRESHOLD_BITS
! 137: * of randomness.
! 138: */
! 139: if (ent->initialized < THRESHOLD_BITS)
! 140: needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
! 141:
! 142: /*
! 143: * Poll each file source to see if we can read anything useful from
! 144: * it. XXXMLG When where are multiple sources, we should keep a
! 145: * record of which one we last used so we can start from it (or the
! 146: * next one) to avoid letting some sources build up entropy while
! 147: * others are always drained.
! 148: */
! 149:
! 150: added = 0;
! 151: remaining = needed;
! 152: if (ent->nextsource == NULL) {
! 153: ent->nextsource = ISC_LIST_HEAD(ent->sources);
! 154: if (ent->nextsource == NULL)
! 155: return;
! 156: }
! 157: source = ent->nextsource;
! 158: /*
! 159: * Remember the first source so we can break if we have looped back to
! 160: * the beginning and still have nothing
! 161: */
! 162: firstsource = source;
! 163: again_file:
! 164: for (nsource = 0; nsource < ent->nsources; nsource++) {
! 165: unsigned int got;
! 166:
! 167: if (remaining == 0)
! 168: break;
! 169:
! 170: got = 0;
! 171:
! 172: if (source->type == ENTROPY_SOURCETYPE_FILE)
! 173: got = get_from_filesource(source, remaining);
! 174:
! 175: added += got;
! 176:
! 177: remaining -= ISC_MIN(remaining, got);
! 178:
! 179: source = ISC_LIST_NEXT(source, link);
! 180: if (source == NULL)
! 181: source = ISC_LIST_HEAD(ent->sources);
! 182: }
! 183: ent->nextsource = source;
! 184:
! 185: /*
! 186: * Go again only if there's been progress and we've not
! 187: * gone back to the beginning
! 188: */
! 189: if (!(ent->nextsource == firstsource && added == 0)) {
! 190: if (blocking && remaining != 0) {
! 191: goto again_file;
! 192: }
! 193: }
! 194:
! 195: /*
! 196: * Here, if there are bits remaining to be had and we can block,
! 197: * check to see if we have a callback source. If so, call them.
! 198: */
! 199: source = ISC_LIST_HEAD(ent->sources);
! 200: while ((remaining != 0) && (source != NULL)) {
! 201: unsigned int got;
! 202:
! 203: got = 0;
! 204:
! 205: if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
! 206: got = get_from_callback(source, remaining, blocking);
! 207:
! 208: added += got;
! 209: remaining -= ISC_MIN(remaining, got);
! 210:
! 211: if (added >= needed)
! 212: break;
! 213:
! 214: source = ISC_LIST_NEXT(source, link);
! 215: }
! 216:
! 217: /*
! 218: * Mark as initialized if we've added enough data.
! 219: */
! 220: if (ent->initialized < THRESHOLD_BITS)
! 221: ent->initialized += added;
! 222: }
! 223:
! 224:
! 225:
! 226: /*
! 227: * Requires "ent" be locked.
! 228: */
! 229: static void
! 230: destroyfilesource(isc_entropyfilesource_t *source) {
! 231: CryptReleaseContext(source->handle, 0);
! 232: }
! 233:
! 234: static void
! 235: destroyusocketsource(isc_entropyusocketsource_t *source) {
! 236: UNUSED(source);
! 237: }
! 238:
! 239:
! 240: isc_result_t
! 241: isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
! 242: isc_result_t ret;
! 243: isc_entropysource_t *source;
! 244: HCRYPTPROV hcryptprov;
! 245: DWORD errval;
! 246: BOOL err;
! 247:
! 248: REQUIRE(VALID_ENTROPY(ent));
! 249: REQUIRE(fname != NULL);
! 250:
! 251: LOCK(&ent->lock);
! 252:
! 253: source = NULL;
! 254:
! 255: /*
! 256: * The first time we just try to acquire the context
! 257: */
! 258: err = CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL,
! 259: CRYPT_VERIFYCONTEXT);
! 260: if (!err){
! 261: errval = GetLastError();
! 262: ret = ISC_R_IOERROR;
! 263: goto errout;
! 264: }
! 265:
! 266: source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
! 267: if (source == NULL) {
! 268: ret = ISC_R_NOMEMORY;
! 269: goto closecontext;
! 270: }
! 271:
! 272: /*
! 273: * From here down, no failures can occur.
! 274: */
! 275: source->magic = SOURCE_MAGIC;
! 276: source->type = ENTROPY_SOURCETYPE_FILE;
! 277: source->ent = ent;
! 278: source->total = 0;
! 279: source->bad = ISC_FALSE;
! 280: memset(source->name, 0, sizeof(source->name));
! 281: ISC_LINK_INIT(source, link);
! 282: source->sources.file.handle = hcryptprov;
! 283:
! 284: /*
! 285: * Hook it into the entropy system.
! 286: */
! 287: ISC_LIST_APPEND(ent->sources, source, link);
! 288: ent->nsources++;
! 289:
! 290: UNLOCK(&ent->lock);
! 291: return (ISC_R_SUCCESS);
! 292:
! 293: closecontext:
! 294: CryptReleaseContext(hcryptprov, 0);
! 295:
! 296: errout:
! 297: if (source != NULL)
! 298: isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
! 299:
! 300: UNLOCK(&ent->lock);
! 301:
! 302: return (ret);
! 303: }
! 304:
! 305:
! 306:
! 307:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>