]> git.saurik.com Git - apple/xnu.git/blob - osfmk/prng/random.c
b927d7f808c857a4bf2f568288be3bd67317d02c
[apple/xnu.git] / osfmk / prng / random.c
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
56 static lck_grp_t *gPRNGGrp;
57 static lck_attr_t *gPRNGAttr;
58 static lck_grp_attr_t *gPRNGGrpAttr;
59 static lck_mtx_t *gPRNGMutex = NULL;
60
61 typedef 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
68 ccdrbg_factory_t prng_ccdrbg_factory = NULL;
69
70 entropy_data_t EntropyData = { .index_ptr = EntropyData.buffer };
71
72 boolean_t erandom_seed_set = FALSE;
73 char erandom_seed[EARLY_RANDOM_SEED_SIZE];
74 typedef struct ccdrbg_state ccdrbg_state_t;
75 uint8_t master_erandom_state[EARLY_RANDOM_STATE_STATIC_SIZE];
76 ccdrbg_state_t *erandom_state[MAX_CPUS];
77 struct ccdrbg_info erandom_info;
78 decl_simple_lock_data(,entropy_lock);
79
80 struct ccdrbg_nisthmac_custom erandom_custom = {
81 .di = &ccsha1_eay_di,
82 .strictFIPS = 0,
83 };
84
85 static void read_erandom(void *buffer, u_int numBytes); /* Forward */
86
87 void
88 entropy_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 */
164 uint64_t
165 early_random(void)
166 {
167 uint32_t cnt = 0;
168 uint64_t result;
169 uint64_t nonce;
170 int rc;
171 int ps;
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 /*
209 * Init our DBRG from the boot entropy and a timestamp as nonce
210 * and the cpu number as personalization.
211 */
212 assert(sizeof(erandom_seed) > sizeof(nonce));
213 nonce = ml_get_timebase();
214 ps = 0; /* boot cpu */
215 rc = ccdrbg_init(&erandom_info, state,
216 sizeof(erandom_seed), erandom_seed,
217 sizeof(nonce), &nonce,
218 sizeof(ps), &ps);
219 cc_clear(sizeof(nonce), &nonce);
220 if (rc != CCDRBG_STATUS_OK)
221 panic("ccdrbg_init() returned %d", rc);
222
223 /* Generate output */
224 rc = ccdrbg_generate(&erandom_info, state,
225 sizeof(result), &result,
226 0, NULL);
227 if (rc != CCDRBG_STATUS_OK)
228 panic("ccdrbg_generate() returned %d", rc);
229
230 return result;
231 };
232
233 read_erandom(&result, sizeof(result));
234
235 return result;
236 }
237
238 static void
239 read_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);
265 cc_clear(sizeof(erandom_seed), erandom_seed);
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
275 void
276 read_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 */
298 void
299 prng_factory_register(ccdrbg_factory_t factory)
300 {
301 prng_ccdrbg_factory = factory;
302 thread_wakeup((event_t) &prng_ccdrbg_factory);
303 }
304
305 void
306 prng_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 /*
326 * Init our DBRG from boot entropy, nonce as timestamp
327 * and use the cpu number as the personalization parameter.
328 */
329 nonce = ml_get_timebase();
330 rc = ccdrbg_init(&erandom_info, state,
331 sizeof(erandom_seed), erandom_seed,
332 sizeof(nonce), &nonce,
333 sizeof(cpu), &cpu);
334 cc_clear(sizeof(nonce), &nonce);
335 if (rc != CCDRBG_STATUS_OK)
336 panic("ccdrbg_init() returned %d", rc);
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
366 static ccdrbg_info_t *
367 prng_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);
412 cc_clear(sizeof(rdBuffer), rdBuffer);
413 return pp->infop;
414 }
415
416 static void
417 Reseed(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
428 cc_clear(sizeof(rdBuffer), rdBuffer);
429 pp->bytes_reseeded = pp->bytes_generated;
430 }
431
432
433 /* export good random numbers to the rest of the kernel */
434 void
435 read_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
467 int
468 write_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 }