]> git.saurik.com Git - apple/xnu.git/blame - osfmk/prng/random.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / osfmk / prng / random.c
CommitLineData
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>
51
52#include <pexpert/pexpert.h>
53#include <console/serial_protos.h>
54#include <IOKit/IOPlatformExpert.h>
55
56static lck_grp_t *gPRNGGrp;
57static lck_attr_t *gPRNGAttr;
58static lck_grp_attr_t *gPRNGGrpAttr;
59static lck_mtx_t *gPRNGMutex = NULL;
60
61typedef struct prngContext {
62 struct ccdrbg_info *infop;
63 struct ccdrbg_state *statep;
64 uint64_t bytes_generated;
65 uint64_t bytes_reseeded;
66} *prngContextp;
67
68ccdrbg_factory_t prng_ccdrbg_factory = NULL;
69
70entropy_data_t EntropyData = { .index_ptr = EntropyData.buffer };
71
72boolean_t erandom_seed_set = FALSE;
73char erandom_seed[EARLY_RANDOM_SEED_SIZE];
74typedef struct ccdrbg_state ccdrbg_state_t;
75uint8_t master_erandom_state[EARLY_RANDOM_STATE_STATIC_SIZE];
76ccdrbg_state_t *erandom_state[MAX_CPUS];
77struct ccdrbg_info erandom_info;
78decl_simple_lock_data(,entropy_lock);
79
80struct ccdrbg_nisthmac_custom erandom_custom = {
81 .di = &ccsha1_eay_di,
82 .strictFIPS = 0,
83};
84
85static void read_erandom(void *buffer, u_int numBytes); /* Forward */
86
87void
88entropy_buffer_read(char *buffer,
89 unsigned int *count)
90{
91 boolean_t current_state;
92 unsigned int i, j;
93
94 if (!erandom_seed_set) {
95 panic("early_random was never invoked");
96 }
97
98 if ((*count) > (ENTROPY_BUFFER_SIZE * sizeof(unsigned int)))
99 *count = ENTROPY_BUFFER_SIZE * sizeof(unsigned int);
100
101 current_state = ml_set_interrupts_enabled(FALSE);
102#if defined (__x86_64__)
103 simple_lock(&entropy_lock);
104#endif
105
106 memcpy((char *) buffer, (char *) EntropyData.buffer, *count);
107
108 for (i = 0, j = (ENTROPY_BUFFER_SIZE - 1); i < ENTROPY_BUFFER_SIZE; j = i, i++)
109 EntropyData.buffer[i] = EntropyData.buffer[i] ^ EntropyData.buffer[j];
110
111#if defined (__x86_64__)
112 simple_unlock(&entropy_lock);
113#endif
114 (void) ml_set_interrupts_enabled(current_state);
115
116#if DEVELOPMENT || DEBUG
117 uint32_t *word = (uint32_t *) (void *) buffer;
118 /* Good for both 32-bit and 64-bit kernels. */
119 for (i = 0; i < ENTROPY_BUFFER_SIZE; i += 4)
120 /*
121 * We use "EARLY" here so that we can grab early entropy on
122 * ARM, where tracing is not started until after PRNG is
123 * initialized.
124 */
125 KERNEL_DEBUG_EARLY(ENTROPY_READ(i/4),
126 word[i+0], word[i+1], word[i+2], word[i+3]);
127#endif
128}
129
130/*
131 * Return a uniformly distributed 64-bit random number.
132 *
133 * This interface should have minimal dependencies on kernel
134 * services, and thus be available very early in the life
135 * of the kernel.
136 * This provides cryptographically secure randomness.
137 * Each processor has its own generator instance.
138 * It is seeded (lazily) with entropy provided by the Booter.
139*
140 * For <rdar://problem/17292592> the algorithm switched from LCG to
141 * NIST HMAC DBRG as follows:
142 * - When first called (on OSX this is very early while page tables are being
143 * built) early_random() calls ccdrbg_factory_hmac() to set-up a ccdbrg info
144 * structure.
145 * - The boot processor's ccdrbg state structure is a statically allocated area
146 * which is then initialized by calling the ccdbrg_init method.
147 * The initial entropy is 16 bytes of boot entropy.
148 * The nonce is the first 8 bytes of entropy xor'ed with a timestamp
149 * from ml_get_timebase().
150 * The personalization data provided is null.
151 * - The first 64-bit random value is returned on the boot processor from
152 * an invocation of the ccdbrg_generate method.
153 * - Non-boot processor's DRBG state structures are allocated dynamically
154 * from prng_init(). Each is initialized with the same 16 bytes of entropy
155 * but with a different timestamped nonce and cpu number as personalization.
156 * - Subsequent calls to early_random() pass to read_erandom() to generate
157 * an 8-byte random value. read_erandom() ensures that pre-emption is
158 * disabled and selects the DBRG state from the current processor.
159 * The ccdbrg_generate method is called for the required random output.
160 * If this method returns CCDRBG_STATUS_NEED_RESEED, the erandom_seed buffer
161 * is re-filled with kernel-harvested entropy and the ccdbrg_reseed method is
162 * called with this new entropy. The kernel panics if a reseed fails.
163 */
164uint64_t
165early_random(void)
166{
167 uint32_t cnt = 0;
168 uint64_t result;
169 uint64_t nonce;
170 int rc;
171 ccdrbg_state_t *state;
172
173 if (!erandom_seed_set) {
174 simple_lock_init(&entropy_lock,0);
175 erandom_seed_set = TRUE;
176 cnt = PE_get_random_seed((unsigned char *) EntropyData.buffer,
177 sizeof(EntropyData.buffer));
178
179 if (cnt < sizeof(EntropyData.buffer)) {
180 /*
181 * Insufficient entropy is fatal. We must fill the
182 * entire entropy buffer during initializaton.
183 */
184 panic("EntropyData needed %lu bytes, but got %u.\n",
185 sizeof(EntropyData.buffer), cnt);
186 }
187
188 /*
189 * Use some of the supplied entropy as a basis for early_random;
190 * reuse is ugly, but simplifies things. Ideally, we would guard
191 * early random values well enough that it isn't safe to attack
192 * them, but this cannot be guaranteed; thus, initial entropy
193 * can be considered 8 bytes weaker for a given boot if any
194 * early random values are conclusively determined.
195 *
196 * early_random_seed could be larger than EntopyData.buffer...
197 * but it won't be.
198 */
199 bcopy(EntropyData.buffer, &erandom_seed, sizeof(erandom_seed));
200
201 /* Init DRBG for NIST HMAC */
202 ccdrbg_factory_nisthmac(&erandom_info, &erandom_custom);
203 assert(erandom_info.size <= sizeof(master_erandom_state));
204 state = (ccdrbg_state_t *) master_erandom_state;
205 erandom_state[0] = state;
206
207 /*
208 * Init our DBRG from the boot entropy and a nonce composed of
209 * a timestamp swizzled with the first 8 bytes of this entropy.
210 */
211 assert(sizeof(erandom_seed) > sizeof(nonce));
212 bcopy(erandom_seed, &nonce, sizeof(nonce));
213 nonce ^= ml_get_timebase();
214 rc = ccdrbg_init(&erandom_info, state,
215 sizeof(erandom_seed), erandom_seed,
216 sizeof(nonce), &nonce,
217 0, NULL);
218 assert(rc == CCDRBG_STATUS_OK);
219
220 /* Generate output */
221 rc = ccdrbg_generate(&erandom_info, state,
222 sizeof(result), &result,
223 0, NULL);
224 assert(rc == CCDRBG_STATUS_OK);
225
226 return result;
227 };
228
229 read_erandom(&result, sizeof(result));
230
231 return result;
232}
233
234void
235read_erandom(void *buffer, u_int numBytes)
236{
237 int cpu;
238 int rc;
239 uint32_t cnt;
240 ccdrbg_state_t *state;
241
242 mp_disable_preemption();
243 cpu = cpu_number();
244 state = erandom_state[cpu];
245 assert(state);
246 while (TRUE) {
247 /* Generate output */
248 rc = ccdrbg_generate(&erandom_info, state,
249 numBytes, buffer,
250 0, NULL);
251 if (rc == CCDRBG_STATUS_OK)
252 break;
253 if (rc == CCDRBG_STATUS_NEED_RESEED) {
254 /* It's time to reseed. Get more entropy */
255 cnt = sizeof(erandom_seed);
256 entropy_buffer_read(erandom_seed, &cnt);
257 assert(cnt == sizeof(erandom_seed));
258 rc = ccdrbg_reseed(&erandom_info, state,
259 sizeof(erandom_seed), erandom_seed,
260 0, NULL);
261 if (rc == CCDRBG_STATUS_OK)
262 continue;
263 panic("read_erandom reseed error %d\n", rc);
264 }
265 panic("read_erandom ccdrbg error %d\n", rc);
266 }
267 mp_enable_preemption();
268}
269
270void
271read_frandom(void *buffer, u_int numBytes)
272{
273 char *cp = (char *) buffer;
274 int nbytes;
275
276 /*
277 * Split up into requests for blocks smaller than
278 * than the DBRG request limit. iThis limit is private but
279 * for NISTHMAC it's known to be greater then 4096.
280 */
281 while (numBytes) {
282 nbytes = MIN(numBytes, PAGE_SIZE);
283 read_erandom(cp, nbytes);
284 cp += nbytes;
285 numBytes -= nbytes;
286 }
287}
288
289/*
290 * Register a DRBG factory routine to e used in constructing the kernel PRNG.
291 * XXX to be called from the corecrypto kext.
292 */
293void
294prng_factory_register(ccdrbg_factory_t factory)
295{
296 prng_ccdrbg_factory = factory;
297 thread_wakeup((event_t) &prng_ccdrbg_factory);
298}
299
300void
301prng_cpu_init(int cpu)
302{
303 uint64_t nonce;
304 int rc;
305 ccdrbg_state_t *state;
306 prngContextp pp;
307
308 /*
309 * Allocate state and initialize DBRG state for early_random()
310 * for this processor, if necessary.
311 */
312 if (erandom_state[cpu] == NULL) {
313
314 state = kalloc(erandom_info.size);
315 if (state == NULL) {
316 panic("prng_init kalloc failed\n");
317 }
318 erandom_state[cpu] = state;
319
320 /*
321 * Init our DBRG from boot entropy, nonce as timestamp xor'ed
322 * with the first 8 bytes of entropy, and use the cpu number
323 * as the personalization parameter.
324 */
325 bcopy(erandom_seed, &nonce, sizeof(nonce));
326 nonce ^= ml_get_timebase();
327 rc = ccdrbg_init(&erandom_info, state,
328 sizeof(erandom_seed), erandom_seed,
329 sizeof(nonce), &nonce,
330 sizeof(cpu), &cpu);
331 assert(rc == CCDRBG_STATUS_OK);
332 }
333
334 /* Non-boot cpus use the master cpu's global context */
335 if (cpu != master_cpu) {
336 cpu_datap(cpu)->cpu_prng = master_prng_context();
337 return;
338 }
339
340 assert(gPRNGMutex == NULL); /* Once only, please */
341
342 /* make a mutex to control access */
343 gPRNGGrpAttr = lck_grp_attr_alloc_init();
344 gPRNGGrp = lck_grp_alloc_init("random", gPRNGGrpAttr);
345 gPRNGAttr = lck_attr_alloc_init();
346 gPRNGMutex = lck_mtx_alloc_init(gPRNGGrp, gPRNGAttr);
347
348 pp = kalloc(sizeof(*pp));
349 if (pp == NULL)
350 panic("Unable to allocate prng context");
351 pp->bytes_generated = 0;
352 pp->bytes_reseeded = 0;
353 pp->infop = NULL;
354
355 /* XXX Temporary registration */
356 prng_factory_register(ccdrbg_factory_yarrow);
357
358 master_prng_context() = pp;
359}
360
361static ccdrbg_info_t *
362prng_infop(prngContextp pp)
363{
364 lck_mtx_assert(gPRNGMutex, LCK_MTX_ASSERT_OWNED);
365
366 /* Usual case: the info is all set */
367 if (pp->infop)
368 return pp->infop;
369
370 /*
371 * Possibly wait for the CCDRBG factory routune to be registered
372 * by corecypto. But panic after waiting for more than 10 seconds.
373 */
374 while (prng_ccdrbg_factory == NULL ) {
375 wait_result_t wait_result;
376 assert_wait_timeout((event_t) &prng_ccdrbg_factory, TRUE,
377 10, NSEC_PER_USEC);
378 lck_mtx_unlock(gPRNGMutex);
379 wait_result = thread_block(THREAD_CONTINUE_NULL);
380 if (wait_result == THREAD_TIMED_OUT)
381 panic("prng_ccdrbg_factory registration timeout");
382 lck_mtx_lock(gPRNGMutex);
383 }
384 /* Check we didn't lose the set-up race */
385 if (pp->infop)
386 return pp->infop;
387
388 pp->infop = (ccdrbg_info_t *) kalloc(sizeof(ccdrbg_info_t));
389 if (pp->infop == NULL)
390 panic("Unable to allocate prng info");
391
392 prng_ccdrbg_factory(pp->infop, NULL);
393
394 pp->statep = kalloc(pp->infop->size);
395 if (pp->statep == NULL)
396 panic("Unable to allocate prng state");
397
398 char rdBuffer[ENTROPY_BUFFER_BYTE_SIZE];
399 unsigned int bytesToInput = sizeof(rdBuffer);
400
401 entropy_buffer_read(rdBuffer, &bytesToInput);
402
403 (void) ccdrbg_init(pp->infop, pp->statep,
404 bytesToInput, rdBuffer,
405 0, NULL,
406 0, NULL);
407 return pp->infop;
408}
409
410static void
411Reseed(prngContextp pp)
412{
413 char rdBuffer[ENTROPY_BUFFER_BYTE_SIZE];
414 unsigned int bytesToInput = sizeof(rdBuffer);
415
416 entropy_buffer_read(rdBuffer, &bytesToInput);
417
418 PRNG_CCDRBG((void) ccdrbg_reseed(pp->infop, pp->statep,
419 bytesToInput, rdBuffer,
420 0, NULL));
421
422 pp->bytes_reseeded = pp->bytes_generated;
423}
424
425
426/* export good random numbers to the rest of the kernel */
427void
428read_random(void* buffer, u_int numbytes)
429{
430 prngContextp pp;
431 ccdrbg_info_t *infop;
432 int ccdrbg_err;
433
434 lck_mtx_lock(gPRNGMutex);
435
436 pp = current_prng_context();
437 infop = prng_infop(pp);
438
439 /*
440 * Call DRBG, reseeding and retrying if requested.
441 */
442 while (TRUE) {
443 PRNG_CCDRBG(
444 ccdrbg_err = ccdrbg_generate(infop, pp->statep,
445 numbytes, buffer,
446 0, NULL));
447 if (ccdrbg_err == CCDRBG_STATUS_OK)
448 break;
449 if (ccdrbg_err == CCDRBG_STATUS_NEED_RESEED) {
450 Reseed(pp);
451 continue;
452 }
453 panic("read_random ccdrbg error %d\n", ccdrbg_err);
454 }
455
456 pp->bytes_generated += numbytes;
457 lck_mtx_unlock(gPRNGMutex);
458}
459
460int
461write_random(void* buffer, u_int numbytes)
462{
463#if 0
464 int retval = 0;
465 prngContextp pp;
466
467 lck_mtx_lock(gPRNGMutex);
468
469 pp = current_prng_context();
470
471 if (ccdrbg_reseed(prng_infop(pp), pp->statep,
472 bytesToInput, rdBuffer, 0, NULL) != 0)
473 retval = EIO;
474
475 lck_mtx_unlock(gPRNGMutex);
476 return retval;
477#else
478#pragma unused(buffer, numbytes)
479 return 0;
480#endif
481}