Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / lib / isc / win32 / entropy.c
blob1518c0feb0fe25852b5919934ca7fb7d5572549b
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: entropy.c,v 1.8.332.2 2009/01/18 23:47:41 tbox Exp */
23 * This is the system dependent part of the ISC entropy API.
26 #include <config.h>
28 #include <windows.h>
29 #include <wincrypt.h>
31 #include <process.h>
32 #include <io.h>
33 #include <share.h>
36 * There is only one variable in the entropy data structures that is not
37 * system independent, but pulling the structure that uses it into this file
38 * ultimately means pulling several other independent structures here also to
39 * resolve their interdependencies. Thus only the problem variable's type
40 * is defined here.
42 #define FILESOURCE_HANDLE_TYPE HCRYPTPROV
44 typedef struct {
45 int dummy;
46 } isc_entropyusocketsource_t;
48 #include "../entropy.c"
50 static unsigned int
51 get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
52 isc_entropy_t *ent = source->ent;
53 unsigned char buf[128];
54 HCRYPTPROV hcryptprov = source->sources.file.handle;
55 ssize_t ndesired;
56 unsigned int added;
58 if (source->bad)
59 return (0);
61 desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
63 added = 0;
64 while (desired > 0) {
65 ndesired = ISC_MIN(desired, sizeof(buf));
66 if (!CryptGenRandom(hcryptprov, ndesired, buf)) {
67 CryptReleaseContext(hcryptprov, 0);
68 source->bad = ISC_TRUE;
69 goto out;
72 entropypool_adddata(ent, buf, ndesired, ndesired * 8);
73 added += ndesired * 8;
74 desired -= ndesired;
77 out:
78 return (added);
82 * Poll each source, trying to get data from it to stuff into the entropy
83 * pool.
85 static void
86 fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
87 unsigned int added;
88 unsigned int remaining;
89 unsigned int needed;
90 unsigned int nsource;
91 isc_entropysource_t *source;
92 isc_entropysource_t *firstsource;
94 REQUIRE(VALID_ENTROPY(ent));
96 needed = desired;
99 * This logic is a little strange, so an explanation is in order.
101 * If needed is 0, it means we are being asked to "fill to whatever
102 * we think is best." This means that if we have at least a
103 * partially full pool (say, > 1/4th of the pool) we probably don't
104 * need to add anything.
106 * Also, we will check to see if the "pseudo" count is too high.
107 * If it is, try to mix in better data. Too high is currently
108 * defined as 1/4th of the pool.
110 * Next, if we are asked to add a specific bit of entropy, make
111 * certain that we will do so. Clamp how much we try to add to
112 * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
114 * Note that if we are in a blocking mode, we will only try to
115 * get as much data as we need, not as much as we might want
116 * to build up.
118 if (needed == 0) {
119 REQUIRE(!blocking);
121 if ((ent->pool.entropy >= RND_POOLBITS / 4)
122 && (ent->pool.pseudo <= RND_POOLBITS / 4))
123 return;
125 needed = THRESHOLD_BITS * 4;
126 } else {
127 needed = ISC_MAX(needed, THRESHOLD_BITS);
128 needed = ISC_MIN(needed, RND_POOLBITS);
132 * In any case, clamp how much we need to how much we can add.
134 needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
137 * But wait! If we're not yet initialized, we need at least
138 * THRESHOLD_BITS
139 * of randomness.
141 if (ent->initialized < THRESHOLD_BITS)
142 needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
145 * Poll each file source to see if we can read anything useful from
146 * it. XXXMLG When where are multiple sources, we should keep a
147 * record of which one we last used so we can start from it (or the
148 * next one) to avoid letting some sources build up entropy while
149 * others are always drained.
152 added = 0;
153 remaining = needed;
154 if (ent->nextsource == NULL) {
155 ent->nextsource = ISC_LIST_HEAD(ent->sources);
156 if (ent->nextsource == NULL)
157 return;
159 source = ent->nextsource;
161 * Remember the first source so we can break if we have looped back to
162 * the beginning and still have nothing
164 firstsource = source;
165 again_file:
166 for (nsource = 0; nsource < ent->nsources; nsource++) {
167 unsigned int got;
169 if (remaining == 0)
170 break;
172 got = 0;
174 if (source->type == ENTROPY_SOURCETYPE_FILE)
175 got = get_from_filesource(source, remaining);
177 added += got;
179 remaining -= ISC_MIN(remaining, got);
181 source = ISC_LIST_NEXT(source, link);
182 if (source == NULL)
183 source = ISC_LIST_HEAD(ent->sources);
185 ent->nextsource = source;
188 * Go again only if there's been progress and we've not
189 * gone back to the beginning
191 if (!(ent->nextsource == firstsource && added == 0)) {
192 if (blocking && remaining != 0) {
193 goto again_file;
198 * Here, if there are bits remaining to be had and we can block,
199 * check to see if we have a callback source. If so, call them.
201 source = ISC_LIST_HEAD(ent->sources);
202 while ((remaining != 0) && (source != NULL)) {
203 unsigned int got;
205 got = 0;
207 if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
208 got = get_from_callback(source, remaining, blocking);
210 added += got;
211 remaining -= ISC_MIN(remaining, got);
213 if (added >= needed)
214 break;
216 source = ISC_LIST_NEXT(source, link);
220 * Mark as initialized if we've added enough data.
222 if (ent->initialized < THRESHOLD_BITS)
223 ent->initialized += added;
229 * Requires "ent" be locked.
231 static void
232 destroyfilesource(isc_entropyfilesource_t *source) {
233 CryptReleaseContext(source->handle, 0);
236 static void
237 destroyusocketsource(isc_entropyusocketsource_t *source) {
238 UNUSED(source);
242 isc_result_t
243 isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
244 isc_result_t ret;
245 isc_entropysource_t *source;
246 HCRYPTPROV hcryptprov;
247 DWORD errval;
248 BOOL err;
250 REQUIRE(VALID_ENTROPY(ent));
251 REQUIRE(fname != NULL);
253 LOCK(&ent->lock);
255 source = NULL;
258 * The first time we just try to acquire the context
260 err = CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL,
261 CRYPT_VERIFYCONTEXT);
262 if (!err){
263 errval = GetLastError();
264 ret = ISC_R_IOERROR;
265 goto errout;
268 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
269 if (source == NULL) {
270 ret = ISC_R_NOMEMORY;
271 goto closecontext;
275 * From here down, no failures can occur.
277 source->magic = SOURCE_MAGIC;
278 source->type = ENTROPY_SOURCETYPE_FILE;
279 source->ent = ent;
280 source->total = 0;
281 source->bad = ISC_FALSE;
282 memset(source->name, 0, sizeof(source->name));
283 ISC_LINK_INIT(source, link);
284 source->sources.file.handle = hcryptprov;
287 * Hook it into the entropy system.
289 ISC_LIST_APPEND(ent->sources, source, link);
290 ent->nsources++;
292 UNLOCK(&ent->lock);
293 return (ISC_R_SUCCESS);
295 closecontext:
296 CryptReleaseContext(hcryptprov, 0);
298 errout:
299 if (source != NULL)
300 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
302 UNLOCK(&ent->lock);
304 return (ret);