]> git.saurik.com Git - apple/xnu.git/blame - osfmk/prng/random.c
xnu-3789.60.24.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;
3e170ce0 171 int ps;
fe8ab488
A
172 ccdrbg_state_t *state;
173
174 if (!erandom_seed_set) {
175 simple_lock_init(&entropy_lock,0);
176 erandom_seed_set = TRUE;
177 cnt = PE_get_random_seed((unsigned char *) EntropyData.buffer,
178 sizeof(EntropyData.buffer));
179
180 if (cnt < sizeof(EntropyData.buffer)) {
181 /*
182 * Insufficient entropy is fatal. We must fill the
183 * entire entropy buffer during initializaton.
184 */
185 panic("EntropyData needed %lu bytes, but got %u.\n",
186 sizeof(EntropyData.buffer), cnt);
187 }
188
189 /*
190 * Use some of the supplied entropy as a basis for early_random;
191 * reuse is ugly, but simplifies things. Ideally, we would guard
192 * early random values well enough that it isn't safe to attack
193 * them, but this cannot be guaranteed; thus, initial entropy
194 * can be considered 8 bytes weaker for a given boot if any
195 * early random values are conclusively determined.
196 *
197 * early_random_seed could be larger than EntopyData.buffer...
198 * but it won't be.
199 */
200 bcopy(EntropyData.buffer, &erandom_seed, sizeof(erandom_seed));
201
202 /* Init DRBG for NIST HMAC */
203 ccdrbg_factory_nisthmac(&erandom_info, &erandom_custom);
204 assert(erandom_info.size <= sizeof(master_erandom_state));
205 state = (ccdrbg_state_t *) master_erandom_state;
206 erandom_state[0] = state;
207
208 /*
3e170ce0
A
209 * Init our DBRG from the boot entropy and a timestamp as nonce
210 * and the cpu number as personalization.
fe8ab488
A
211 */
212 assert(sizeof(erandom_seed) > sizeof(nonce));
3e170ce0
A
213 nonce = ml_get_timebase();
214 ps = 0; /* boot cpu */
fe8ab488
A
215 rc = ccdrbg_init(&erandom_info, state,
216 sizeof(erandom_seed), erandom_seed,
217 sizeof(nonce), &nonce,
3e170ce0
A
218 sizeof(ps), &ps);
219 cc_clear(sizeof(nonce), &nonce);
220 if (rc != CCDRBG_STATUS_OK)
221 panic("ccdrbg_init() returned %d", rc);
fe8ab488
A
222
223 /* Generate output */
224 rc = ccdrbg_generate(&erandom_info, state,
225 sizeof(result), &result,
226 0, NULL);
3e170ce0
A
227 if (rc != CCDRBG_STATUS_OK)
228 panic("ccdrbg_generate() returned %d", rc);
fe8ab488
A
229
230 return result;
231 };
232
233 read_erandom(&result, sizeof(result));
234
235 return result;
236}
237
3e170ce0 238static void
fe8ab488
A
239read_erandom(void *buffer, u_int numBytes)
240{
241 int cpu;
242 int rc;
243 uint32_t cnt;
244 ccdrbg_state_t *state;
245
246 mp_disable_preemption();
247 cpu = cpu_number();
248 state = erandom_state[cpu];
249 assert(state);
250 while (TRUE) {
251 /* Generate output */
252 rc = ccdrbg_generate(&erandom_info, state,
253 numBytes, buffer,
254 0, NULL);
255 if (rc == CCDRBG_STATUS_OK)
256 break;
257 if (rc == CCDRBG_STATUS_NEED_RESEED) {
258 /* It's time to reseed. Get more entropy */
259 cnt = sizeof(erandom_seed);
260 entropy_buffer_read(erandom_seed, &cnt);
261 assert(cnt == sizeof(erandom_seed));
262 rc = ccdrbg_reseed(&erandom_info, state,
263 sizeof(erandom_seed), erandom_seed,
264 0, NULL);
3e170ce0 265 cc_clear(sizeof(erandom_seed), erandom_seed);
fe8ab488
A
266 if (rc == CCDRBG_STATUS_OK)
267 continue;
268 panic("read_erandom reseed error %d\n", rc);
269 }
270 panic("read_erandom ccdrbg error %d\n", rc);
271 }
272 mp_enable_preemption();
273}
274
275void
276read_frandom(void *buffer, u_int numBytes)
277{
278 char *cp = (char *) buffer;
279 int nbytes;
280
281 /*
282 * Split up into requests for blocks smaller than
283 * than the DBRG request limit. iThis limit is private but
284 * for NISTHMAC it's known to be greater then 4096.
285 */
286 while (numBytes) {
287 nbytes = MIN(numBytes, PAGE_SIZE);
288 read_erandom(cp, nbytes);
289 cp += nbytes;
290 numBytes -= nbytes;
291 }
292}
293
294/*
295 * Register a DRBG factory routine to e used in constructing the kernel PRNG.
296 * XXX to be called from the corecrypto kext.
297 */
298void
299prng_factory_register(ccdrbg_factory_t factory)
300{
301 prng_ccdrbg_factory = factory;
302 thread_wakeup((event_t) &prng_ccdrbg_factory);
303}
304
305void
306prng_cpu_init(int cpu)
307{
308 uint64_t nonce;
309 int rc;
310 ccdrbg_state_t *state;
311 prngContextp pp;
312
313 /*
314 * Allocate state and initialize DBRG state for early_random()
315 * for this processor, if necessary.
316 */
317 if (erandom_state[cpu] == NULL) {
318
319 state = kalloc(erandom_info.size);
320 if (state == NULL) {
321 panic("prng_init kalloc failed\n");
322 }
323 erandom_state[cpu] = state;
324
325 /*
3e170ce0
A
326 * Init our DBRG from boot entropy, nonce as timestamp
327 * and use the cpu number as the personalization parameter.
fe8ab488 328 */
3e170ce0 329 nonce = ml_get_timebase();
fe8ab488
A
330 rc = ccdrbg_init(&erandom_info, state,
331 sizeof(erandom_seed), erandom_seed,
332 sizeof(nonce), &nonce,
333 sizeof(cpu), &cpu);
3e170ce0
A
334 cc_clear(sizeof(nonce), &nonce);
335 if (rc != CCDRBG_STATUS_OK)
336 panic("ccdrbg_init() returned %d", rc);
fe8ab488
A
337 }
338
339 /* Non-boot cpus use the master cpu's global context */
340 if (cpu != master_cpu) {
341 cpu_datap(cpu)->cpu_prng = master_prng_context();
342 return;
343 }
344
345 assert(gPRNGMutex == NULL); /* Once only, please */
346
347 /* make a mutex to control access */
348 gPRNGGrpAttr = lck_grp_attr_alloc_init();
349 gPRNGGrp = lck_grp_alloc_init("random", gPRNGGrpAttr);
350 gPRNGAttr = lck_attr_alloc_init();
351 gPRNGMutex = lck_mtx_alloc_init(gPRNGGrp, gPRNGAttr);
352
353 pp = kalloc(sizeof(*pp));
354 if (pp == NULL)
355 panic("Unable to allocate prng context");
356 pp->bytes_generated = 0;
357 pp->bytes_reseeded = 0;
358 pp->infop = NULL;
359
360 /* XXX Temporary registration */
361 prng_factory_register(ccdrbg_factory_yarrow);
362
363 master_prng_context() = pp;
364}
365
366static ccdrbg_info_t *
367prng_infop(prngContextp pp)
368{
369 lck_mtx_assert(gPRNGMutex, LCK_MTX_ASSERT_OWNED);
370
371 /* Usual case: the info is all set */
372 if (pp->infop)
373 return pp->infop;
374
375 /*
376 * Possibly wait for the CCDRBG factory routune to be registered
377 * by corecypto. But panic after waiting for more than 10 seconds.
378 */
379 while (prng_ccdrbg_factory == NULL ) {
380 wait_result_t wait_result;
381 assert_wait_timeout((event_t) &prng_ccdrbg_factory, TRUE,
382 10, NSEC_PER_USEC);
383 lck_mtx_unlock(gPRNGMutex);
384 wait_result = thread_block(THREAD_CONTINUE_NULL);
385 if (wait_result == THREAD_TIMED_OUT)
386 panic("prng_ccdrbg_factory registration timeout");
387 lck_mtx_lock(gPRNGMutex);
388 }
389 /* Check we didn't lose the set-up race */
390 if (pp->infop)
391 return pp->infop;
392
393 pp->infop = (ccdrbg_info_t *) kalloc(sizeof(ccdrbg_info_t));
394 if (pp->infop == NULL)
395 panic("Unable to allocate prng info");
396
397 prng_ccdrbg_factory(pp->infop, NULL);
398
399 pp->statep = kalloc(pp->infop->size);
400 if (pp->statep == NULL)
401 panic("Unable to allocate prng state");
402
403 char rdBuffer[ENTROPY_BUFFER_BYTE_SIZE];
404 unsigned int bytesToInput = sizeof(rdBuffer);
405
406 entropy_buffer_read(rdBuffer, &bytesToInput);
407
408 (void) ccdrbg_init(pp->infop, pp->statep,
409 bytesToInput, rdBuffer,
410 0, NULL,
411 0, NULL);
3e170ce0 412 cc_clear(sizeof(rdBuffer), rdBuffer);
fe8ab488
A
413 return pp->infop;
414}
415
416static void
417Reseed(prngContextp pp)
418{
419 char rdBuffer[ENTROPY_BUFFER_BYTE_SIZE];
420 unsigned int bytesToInput = sizeof(rdBuffer);
421
422 entropy_buffer_read(rdBuffer, &bytesToInput);
423
424 PRNG_CCDRBG((void) ccdrbg_reseed(pp->infop, pp->statep,
425 bytesToInput, rdBuffer,
426 0, NULL));
427
3e170ce0 428 cc_clear(sizeof(rdBuffer), rdBuffer);
fe8ab488
A
429 pp->bytes_reseeded = pp->bytes_generated;
430}
431
432
433/* export good random numbers to the rest of the kernel */
434void
435read_random(void* buffer, u_int numbytes)
436{
437 prngContextp pp;
438 ccdrbg_info_t *infop;
439 int ccdrbg_err;
440
441 lck_mtx_lock(gPRNGMutex);
442
443 pp = current_prng_context();
444 infop = prng_infop(pp);
445
446 /*
447 * Call DRBG, reseeding and retrying if requested.
448 */
449 while (TRUE) {
450 PRNG_CCDRBG(
451 ccdrbg_err = ccdrbg_generate(infop, pp->statep,
452 numbytes, buffer,
453 0, NULL));
454 if (ccdrbg_err == CCDRBG_STATUS_OK)
455 break;
456 if (ccdrbg_err == CCDRBG_STATUS_NEED_RESEED) {
457 Reseed(pp);
458 continue;
459 }
460 panic("read_random ccdrbg error %d\n", ccdrbg_err);
461 }
462
463 pp->bytes_generated += numbytes;
464 lck_mtx_unlock(gPRNGMutex);
465}
466
467int
468write_random(void* buffer, u_int numbytes)
469{
470#if 0
471 int retval = 0;
472 prngContextp pp;
473
474 lck_mtx_lock(gPRNGMutex);
475
476 pp = current_prng_context();
477
478 if (ccdrbg_reseed(prng_infop(pp), pp->statep,
479 bytesToInput, rdBuffer, 0, NULL) != 0)
480 retval = EIO;
481
482 lck_mtx_unlock(gPRNGMutex);
483 return retval;
484#else
485#pragma unused(buffer, numbytes)
486 return 0;
487#endif
488}