Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / isc / win32 / entropy.c
blobd58d748ebba695ec8a7070256e5938aaf3a88830
1 /* $NetBSD: entropy.c,v 1.6 2014/12/10 04:38:01 christos Exp $ */
3 /*
4 * Copyright (C) 2004, 2007, 2009, 2013 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.10 2009/01/18 23:48:14 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, (DWORD)ndesired, buf)) {
67 CryptReleaseContext(hcryptprov, 0);
68 source->bad = ISC_TRUE;
69 goto out;
72 entropypool_adddata(ent, buf,
73 (unsigned int)ndesired,
74 (unsigned int)ndesired * 8);
75 added += (unsigned int)ndesired * 8;
76 desired -= (isc_uint32_t)ndesired;
79 out:
80 return (added);
84 * Poll each source, trying to get data from it to stuff into the entropy
85 * pool.
87 static void
88 fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
89 unsigned int added;
90 unsigned int remaining;
91 unsigned int needed;
92 unsigned int nsource;
93 isc_entropysource_t *source;
94 isc_entropysource_t *firstsource;
96 REQUIRE(VALID_ENTROPY(ent));
98 needed = desired;
101 * This logic is a little strange, so an explanation is in order.
103 * If needed is 0, it means we are being asked to "fill to whatever
104 * we think is best." This means that if we have at least a
105 * partially full pool (say, > 1/4th of the pool) we probably don't
106 * need to add anything.
108 * Also, we will check to see if the "pseudo" count is too high.
109 * If it is, try to mix in better data. Too high is currently
110 * defined as 1/4th of the pool.
112 * Next, if we are asked to add a specific bit of entropy, make
113 * certain that we will do so. Clamp how much we try to add to
114 * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
116 * Note that if we are in a blocking mode, we will only try to
117 * get as much data as we need, not as much as we might want
118 * to build up.
120 if (needed == 0) {
121 REQUIRE(!blocking);
123 if ((ent->pool.entropy >= RND_POOLBITS / 4)
124 && (ent->pool.pseudo <= RND_POOLBITS / 4))
125 return;
127 needed = THRESHOLD_BITS * 4;
128 } else {
129 needed = ISC_MAX(needed, THRESHOLD_BITS);
130 needed = ISC_MIN(needed, RND_POOLBITS);
134 * In any case, clamp how much we need to how much we can add.
136 needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
139 * But wait! If we're not yet initialized, we need at least
140 * THRESHOLD_BITS
141 * of randomness.
143 if (ent->initialized < THRESHOLD_BITS)
144 needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
147 * Poll each file source to see if we can read anything useful from
148 * it. XXXMLG When where are multiple sources, we should keep a
149 * record of which one we last used so we can start from it (or the
150 * next one) to avoid letting some sources build up entropy while
151 * others are always drained.
154 added = 0;
155 remaining = needed;
156 if (ent->nextsource == NULL) {
157 ent->nextsource = ISC_LIST_HEAD(ent->sources);
158 if (ent->nextsource == NULL)
159 return;
161 source = ent->nextsource;
163 * Remember the first source so we can break if we have looped back to
164 * the beginning and still have nothing
166 firstsource = source;
167 again_file:
168 for (nsource = 0; nsource < ent->nsources; nsource++) {
169 unsigned int got;
171 if (remaining == 0)
172 break;
174 got = 0;
176 if (source->type == ENTROPY_SOURCETYPE_FILE)
177 got = get_from_filesource(source, remaining);
179 added += got;
181 remaining -= ISC_MIN(remaining, got);
183 source = ISC_LIST_NEXT(source, link);
184 if (source == NULL)
185 source = ISC_LIST_HEAD(ent->sources);
187 ent->nextsource = source;
190 * Go again only if there's been progress and we've not
191 * gone back to the beginning
193 if (!(ent->nextsource == firstsource && added == 0)) {
194 if (blocking && remaining != 0) {
195 goto again_file;
200 * Here, if there are bits remaining to be had and we can block,
201 * check to see if we have a callback source. If so, call them.
203 source = ISC_LIST_HEAD(ent->sources);
204 while ((remaining != 0) && (source != NULL)) {
205 unsigned int got;
207 got = 0;
209 if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
210 got = get_from_callback(source, remaining, blocking);
212 added += got;
213 remaining -= ISC_MIN(remaining, got);
215 if (added >= needed)
216 break;
218 source = ISC_LIST_NEXT(source, link);
222 * Mark as initialized if we've added enough data.
224 if (ent->initialized < THRESHOLD_BITS)
225 ent->initialized += added;
231 * Requires "ent" be locked.
233 static void
234 destroyfilesource(isc_entropyfilesource_t *source) {
235 CryptReleaseContext(source->handle, 0);
238 static void
239 destroyusocketsource(isc_entropyusocketsource_t *source) {
240 UNUSED(source);
244 isc_result_t
245 isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
246 isc_result_t ret;
247 isc_entropysource_t *source;
248 HCRYPTPROV hcryptprov;
249 BOOL err;
251 REQUIRE(VALID_ENTROPY(ent));
252 REQUIRE(fname != NULL);
254 LOCK(&ent->lock);
256 source = NULL;
259 * The first time we just try to acquire the context
261 err = CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL,
262 CRYPT_VERIFYCONTEXT);
263 if (!err){
264 (void)GetLastError();
265 ret = ISC_R_IOERROR;
266 goto errout;
269 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
270 if (source == NULL) {
271 ret = ISC_R_NOMEMORY;
272 goto closecontext;
276 * From here down, no failures can occur.
278 source->magic = SOURCE_MAGIC;
279 source->type = ENTROPY_SOURCETYPE_FILE;
280 source->ent = ent;
281 source->total = 0;
282 source->bad = ISC_FALSE;
283 memset(source->name, 0, sizeof(source->name));
284 ISC_LINK_INIT(source, link);
285 source->sources.file.handle = hcryptprov;
288 * Hook it into the entropy system.
290 ISC_LIST_APPEND(ent->sources, source, link);
291 ent->nsources++;
293 UNLOCK(&ent->lock);
294 return (ISC_R_SUCCESS);
296 closecontext:
297 CryptReleaseContext(hcryptprov, 0);
299 errout:
300 if (source != NULL)
301 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
303 UNLOCK(&ent->lock);
305 return (ret);