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>