Annotation of embedaddon/ntp/lib/isc/win32/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-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>