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>