]>
Commit | Line | Data |
---|---|---|
fe8ab488 A |
1 | /* |
2 | * Copyright (c) 2013 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | #include <mach/machine.h> | |
30 | #include <mach/processor.h> | |
31 | #include <kern/processor.h> | |
32 | #include <kern/cpu_data.h> | |
33 | #include <kern/cpu_number.h> | |
34 | #include <kern/kalloc.h> | |
35 | #include <kern/machine.h> | |
36 | #include <kern/misc_protos.h> | |
37 | #include <kern/startup.h> | |
38 | #include <kern/sched.h> | |
39 | #include <kern/thread.h> | |
40 | #include <kern/thread_call.h> | |
41 | #include <machine/cpu_data.h> | |
42 | #include <machine/simple_lock.h> | |
43 | #include <vm/pmap.h> | |
44 | #include <vm/vm_page.h> | |
45 | #include <sys/kdebug.h> | |
46 | #include <sys/random.h> | |
47 | ||
48 | #include <prng/random.h> | |
49 | #include <corecrypto/ccdrbg.h> | |
50 | #include <corecrypto/ccsha1.h> | |
5ba3f43e A |
51 | #include <corecrypto/ccdigest.h> |
52 | #include <corecrypto/ccsha2.h> | |
fe8ab488 A |
53 | |
54 | #include <pexpert/pexpert.h> | |
55 | #include <console/serial_protos.h> | |
56 | #include <IOKit/IOPlatformExpert.h> | |
57 | ||
5ba3f43e A |
58 | #if defined(__x86_64__) |
59 | #include <i386/cpuid.h> | |
60 | ||
61 | static int rdseed_step(uint64_t *seed) | |
62 | { | |
63 | uint8_t ok; | |
64 | ||
65 | asm volatile ("rdseed %0; setc %1" : "=r" (*seed), "=qm" (ok)); | |
66 | ||
67 | return (int) ok; | |
68 | } | |
69 | ||
70 | static int rdseed_retry(uint64_t *seed, size_t nretries) | |
71 | { | |
72 | size_t i; | |
73 | ||
74 | for (i = 0; i < nretries; i += 1) { | |
75 | if (rdseed_step(seed)) { | |
76 | return 1; | |
77 | } else { | |
78 | asm volatile ("pause"); | |
79 | } | |
80 | } | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
85 | static size_t rdseed_seed(void *buf, size_t nwords) | |
86 | { | |
87 | uint64_t *buf_words; | |
88 | size_t i; | |
89 | ||
90 | if (nwords > 8) { | |
91 | nwords = 8; | |
92 | } | |
93 | ||
94 | buf_words = buf; | |
95 | for (i = 0; i < nwords; i += 1) { | |
96 | if (!rdseed_retry(buf_words + i, 10)) { | |
97 | return i; | |
98 | } | |
99 | } | |
100 | ||
101 | return nwords; | |
102 | } | |
103 | ||
104 | static int rdrand_step(uint64_t *rand) | |
105 | { | |
106 | uint8_t ok; | |
107 | ||
108 | asm volatile ("rdrand %0; setc %1" : "=r" (*rand), "=qm" (ok)); | |
109 | ||
110 | return (int) ok; | |
111 | } | |
112 | ||
113 | static int rdrand_retry(uint64_t *rand, size_t nretries) | |
114 | { | |
115 | size_t i; | |
116 | ||
117 | for (i = 0; i < nretries; i += 1) { | |
118 | if (rdrand_step(rand)) { | |
119 | return 1; | |
120 | } | |
121 | } | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | static size_t rdrand_seed(void *buf, size_t nwords) | |
127 | { | |
128 | size_t i; | |
129 | uint64_t w; | |
130 | uint8_t hash[CCSHA256_OUTPUT_SIZE]; | |
131 | const struct ccdigest_info *di = &ccsha256_ltc_di; | |
132 | ||
133 | ccdigest_di_decl(di, ctx); | |
134 | ccdigest_init(di, ctx); | |
135 | ||
136 | for (i = 0; i < 1023; i += 1) { | |
137 | if (!rdrand_retry(&w, 10)) { | |
138 | nwords = 0; | |
139 | goto out; | |
140 | } | |
141 | ccdigest_update(di, ctx, sizeof w, &w); | |
142 | } | |
143 | ||
144 | ccdigest_final(di, ctx, hash); | |
145 | ||
146 | if (nwords > 2) { | |
147 | nwords = 2; | |
148 | } | |
149 | ||
150 | memcpy(buf, hash, nwords * sizeof (uint64_t)); | |
151 | ||
152 | out: | |
153 | ccdigest_di_clear(di, ctx); | |
154 | bzero(hash, sizeof hash); | |
155 | bzero(&w, sizeof w); | |
156 | ||
157 | return nwords; | |
158 | } | |
159 | ||
160 | static void intel_entropysource(void *buf, size_t *nbytes) | |
161 | { | |
162 | size_t nwords; | |
163 | ||
164 | /* only handle complete words */ | |
165 | assert(*nbytes % sizeof (uint64_t) == 0); | |
166 | ||
167 | nwords = (*nbytes) / sizeof (uint64_t); | |
168 | if (cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_RDSEED) { | |
169 | nwords = rdseed_seed(buf, nwords); | |
170 | *nbytes = nwords * sizeof (uint64_t); | |
171 | } else if (cpuid_features() & CPUID_FEATURE_RDRAND) { | |
172 | nwords = rdrand_seed(buf, nwords); | |
173 | *nbytes = nwords * sizeof (uint64_t); | |
174 | } else { | |
175 | *nbytes = 0; | |
176 | } | |
177 | } | |
178 | ||
179 | #endif | |
180 | ||
181 | typedef void (*entropysource)(void *buf, size_t *nbytes); | |
182 | ||
183 | static const entropysource entropysources[] = { | |
184 | entropy_buffer_read, | |
185 | #if defined(__x86_64__) | |
186 | intel_entropysource, | |
187 | #endif | |
188 | }; | |
189 | ||
190 | static const size_t nsources = sizeof entropysources / sizeof entropysources[0]; | |
191 | ||
192 | static size_t entropy_readall(void *buf, size_t nbytes_persource) | |
193 | { | |
194 | uint8_t *buf_bytes = buf; | |
195 | size_t i; | |
196 | size_t nbytes_total = 0; | |
197 | ||
198 | for (i = 0; i < nsources; i += 1) { | |
199 | size_t nbytes = nbytes_persource; | |
200 | entropysources[i](buf_bytes, &nbytes); | |
201 | bzero(buf_bytes + nbytes, nbytes_persource - nbytes); | |
202 | nbytes_total += nbytes; | |
203 | buf_bytes += nbytes_persource; | |
204 | } | |
205 | ||
206 | return nbytes_total; | |
207 | } | |
208 | ||
209 | static struct { | |
210 | lck_grp_t *group; | |
211 | lck_attr_t *attrs; | |
212 | lck_grp_attr_t *group_attrs; | |
213 | lck_mtx_t *mutex; | |
214 | } lock; | |
fe8ab488 A |
215 | |
216 | typedef struct prngContext { | |
5ba3f43e A |
217 | struct ccdrbg_info *infop; |
218 | struct ccdrbg_state *statep; | |
219 | uint64_t bytes_generated; | |
220 | uint64_t bytes_reseeded; | |
fe8ab488 A |
221 | } *prngContextp; |
222 | ||
223 | ccdrbg_factory_t prng_ccdrbg_factory = NULL; | |
224 | ||
5ba3f43e A |
225 | entropy_data_t EntropyData = { |
226 | .index_ptr = EntropyData.buffer | |
227 | }; | |
fe8ab488 | 228 | |
5ba3f43e A |
229 | static struct { |
230 | uint8_t seed[nsources][EARLY_RANDOM_SEED_SIZE]; | |
231 | size_t seedset; | |
232 | uint8_t master_drbg_state[EARLY_RANDOM_STATE_STATIC_SIZE]; | |
233 | struct ccdrbg_state *drbg_states[MAX_CPUS]; | |
234 | struct ccdrbg_info drbg_info; | |
235 | const struct ccdrbg_nisthmac_custom drbg_custom; | |
236 | } erandom = { | |
237 | .drbg_custom = { | |
238 | .di = &ccsha1_eay_di, | |
239 | .strictFIPS = 0, | |
240 | } | |
fe8ab488 A |
241 | }; |
242 | ||
5ba3f43e | 243 | static void read_erandom(void *buf, uint32_t nbytes); |
fe8ab488 A |
244 | |
245 | void | |
5ba3f43e | 246 | entropy_buffer_read(void *buffer, size_t *count) |
fe8ab488 | 247 | { |
5ba3f43e A |
248 | boolean_t current_state; |
249 | unsigned int i, j; | |
fe8ab488 | 250 | |
5ba3f43e | 251 | if (!erandom.seedset) { |
fe8ab488 A |
252 | panic("early_random was never invoked"); |
253 | } | |
254 | ||
5ba3f43e A |
255 | if (*count > ENTROPY_BUFFER_BYTE_SIZE) { |
256 | *count = ENTROPY_BUFFER_BYTE_SIZE; | |
257 | } | |
fe8ab488 A |
258 | |
259 | current_state = ml_set_interrupts_enabled(FALSE); | |
fe8ab488 | 260 | |
5ba3f43e | 261 | memcpy(buffer, EntropyData.buffer, *count); |
fe8ab488 | 262 | |
5ba3f43e | 263 | /* Consider removing this mixing step rdar://problem/31668239 */ |
fe8ab488 A |
264 | for (i = 0, j = (ENTROPY_BUFFER_SIZE - 1); i < ENTROPY_BUFFER_SIZE; j = i, i++) |
265 | EntropyData.buffer[i] = EntropyData.buffer[i] ^ EntropyData.buffer[j]; | |
266 | ||
fe8ab488 A |
267 | (void) ml_set_interrupts_enabled(current_state); |
268 | ||
269 | #if DEVELOPMENT || DEBUG | |
5ba3f43e | 270 | uint32_t *word = buffer; |
fe8ab488 A |
271 | /* Good for both 32-bit and 64-bit kernels. */ |
272 | for (i = 0; i < ENTROPY_BUFFER_SIZE; i += 4) | |
5ba3f43e | 273 | /* |
fe8ab488 A |
274 | * We use "EARLY" here so that we can grab early entropy on |
275 | * ARM, where tracing is not started until after PRNG is | |
276 | * initialized. | |
277 | */ | |
278 | KERNEL_DEBUG_EARLY(ENTROPY_READ(i/4), | |
279 | word[i+0], word[i+1], word[i+2], word[i+3]); | |
280 | #endif | |
281 | } | |
282 | ||
283 | /* | |
284 | * Return a uniformly distributed 64-bit random number. | |
285 | * | |
286 | * This interface should have minimal dependencies on kernel | |
287 | * services, and thus be available very early in the life | |
288 | * of the kernel. | |
289 | * This provides cryptographically secure randomness. | |
290 | * Each processor has its own generator instance. | |
291 | * It is seeded (lazily) with entropy provided by the Booter. | |
5ba3f43e | 292 | * |
fe8ab488 A |
293 | * For <rdar://problem/17292592> the algorithm switched from LCG to |
294 | * NIST HMAC DBRG as follows: | |
295 | * - When first called (on OSX this is very early while page tables are being | |
296 | * built) early_random() calls ccdrbg_factory_hmac() to set-up a ccdbrg info | |
297 | * structure. | |
298 | * - The boot processor's ccdrbg state structure is a statically allocated area | |
299 | * which is then initialized by calling the ccdbrg_init method. | |
300 | * The initial entropy is 16 bytes of boot entropy. | |
301 | * The nonce is the first 8 bytes of entropy xor'ed with a timestamp | |
302 | * from ml_get_timebase(). | |
5ba3f43e | 303 | * The personalization data provided is null. |
fe8ab488 A |
304 | * - The first 64-bit random value is returned on the boot processor from |
305 | * an invocation of the ccdbrg_generate method. | |
306 | * - Non-boot processor's DRBG state structures are allocated dynamically | |
307 | * from prng_init(). Each is initialized with the same 16 bytes of entropy | |
308 | * but with a different timestamped nonce and cpu number as personalization. | |
309 | * - Subsequent calls to early_random() pass to read_erandom() to generate | |
310 | * an 8-byte random value. read_erandom() ensures that pre-emption is | |
311 | * disabled and selects the DBRG state from the current processor. | |
312 | * The ccdbrg_generate method is called for the required random output. | |
5ba3f43e | 313 | * If this method returns CCDRBG_STATUS_NEED_RESEED, the erandom.seed buffer |
fe8ab488 A |
314 | * is re-filled with kernel-harvested entropy and the ccdbrg_reseed method is |
315 | * called with this new entropy. The kernel panics if a reseed fails. | |
316 | */ | |
317 | uint64_t | |
318 | early_random(void) | |
319 | { | |
320 | uint32_t cnt = 0; | |
321 | uint64_t result; | |
322 | uint64_t nonce; | |
323 | int rc; | |
3e170ce0 | 324 | int ps; |
5ba3f43e | 325 | struct ccdrbg_state *state; |
fe8ab488 | 326 | |
5ba3f43e A |
327 | if (!erandom.seedset) { |
328 | erandom.seedset = 1; | |
fe8ab488 A |
329 | cnt = PE_get_random_seed((unsigned char *) EntropyData.buffer, |
330 | sizeof(EntropyData.buffer)); | |
331 | ||
332 | if (cnt < sizeof(EntropyData.buffer)) { | |
333 | /* | |
334 | * Insufficient entropy is fatal. We must fill the | |
335 | * entire entropy buffer during initializaton. | |
336 | */ | |
337 | panic("EntropyData needed %lu bytes, but got %u.\n", | |
338 | sizeof(EntropyData.buffer), cnt); | |
339 | } | |
340 | ||
5ba3f43e | 341 | entropy_readall(&erandom.seed, EARLY_RANDOM_SEED_SIZE); |
fe8ab488 A |
342 | |
343 | /* Init DRBG for NIST HMAC */ | |
5ba3f43e A |
344 | ccdrbg_factory_nisthmac(&erandom.drbg_info, &erandom.drbg_custom); |
345 | assert(erandom.drbg_info.size <= sizeof(erandom.master_drbg_state)); | |
346 | state = (struct ccdrbg_state *) erandom.master_drbg_state; | |
347 | erandom.drbg_states[master_cpu] = state; | |
fe8ab488 A |
348 | |
349 | /* | |
3e170ce0 A |
350 | * Init our DBRG from the boot entropy and a timestamp as nonce |
351 | * and the cpu number as personalization. | |
fe8ab488 | 352 | */ |
5ba3f43e | 353 | assert(sizeof(erandom.seed) > sizeof(nonce)); |
3e170ce0 A |
354 | nonce = ml_get_timebase(); |
355 | ps = 0; /* boot cpu */ | |
5ba3f43e A |
356 | rc = ccdrbg_init(&erandom.drbg_info, state, |
357 | sizeof(erandom.seed), erandom.seed, | |
fe8ab488 | 358 | sizeof(nonce), &nonce, |
3e170ce0 A |
359 | sizeof(ps), &ps); |
360 | cc_clear(sizeof(nonce), &nonce); | |
361 | if (rc != CCDRBG_STATUS_OK) | |
362 | panic("ccdrbg_init() returned %d", rc); | |
fe8ab488 A |
363 | |
364 | /* Generate output */ | |
5ba3f43e A |
365 | rc = ccdrbg_generate(&erandom.drbg_info, state, |
366 | sizeof(result), &result, | |
367 | 0, NULL); | |
3e170ce0 A |
368 | if (rc != CCDRBG_STATUS_OK) |
369 | panic("ccdrbg_generate() returned %d", rc); | |
fe8ab488 A |
370 | |
371 | return result; | |
372 | }; | |
373 | ||
374 | read_erandom(&result, sizeof(result)); | |
375 | ||
376 | return result; | |
377 | } | |
378 | ||
3e170ce0 | 379 | static void |
fe8ab488 A |
380 | read_erandom(void *buffer, u_int numBytes) |
381 | { | |
382 | int cpu; | |
383 | int rc; | |
5ba3f43e A |
384 | size_t nbytes; |
385 | struct ccdrbg_state *state; | |
fe8ab488 A |
386 | |
387 | mp_disable_preemption(); | |
388 | cpu = cpu_number(); | |
5ba3f43e | 389 | state = erandom.drbg_states[cpu]; |
fe8ab488 | 390 | assert(state); |
5ba3f43e | 391 | for (;;) { |
fe8ab488 | 392 | /* Generate output */ |
5ba3f43e A |
393 | rc = ccdrbg_generate(&erandom.drbg_info, state, |
394 | numBytes, buffer, | |
395 | 0, NULL); | |
fe8ab488 A |
396 | if (rc == CCDRBG_STATUS_OK) |
397 | break; | |
398 | if (rc == CCDRBG_STATUS_NEED_RESEED) { | |
399 | /* It's time to reseed. Get more entropy */ | |
5ba3f43e A |
400 | nbytes = entropy_readall(erandom.seed, EARLY_RANDOM_SEED_SIZE); |
401 | assert(nbytes >= EARLY_RANDOM_SEED_SIZE); | |
402 | rc = ccdrbg_reseed(&erandom.drbg_info, state, | |
403 | sizeof(erandom.seed), erandom.seed, | |
fe8ab488 | 404 | 0, NULL); |
5ba3f43e | 405 | cc_clear(sizeof(erandom.seed), erandom.seed); |
fe8ab488 A |
406 | if (rc == CCDRBG_STATUS_OK) |
407 | continue; | |
408 | panic("read_erandom reseed error %d\n", rc); | |
409 | } | |
410 | panic("read_erandom ccdrbg error %d\n", rc); | |
411 | } | |
412 | mp_enable_preemption(); | |
413 | } | |
414 | ||
415 | void | |
416 | read_frandom(void *buffer, u_int numBytes) | |
417 | { | |
5ba3f43e A |
418 | uint8_t *buffer_bytes = buffer; |
419 | int nbytes; | |
fe8ab488 A |
420 | |
421 | /* | |
422 | * Split up into requests for blocks smaller than | |
423 | * than the DBRG request limit. iThis limit is private but | |
424 | * for NISTHMAC it's known to be greater then 4096. | |
425 | */ | |
426 | while (numBytes) { | |
427 | nbytes = MIN(numBytes, PAGE_SIZE); | |
5ba3f43e A |
428 | read_erandom(buffer_bytes, nbytes); |
429 | buffer_bytes += nbytes; | |
fe8ab488 A |
430 | numBytes -= nbytes; |
431 | } | |
432 | } | |
433 | ||
434 | /* | |
435 | * Register a DRBG factory routine to e used in constructing the kernel PRNG. | |
436 | * XXX to be called from the corecrypto kext. | |
437 | */ | |
438 | void | |
439 | prng_factory_register(ccdrbg_factory_t factory) | |
440 | { | |
441 | prng_ccdrbg_factory = factory; | |
442 | thread_wakeup((event_t) &prng_ccdrbg_factory); | |
443 | } | |
444 | ||
445 | void | |
446 | prng_cpu_init(int cpu) | |
447 | { | |
448 | uint64_t nonce; | |
449 | int rc; | |
5ba3f43e | 450 | struct ccdrbg_state *state; |
fe8ab488 A |
451 | prngContextp pp; |
452 | ||
453 | /* | |
454 | * Allocate state and initialize DBRG state for early_random() | |
455 | * for this processor, if necessary. | |
456 | */ | |
5ba3f43e | 457 | if (erandom.drbg_states[cpu] == NULL) { |
fe8ab488 | 458 | |
5ba3f43e | 459 | state = kalloc(erandom.drbg_info.size); |
fe8ab488 A |
460 | if (state == NULL) { |
461 | panic("prng_init kalloc failed\n"); | |
462 | } | |
5ba3f43e | 463 | erandom.drbg_states[cpu] = state; |
fe8ab488 A |
464 | |
465 | /* | |
3e170ce0 A |
466 | * Init our DBRG from boot entropy, nonce as timestamp |
467 | * and use the cpu number as the personalization parameter. | |
fe8ab488 | 468 | */ |
3e170ce0 | 469 | nonce = ml_get_timebase(); |
5ba3f43e A |
470 | rc = ccdrbg_init(&erandom.drbg_info, state, |
471 | sizeof(erandom.seed), erandom.seed, | |
fe8ab488 A |
472 | sizeof(nonce), &nonce, |
473 | sizeof(cpu), &cpu); | |
3e170ce0 A |
474 | cc_clear(sizeof(nonce), &nonce); |
475 | if (rc != CCDRBG_STATUS_OK) | |
476 | panic("ccdrbg_init() returned %d", rc); | |
fe8ab488 A |
477 | } |
478 | ||
479 | /* Non-boot cpus use the master cpu's global context */ | |
480 | if (cpu != master_cpu) { | |
481 | cpu_datap(cpu)->cpu_prng = master_prng_context(); | |
482 | return; | |
483 | } | |
484 | ||
5ba3f43e | 485 | assert(lock.mutex == NULL); /* Once only, please */ |
fe8ab488 A |
486 | |
487 | /* make a mutex to control access */ | |
5ba3f43e A |
488 | lock.group_attrs = lck_grp_attr_alloc_init(); |
489 | lock.group = lck_grp_alloc_init("random", lock.group_attrs); | |
490 | lock.attrs = lck_attr_alloc_init(); | |
491 | lock.mutex = lck_mtx_alloc_init(lock.group, lock.attrs); | |
fe8ab488 A |
492 | |
493 | pp = kalloc(sizeof(*pp)); | |
494 | if (pp == NULL) | |
495 | panic("Unable to allocate prng context"); | |
496 | pp->bytes_generated = 0; | |
497 | pp->bytes_reseeded = 0; | |
498 | pp->infop = NULL; | |
499 | ||
500 | /* XXX Temporary registration */ | |
501 | prng_factory_register(ccdrbg_factory_yarrow); | |
502 | ||
503 | master_prng_context() = pp; | |
504 | } | |
505 | ||
5ba3f43e | 506 | static struct ccdrbg_info * |
fe8ab488 A |
507 | prng_infop(prngContextp pp) |
508 | { | |
5ba3f43e A |
509 | uint8_t buf[nsources][ENTROPY_BUFFER_BYTE_SIZE]; |
510 | size_t nbytes; | |
511 | ||
512 | lck_mtx_assert(lock.mutex, LCK_MTX_ASSERT_OWNED); | |
fe8ab488 A |
513 | |
514 | /* Usual case: the info is all set */ | |
515 | if (pp->infop) | |
516 | return pp->infop; | |
517 | ||
518 | /* | |
519 | * Possibly wait for the CCDRBG factory routune to be registered | |
520 | * by corecypto. But panic after waiting for more than 10 seconds. | |
521 | */ | |
522 | while (prng_ccdrbg_factory == NULL ) { | |
523 | wait_result_t wait_result; | |
524 | assert_wait_timeout((event_t) &prng_ccdrbg_factory, TRUE, | |
5ba3f43e A |
525 | 10, NSEC_PER_USEC); |
526 | lck_mtx_unlock(lock.mutex); | |
fe8ab488 A |
527 | wait_result = thread_block(THREAD_CONTINUE_NULL); |
528 | if (wait_result == THREAD_TIMED_OUT) | |
529 | panic("prng_ccdrbg_factory registration timeout"); | |
5ba3f43e | 530 | lck_mtx_lock(lock.mutex); |
fe8ab488 A |
531 | } |
532 | /* Check we didn't lose the set-up race */ | |
533 | if (pp->infop) | |
534 | return pp->infop; | |
535 | ||
5ba3f43e | 536 | pp->infop = (struct ccdrbg_info *) kalloc(sizeof(struct ccdrbg_info)); |
fe8ab488 A |
537 | if (pp->infop == NULL) |
538 | panic("Unable to allocate prng info"); | |
539 | ||
540 | prng_ccdrbg_factory(pp->infop, NULL); | |
541 | ||
542 | pp->statep = kalloc(pp->infop->size); | |
543 | if (pp->statep == NULL) | |
544 | panic("Unable to allocate prng state"); | |
545 | ||
5ba3f43e | 546 | nbytes = entropy_readall(buf, ENTROPY_BUFFER_BYTE_SIZE); |
fe8ab488 A |
547 | |
548 | (void) ccdrbg_init(pp->infop, pp->statep, | |
5ba3f43e | 549 | nbytes, buf, |
fe8ab488 A |
550 | 0, NULL, |
551 | 0, NULL); | |
5ba3f43e | 552 | cc_clear(sizeof (buf), buf); |
fe8ab488 A |
553 | return pp->infop; |
554 | } | |
555 | ||
556 | static void | |
557 | Reseed(prngContextp pp) | |
558 | { | |
5ba3f43e A |
559 | uint8_t buf[nsources][ENTROPY_BUFFER_BYTE_SIZE]; |
560 | size_t nbytes; | |
561 | ||
562 | nbytes = entropy_readall(buf, ENTROPY_BUFFER_BYTE_SIZE); | |
fe8ab488 A |
563 | |
564 | PRNG_CCDRBG((void) ccdrbg_reseed(pp->infop, pp->statep, | |
5ba3f43e | 565 | nbytes, buf, |
fe8ab488 A |
566 | 0, NULL)); |
567 | ||
5ba3f43e | 568 | cc_clear(sizeof (buf), buf); |
fe8ab488 A |
569 | pp->bytes_reseeded = pp->bytes_generated; |
570 | } | |
571 | ||
572 | ||
573 | /* export good random numbers to the rest of the kernel */ | |
574 | void | |
575 | read_random(void* buffer, u_int numbytes) | |
576 | { | |
5ba3f43e A |
577 | prngContextp pp; |
578 | struct ccdrbg_info *infop; | |
579 | int ccdrbg_err; | |
fe8ab488 | 580 | |
5ba3f43e | 581 | lck_mtx_lock(lock.mutex); |
fe8ab488 A |
582 | |
583 | pp = current_prng_context(); | |
584 | infop = prng_infop(pp); | |
585 | ||
586 | /* | |
587 | * Call DRBG, reseeding and retrying if requested. | |
588 | */ | |
5ba3f43e | 589 | for (;;) { |
fe8ab488 A |
590 | PRNG_CCDRBG( |
591 | ccdrbg_err = ccdrbg_generate(infop, pp->statep, | |
5ba3f43e A |
592 | numbytes, buffer, |
593 | 0, NULL)); | |
fe8ab488 A |
594 | if (ccdrbg_err == CCDRBG_STATUS_OK) |
595 | break; | |
596 | if (ccdrbg_err == CCDRBG_STATUS_NEED_RESEED) { | |
597 | Reseed(pp); | |
598 | continue; | |
599 | } | |
600 | panic("read_random ccdrbg error %d\n", ccdrbg_err); | |
601 | } | |
602 | ||
603 | pp->bytes_generated += numbytes; | |
5ba3f43e | 604 | lck_mtx_unlock(lock.mutex); |
fe8ab488 A |
605 | } |
606 | ||
607 | int | |
608 | write_random(void* buffer, u_int numbytes) | |
609 | { | |
610 | #if 0 | |
611 | int retval = 0; | |
612 | prngContextp pp; | |
613 | ||
5ba3f43e | 614 | lck_mtx_lock(lock.mutex); |
fe8ab488 A |
615 | |
616 | pp = current_prng_context(); | |
617 | ||
618 | if (ccdrbg_reseed(prng_infop(pp), pp->statep, | |
619 | bytesToInput, rdBuffer, 0, NULL) != 0) | |
620 | retval = EIO; | |
621 | ||
5ba3f43e | 622 | lck_mtx_unlock(lock.mutex); |
fe8ab488 A |
623 | return retval; |
624 | #else | |
5ba3f43e A |
625 | #pragma unused(buffer, numbytes) |
626 | return 0; | |
fe8ab488 A |
627 | #endif |
628 | } |