]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/random/randomdev.c
xnu-2422.115.4.tar.gz
[apple/xnu.git] / bsd / dev / random / randomdev.c
CommitLineData
0b4e3aa0 1/*
b0d623f7 2 * Copyright (c) 1999-2009 Apple, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0b4e3aa0 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
0b4e3aa0
A
27 */
28
b0d623f7
A
29/*
30 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
31
32 THIS FILE IS NEEDED TO PASS FIPS ACCEPTANCE FOR THE RANDOM NUMBER GENERATOR.
33 IF YOU ALTER IT IN ANY WAY, WE WILL NEED TO GO THOUGH FIPS ACCEPTANCE AGAIN,
34 AN OPERATION THAT IS VERY EXPENSIVE AND TIME CONSUMING. IN OTHER WORDS,
35 DON'T MESS WITH THIS FILE.
36
37 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
38*/
39
0b4e3aa0
A
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/proc.h>
43#include <sys/errno.h>
44#include <sys/ioctl.h>
45#include <sys/conf.h>
46#include <sys/fcntl.h>
8ad349bb 47#include <string.h>
0b4e3aa0
A
48#include <miscfs/devfs/devfs.h>
49#include <kern/lock.h>
2d21ac55 50#include <kern/clock.h>
0b4e3aa0
A
51#include <sys/time.h>
52#include <sys/malloc.h>
91447636 53#include <sys/uio_internal.h>
0b4e3aa0
A
54
55#include <dev/random/randomdev.h>
56#include <dev/random/YarrowCoreLib/include/yarrow.h>
b0d623f7
A
57
58#include <libkern/OSByteOrder.h>
bd504ef0 59#include <libkern/OSAtomic.h>
2d21ac55
A
60
61#include <mach/mach_time.h>
62#include <machine/machine_routines.h>
0b4e3aa0 63
b0d623f7
A
64#include "fips_sha1.h"
65
0b4e3aa0
A
66#define RANDOM_MAJOR -1 /* let the kernel pick the device number */
67
55e303ae
A
68d_ioctl_t random_ioctl;
69
39236c6e
A
70/* To generate the seed for the RNG */
71extern uint64_t early_random();
72
0b4e3aa0
A
73/*
74 * A struct describing which functions will get invoked for certain
75 * actions.
76 */
77static struct cdevsw random_cdevsw =
78{
79 random_open, /* open */
80 random_close, /* close */
81 random_read, /* read */
82 random_write, /* write */
91447636
A
83 random_ioctl, /* ioctl */
84 (stop_fcn_t *)nulldev, /* stop */
85 (reset_fcn_t *)nulldev, /* reset */
0b4e3aa0
A
86 NULL, /* tty's */
87 eno_select, /* select */
88 eno_mmap, /* mmap */
89 eno_strat, /* strategy */
90 eno_getc, /* getc */
91 eno_putc, /* putc */
92 0 /* type */
93};
94
d1ecb069
A
95
96/*
97 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
98
99 ANY CODE PROTECTED UNDER "#ifdef __arm__" IS SERIOUSLY SUPPOSED TO BE THERE!
100 IF YOU REMOVE ARM CODE, RANDOM WILL NOT MEAN ANYTHING FOR iPHONES ALL OVER.
101 PLEASE DON'T TOUCH __arm__ CODE IN THIS FILE!
102
103 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
104*/
105
106
0b4e3aa0 107/* Used to detect whether we've already been initialized */
bd504ef0 108static UInt8 gRandomInstalled = 0;
0b4e3aa0
A
109static PrngRef gPrngRef;
110static int gRandomError = 1;
2d21ac55
A
111static lck_grp_t *gYarrowGrp;
112static lck_attr_t *gYarrowAttr;
113static lck_grp_attr_t *gYarrowGrpAttr;
114static lck_mtx_t *gYarrowMutex = 0;
bd504ef0 115static UInt8 gYarrowInitializationLock = 0;
2d21ac55 116
0b4e3aa0
A
117#define RESEED_TICKS 50 /* how long a reseed operation can take */
118
91447636 119
b0d623f7
A
120typedef u_int8_t BlockWord;
121enum {kBSize = 20};
8ad349bb 122typedef BlockWord Block[kBSize];
b0d623f7 123enum {kBlockSize = sizeof(Block)};
8ad349bb
A
124
125/* define prototypes to keep the compiler happy... */
126
127void add_blocks(Block a, Block b, BlockWord carry);
128void fips_initialize(void);
4a3eedf9 129void random_block(Block b, int addOptional);
21362eb3 130u_int32_t CalculateCRC(u_int8_t* buffer, size_t length);
8ad349bb
A
131
132/*
133 * Get 120 bits from yarrow
134 */
135
136/*
137 * add block b to block a
138 */
139void
140add_blocks(Block a, Block b, BlockWord carry)
141{
b0d623f7
A
142 int i = kBlockSize - 1;
143 while (i >= 0)
8ad349bb 144 {
b0d623f7
A
145 u_int32_t c = (u_int32_t)carry +
146 (u_int32_t)a[i] +
147 (u_int32_t)b[i];
148 a[i] = c & 0xff;
149 carry = c >> 8;
150 i -= 1;
8ad349bb
A
151 }
152}
153
154
155
b0d623f7
A
156static char zeros[(512 - kBSize * 8) / 8];
157static Block g_xkey;
158static Block g_random_data;
159static int g_bytes_used;
160static unsigned char g_SelfTestInitialized = 0;
161static u_int32_t gLastBlockChecksum;
21362eb3
A
162
163static const u_int32_t g_crc_table[] =
164{
165 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
166 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
167 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
168 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
169 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
170 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
171 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
172 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
173 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
174 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
175 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
176 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
177 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
178 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
179 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
180 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
181 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
182 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
183 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
184 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
185 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
186 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
187 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
188 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
189 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
190 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
191 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
192 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
193 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
194 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
195 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
196 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
197};
8ad349bb
A
198
199/*
200 * Setup for fips compliance
201 */
202
21362eb3
A
203/*
204 * calculate a crc-32 checksum
205 */
206u_int32_t CalculateCRC(u_int8_t* buffer, size_t length)
207{
208 u_int32_t crc = 0;
209
210 size_t i;
211 for (i = 0; i < length; ++i)
212 {
213 u_int32_t temp = (crc ^ ((u_int32_t) buffer[i])) & 0xFF;
214 crc = (crc >> 8) ^ g_crc_table[temp];
215 }
216
217 return crc;
218}
219
8ad349bb
A
220/*
221 * get a random block of data per fips 186-2
222 */
223void
4a3eedf9 224random_block(Block b, int addOptional)
8ad349bb 225{
b0d623f7
A
226 SHA1_CTX sha1_ctx;
227
21362eb3
A
228 int repeatCount = 0;
229 do
230 {
2d21ac55 231 // do one iteration
21362eb3 232
4a3eedf9
A
233 if (addOptional)
234 {
b0d623f7 235 // create an xSeed to add.
4a3eedf9
A
236 Block xSeed;
237 prngOutput (gPrngRef, (BYTE*) &xSeed, sizeof (xSeed));
238
239 // add the seed to the previous value of g_xkey
240 add_blocks (g_xkey, xSeed, 0);
241 }
242
b0d623f7
A
243 // initialize the value of H
244 FIPS_SHA1Init(&sha1_ctx);
245
246 // to stay compatible with the FIPS specification, we need to flip the bytes in
247 // g_xkey to little endian byte order. In our case, this makes exactly no difference
248 // (random is random), but we need to do it anyway to keep FIPS happy
249
21362eb3 250 // compute "G"
b0d623f7 251 FIPS_SHA1Update(&sha1_ctx, g_xkey, kBlockSize);
21362eb3
A
252
253 // add zeros to fill the internal SHA-1 buffer
b0d623f7
A
254 FIPS_SHA1Update (&sha1_ctx, (const u_int8_t *)zeros, sizeof (zeros));
255
256 // we have to do a byte order correction here because the sha1 math is being done internally
257 // as u_int32_t, not a stream of bytes. Since we maintain our data as a byte stream, we need
258 // to convert
21362eb3 259
b0d623f7
A
260 u_int32_t* finger = (u_int32_t*) b;
261
262 unsigned j;
263 for (j = 0; j < kBlockSize / sizeof (u_int32_t); ++j)
264 {
265 *finger++ = OSSwapHostToBigInt32(sha1_ctx.h.b32[j]);
266 }
21362eb3
A
267
268 // calculate the CRC-32 of the block
b0d623f7 269 u_int32_t new_crc = CalculateCRC(sha1_ctx.h.b8, sizeof (Block));
21362eb3
A
270
271 // make sure we don't repeat
272 int cmp = new_crc == gLastBlockChecksum;
273 gLastBlockChecksum = new_crc;
274 if (!g_SelfTestInitialized)
275 {
276 g_SelfTestInitialized = 1;
277 return;
278 }
279 else if (!cmp)
280 {
281 return;
282 }
283
284 repeatCount += 1;
285
286 // fix up the next value of g_xkey
287 add_blocks (g_xkey, b, 1);
288 } while (repeatCount < 2);
8ad349bb 289
21362eb3
A
290 /*
291 * If we got here, three sucessive checksums of the random number
292 * generator have been the same. Since the odds of this happening are
293 * 1 in 18,446,744,073,709,551,616, (1 in 18 quintillion) one of the following has
294 * most likely happened:
295 *
296 * 1: There is a significant bug in this code.
297 * 2: There has been a massive system failure.
298 * 3: The universe has ceased to exist.
299 *
300 * There is no good way to recover from any of these cases. We
301 * therefore panic.
302 */
303
304 panic("FIPS random self-test failed.");
8ad349bb
A
305}
306
0b4e3aa0
A
307/*
308 *Initialize ONLY the Yarrow generator.
309 */
8ad349bb
A
310void
311PreliminarySetup(void)
0b4e3aa0
A
312{
313 prng_error_status perr;
0b4e3aa0 314
bd504ef0
A
315 /* Multiple threads can enter this as a result of an earlier
316 * check of gYarrowMutex. We make sure that only one of them
317 * can enter at a time. If one of them enters and discovers
318 * that gYarrowMutex is no longer NULL, we know that another
319 * thread has initialized the Yarrow state and we can exit.
320 */
321
322 /* The first thread that enters this function will find
323 * gYarrowInitializationLock set to 0. It will atomically
324 * set the value to 1 and, seeing that it was zero, drop
325 * out of the loop. Other threads will see that the value is
326 * 1 and continue to loop until we are initialized.
327 */
328
329 while (OSTestAndSet(0, &gYarrowInitializationLock)); /* serialize access to this function */
330
331 if (gYarrowMutex) {
332 /* we've already been initialized, clear and get out */
333 goto function_exit;
334 }
335
0b4e3aa0
A
336 /* create a Yarrow object */
337 perr = prngInitialize(&gPrngRef);
338 if (perr != 0) {
339 printf ("Couldn't initialize Yarrow, /dev/random will not work.\n");
340 return;
341 }
342
343 /* clear the error flag, reads and write should then work */
344 gRandomError = 0;
345
39236c6e 346 uint64_t tt;
2d21ac55
A
347 char buffer [16];
348
0b4e3aa0 349 /* get a little non-deterministic data as an initial seed. */
bd504ef0
A
350 /* On OSX, securityd will add much more entropy as soon as it */
351 /* comes up. On iOS, entropy is added with each system interrupt. */
39236c6e
A
352 tt = early_random();
353
0b4e3aa0
A
354 perr = prngInput(gPrngRef, (BYTE*) &tt, sizeof (tt), SYSTEM_SOURCE, 8);
355 if (perr != 0) {
356 /* an error, complain */
357 printf ("Couldn't seed Yarrow.\n");
bd504ef0 358 goto function_exit;
0b4e3aa0
A
359 }
360
361 /* turn the data around */
2d21ac55 362 perr = prngOutput(gPrngRef, (BYTE*) buffer, sizeof (buffer));
0b4e3aa0
A
363
364 /* and scramble it some more */
365 perr = prngForceReseed(gPrngRef, RESEED_TICKS);
366
367 /* make a mutex to control access */
2d21ac55
A
368 gYarrowGrpAttr = lck_grp_attr_alloc_init();
369 gYarrowGrp = lck_grp_alloc_init("random", gYarrowGrpAttr);
370 gYarrowAttr = lck_attr_alloc_init();
371 gYarrowMutex = lck_mtx_alloc_init(gYarrowGrp, gYarrowAttr);
8ad349bb
A
372
373 fips_initialize ();
bd504ef0
A
374
375function_exit:
376 /* allow other threads to figure out whether or not we have been initialized. */
377 gYarrowInitializationLock = 0;
8ad349bb
A
378}
379
b0d623f7 380const Block kKnownAnswer = {0x92, 0xb4, 0x04, 0xe5, 0x56, 0x58, 0x8c, 0xed, 0x6c, 0x1a, 0xcd, 0x4e, 0xbf, 0x05, 0x3f, 0x68, 0x09, 0xf7, 0x3a, 0x93};
4a3eedf9 381
8ad349bb
A
382void
383fips_initialize(void)
384{
4a3eedf9
A
385 /* So that we can do the self test, set the seed to zero */
386 memset(&g_xkey, 0, sizeof(g_xkey));
8ad349bb 387
8ad349bb
A
388 /* other initializations */
389 memset (zeros, 0, sizeof (zeros));
390 g_bytes_used = 0;
4a3eedf9
A
391 random_block(g_random_data, FALSE);
392
393 // check here to see if we got the initial data we were expecting
b0d623f7 394 if (memcmp(kKnownAnswer, g_random_data, kBlockSize) != 0)
4a3eedf9 395 {
b0d623f7 396 panic("FIPS random self test failed");
4a3eedf9
A
397 }
398
399 // now do the random block again to make sure that userland doesn't get predicatable data
400 random_block(g_random_data, TRUE);
0b4e3aa0
A
401}
402
403/*
404 * Called to initialize our device,
405 * and to register ourselves with devfs
406 */
407void
8ad349bb 408random_init(void)
0b4e3aa0
A
409{
410 int ret;
411
bd504ef0
A
412 if (OSTestAndSet(0, &gRandomInstalled)) {
413 /* do this atomically so that it works correctly with
414 multiple threads */
0b4e3aa0 415 return;
bd504ef0 416 }
0b4e3aa0
A
417
418 ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw);
419 if (ret < 0) {
420 printf("random_init: failed to allocate a major number!\n");
421 gRandomInstalled = 0;
422 return;
423 }
424
425 devfs_make_node(makedev (ret, 0), DEVFS_CHAR,
55e303ae 426 UID_ROOT, GID_WHEEL, 0666, "random", 0);
0b4e3aa0
A
427
428 /*
429 * also make urandom
430 * (which is exactly the same thing in our context)
431 */
432 devfs_make_node(makedev (ret, 1), DEVFS_CHAR,
55e303ae 433 UID_ROOT, GID_WHEEL, 0666, "urandom", 0);
bd504ef0
A
434
435 /* setup yarrow and the mutex if needed*/
436 PreliminarySetup();
55e303ae
A
437}
438
439int
91447636
A
440random_ioctl( __unused dev_t dev, u_long cmd, __unused caddr_t data,
441 __unused int flag, __unused struct proc *p )
55e303ae
A
442{
443 switch (cmd) {
444 case FIONBIO:
445 case FIOASYNC:
446 break;
447 default:
448 return ENODEV;
449 }
450
451 return (0);
0b4e3aa0
A
452}
453
454/*
455 * Open the device. Make sure init happened, and make sure the caller is
456 * authorized.
457 */
458
459int
91447636 460random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
0b4e3aa0
A
461{
462 if (gRandomError != 0) {
463 /* forget it, yarrow didn't come up */
464 return (ENOTSUP);
465 }
466
467 /*
468 * if we are being opened for write,
469 * make sure that we have privledges do so
470 */
471 if (flags & FWRITE) {
472 if (securelevel >= 2)
473 return (EPERM);
55e303ae 474#ifndef __APPLE__
91447636 475 if ((securelevel >= 1) && proc_suser(p))
0b4e3aa0 476 return (EPERM);
55e303ae 477#endif /* !__APPLE__ */
0b4e3aa0
A
478 }
479
480 return (0);
481}
482
483
484/*
485 * close the device.
486 */
487
488int
91447636 489random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p)
0b4e3aa0
A
490{
491 return (0);
492}
493
494
495/*
496 * Get entropic data from the Security Server, and use it to reseed the
497 * prng.
498 */
499int
91447636 500random_write (__unused dev_t dev, struct uio *uio, __unused int ioflag)
0b4e3aa0
A
501{
502 int retCode = 0;
503 char rdBuffer[256];
504
505 if (gRandomError != 0) {
506 return (ENOTSUP);
507 }
508
509 /* get control of the Yarrow instance, Yarrow is NOT thread safe */
2d21ac55 510 lck_mtx_lock(gYarrowMutex);
0b4e3aa0
A
511
512 /* Security server is sending us entropy */
513
91447636 514 while (uio_resid(uio) > 0 && retCode == 0) {
0b4e3aa0 515 /* get the user's data */
91447636 516 int bytesToInput = min(uio_resid(uio), sizeof (rdBuffer));
0b4e3aa0
A
517 retCode = uiomove(rdBuffer, bytesToInput, uio);
518 if (retCode != 0)
519 goto /*ugh*/ error_exit;
520
521 /* put it in Yarrow */
2d21ac55 522 if (prngInput(gPrngRef, (BYTE*) rdBuffer,
c0fea474
A
523 bytesToInput, SYSTEM_SOURCE,
524 bytesToInput * 8) != 0) {
0b4e3aa0
A
525 retCode = EIO;
526 goto error_exit;
527 }
528 }
529
530 /* force a reseed */
531 if (prngForceReseed(gPrngRef, RESEED_TICKS) != 0) {
532 retCode = EIO;
533 goto error_exit;
534 }
535
536 /* retCode should be 0 at this point */
537
538error_exit: /* do this to make sure the mutex unlocks. */
2d21ac55 539 lck_mtx_unlock(gYarrowMutex);
0b4e3aa0
A
540 return (retCode);
541}
542
0b4e3aa0
A
543
544/* export good random numbers to the rest of the kernel */
545void
546read_random(void* buffer, u_int numbytes)
547{
548 if (gYarrowMutex == 0) { /* are we initialized? */
549 PreliminarySetup ();
550 }
551
2d21ac55 552 lck_mtx_lock(gYarrowMutex);
39236c6e
A
553
554
21362eb3 555 int bytes_read = 0;
8ad349bb
A
556
557 int bytes_remaining = numbytes;
558 while (bytes_remaining > 0) {
b0d623f7 559 int bytes_to_read = min(bytes_remaining, kBlockSize - g_bytes_used);
8ad349bb
A
560 if (bytes_to_read == 0)
561 {
4a3eedf9 562 random_block(g_random_data, TRUE);
8ad349bb 563 g_bytes_used = 0;
b0d623f7 564 bytes_to_read = min(bytes_remaining, kBlockSize);
8ad349bb
A
565 }
566
2d21ac55 567 memmove ((u_int8_t*) buffer + bytes_read, ((u_int8_t*)g_random_data)+ g_bytes_used, bytes_to_read);
8ad349bb 568 g_bytes_used += bytes_to_read;
21362eb3 569 bytes_read += bytes_to_read;
8ad349bb
A
570 bytes_remaining -= bytes_to_read;
571 }
572
2d21ac55 573 lck_mtx_unlock(gYarrowMutex);
0b4e3aa0
A
574}
575
39236c6e
A
576/*
577 * return data to the caller. Results unpredictable.
578 */
579int
580random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag)
581{
582 int retCode = 0;
583
584 if (gRandomError != 0)
585 return (ENOTSUP);
586
587 char buffer[64];
588
589 user_ssize_t bytes_remaining = uio_resid(uio);
590 while (bytes_remaining > 0 && retCode == 0) {
591 user_ssize_t bytesToRead = min(sizeof(buffer), bytes_remaining);
592 read_random(buffer, bytesToRead);
593 retCode = uiomove(buffer, bytesToRead, uio);
594
595 if (retCode != 0)
596 goto error_exit;
597
598 bytes_remaining = uio_resid(uio);
599 }
600
601 retCode = 0;
602
603error_exit:
604 return retCode;
605}
0b4e3aa0 606/*
b0d623f7 607 * Return an u_int32_t pseudo-random number.
0b4e3aa0 608 */
b0d623f7 609u_int32_t
8ad349bb 610RandomULong(void)
0b4e3aa0 611{
b0d623f7 612 u_int32_t buf;
0b4e3aa0
A
613 read_random(&buf, sizeof (buf));
614 return (buf);
615}
d1ecb069 616