]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/random/randomdev.c
2339353fe95cd6c625e9ae95434148026b5fe6c0
[apple/xnu.git] / bsd / dev / random / randomdev.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/proc.h>
34 #include <sys/errno.h>
35 #include <sys/ioctl.h>
36 #include <sys/conf.h>
37 #include <sys/fcntl.h>
38 #include <string.h>
39 #include <miscfs/devfs/devfs.h>
40 #include <kern/lock.h>
41 #include <sys/time.h>
42 #include <sys/malloc.h>
43 #include <sys/uio_internal.h>
44
45 #include <dev/random/randomdev.h>
46 #include <dev/random/YarrowCoreLib/include/yarrow.h>
47 #include <crypto/sha1.h>
48
49 #define RANDOM_MAJOR -1 /* let the kernel pick the device number */
50
51 d_ioctl_t random_ioctl;
52
53 /*
54 * A struct describing which functions will get invoked for certain
55 * actions.
56 */
57 static struct cdevsw random_cdevsw =
58 {
59 random_open, /* open */
60 random_close, /* close */
61 random_read, /* read */
62 random_write, /* write */
63 random_ioctl, /* ioctl */
64 (stop_fcn_t *)nulldev, /* stop */
65 (reset_fcn_t *)nulldev, /* reset */
66 NULL, /* tty's */
67 eno_select, /* select */
68 eno_mmap, /* mmap */
69 eno_strat, /* strategy */
70 eno_getc, /* getc */
71 eno_putc, /* putc */
72 0 /* type */
73 };
74
75 /* Used to detect whether we've already been initialized */
76 static int gRandomInstalled = 0;
77 static PrngRef gPrngRef;
78 static int gRandomError = 1;
79 static mutex_t *gYarrowMutex = 0;
80
81 #define RESEED_TICKS 50 /* how long a reseed operation can take */
82
83
84 enum {kBSizeInBits = 160}; // MUST be a multiple of 32!!!
85 enum {kBSizeInBytes = kBSizeInBits / 8};
86 typedef u_int32_t BlockWord;
87 enum {kWordSizeInBits = 32};
88 enum {kBSize = 5};
89 typedef BlockWord Block[kBSize];
90
91 /* define prototypes to keep the compiler happy... */
92
93 void add_blocks(Block a, Block b, BlockWord carry);
94 void fips_initialize(void);
95 void random_block(Block b);
96
97 /*
98 * Get 120 bits from yarrow
99 */
100
101 /*
102 * add block b to block a
103 */
104 void
105 add_blocks(Block a, Block b, BlockWord carry)
106 {
107 int i = kBSize;
108 while (--i >= 0)
109 {
110 u_int64_t c = (u_int64_t)carry +
111 (u_int64_t)a[i] +
112 (u_int64_t)b[i];
113 a[i] = c & ((1LL << kWordSizeInBits) - 1);
114 carry = c >> kWordSizeInBits;
115 }
116 }
117
118
119
120 struct sha1_ctxt g_sha1_ctx;
121 char zeros[(512 - kBSizeInBits) / 8];
122 Block g_xkey;
123 Block g_random_data;
124 int g_bytes_used;
125
126 /*
127 * Setup for fips compliance
128 */
129
130 /*
131 * get a random block of data per fips 186-2
132 */
133 void
134 random_block(Block b)
135 {
136 // do one iteration
137 Block xSeed;
138 prngOutput (gPrngRef, (BYTE*) &xSeed, sizeof (xSeed));
139
140 // add the seed to the previous value of g_xkey
141 add_blocks (g_xkey, xSeed, 0);
142
143 // compute "G"
144 SHA1Update (&g_sha1_ctx, (const u_int8_t *) &g_xkey, sizeof (g_xkey));
145
146 // add zeros to fill the internal SHA-1 buffer
147 SHA1Update (&g_sha1_ctx, (const u_int8_t *)zeros, sizeof (zeros));
148
149 // write the resulting block
150 memmove(b, g_sha1_ctx.h.b8, sizeof (Block));
151
152 // fix up the next value of g_xkey
153 add_blocks (g_xkey, b, 1);
154 }
155
156 /*
157 *Initialize ONLY the Yarrow generator.
158 */
159 void
160 PreliminarySetup(void)
161 {
162 prng_error_status perr;
163 struct timeval tt;
164 char buffer [16];
165
166 /* create a Yarrow object */
167 perr = prngInitialize(&gPrngRef);
168 if (perr != 0) {
169 printf ("Couldn't initialize Yarrow, /dev/random will not work.\n");
170 return;
171 }
172
173 /* clear the error flag, reads and write should then work */
174 gRandomError = 0;
175
176 /* get a little non-deterministic data as an initial seed. */
177 microtime(&tt);
178
179 /*
180 * So how much of the system clock is entropic?
181 * It's hard to say, but assume that at least the
182 * least significant byte of a 64 bit structure
183 * is entropic. It's probably more, how can you figure
184 * the exact time the user turned the computer on, for example.
185 */
186 perr = prngInput(gPrngRef, (BYTE*) &tt, sizeof (tt), SYSTEM_SOURCE, 8);
187 if (perr != 0) {
188 /* an error, complain */
189 printf ("Couldn't seed Yarrow.\n");
190 return;
191 }
192
193 /* turn the data around */
194 perr = prngOutput(gPrngRef, (BYTE*)buffer, sizeof (buffer));
195
196 /* and scramble it some more */
197 perr = prngForceReseed(gPrngRef, RESEED_TICKS);
198
199 /* make a mutex to control access */
200 gYarrowMutex = mutex_alloc(0);
201
202 fips_initialize ();
203 }
204
205 void
206 fips_initialize(void)
207 {
208 /* Read the initial value of g_xkey from yarrow */
209 prngOutput (gPrngRef, (BYTE*) &g_xkey, sizeof (g_xkey));
210
211 /* initialize our SHA1 generator */
212 SHA1Init (&g_sha1_ctx);
213
214 /* other initializations */
215 memset (zeros, 0, sizeof (zeros));
216 g_bytes_used = 0;
217 random_block(g_random_data);
218 }
219
220 /*
221 * Called to initialize our device,
222 * and to register ourselves with devfs
223 */
224 void
225 random_init(void)
226 {
227 int ret;
228
229 if (gRandomInstalled)
230 return;
231
232 /* install us in the file system */
233 gRandomInstalled = 1;
234
235 /* setup yarrow and the mutex */
236 PreliminarySetup();
237
238 ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw);
239 if (ret < 0) {
240 printf("random_init: failed to allocate a major number!\n");
241 gRandomInstalled = 0;
242 return;
243 }
244
245 devfs_make_node(makedev (ret, 0), DEVFS_CHAR,
246 UID_ROOT, GID_WHEEL, 0666, "random", 0);
247
248 /*
249 * also make urandom
250 * (which is exactly the same thing in our context)
251 */
252 devfs_make_node(makedev (ret, 1), DEVFS_CHAR,
253 UID_ROOT, GID_WHEEL, 0666, "urandom", 0);
254 }
255
256 int
257 random_ioctl( __unused dev_t dev, u_long cmd, __unused caddr_t data,
258 __unused int flag, __unused struct proc *p )
259 {
260 switch (cmd) {
261 case FIONBIO:
262 case FIOASYNC:
263 break;
264 default:
265 return ENODEV;
266 }
267
268 return (0);
269 }
270
271 /*
272 * Open the device. Make sure init happened, and make sure the caller is
273 * authorized.
274 */
275
276 int
277 random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
278 {
279 if (gRandomError != 0) {
280 /* forget it, yarrow didn't come up */
281 return (ENOTSUP);
282 }
283
284 /*
285 * if we are being opened for write,
286 * make sure that we have privledges do so
287 */
288 if (flags & FWRITE) {
289 if (securelevel >= 2)
290 return (EPERM);
291 #ifndef __APPLE__
292 if ((securelevel >= 1) && proc_suser(p))
293 return (EPERM);
294 #endif /* !__APPLE__ */
295 }
296
297 return (0);
298 }
299
300
301 /*
302 * close the device.
303 */
304
305 int
306 random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p)
307 {
308 return (0);
309 }
310
311
312 /*
313 * Get entropic data from the Security Server, and use it to reseed the
314 * prng.
315 */
316 int
317 random_write (__unused dev_t dev, struct uio *uio, __unused int ioflag)
318 {
319 int retCode = 0;
320 char rdBuffer[256];
321
322 if (gRandomError != 0) {
323 return (ENOTSUP);
324 }
325
326 /* get control of the Yarrow instance, Yarrow is NOT thread safe */
327 mutex_lock(gYarrowMutex);
328
329 /* Security server is sending us entropy */
330
331 while (uio_resid(uio) > 0 && retCode == 0) {
332 /* get the user's data */
333 // LP64todo - fix this! uio_resid may be 64-bit value
334 int bytesToInput = min(uio_resid(uio), sizeof (rdBuffer));
335 retCode = uiomove(rdBuffer, bytesToInput, uio);
336 if (retCode != 0)
337 goto /*ugh*/ error_exit;
338
339 /* put it in Yarrow */
340 if (prngInput(gPrngRef, (BYTE*)rdBuffer,
341 bytesToInput, SYSTEM_SOURCE,
342 bytesToInput * 8) != 0) {
343 retCode = EIO;
344 goto error_exit;
345 }
346 }
347
348 /* force a reseed */
349 if (prngForceReseed(gPrngRef, RESEED_TICKS) != 0) {
350 retCode = EIO;
351 goto error_exit;
352 }
353
354 /* retCode should be 0 at this point */
355
356 error_exit: /* do this to make sure the mutex unlocks. */
357 mutex_unlock(gYarrowMutex);
358 return (retCode);
359 }
360
361 /*
362 * return data to the caller. Results unpredictable.
363 */
364 int random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag)
365 {
366 int retCode = 0;
367
368 if (gRandomError != 0)
369 return (ENOTSUP);
370
371 /* lock down the mutex */
372 mutex_lock(gYarrowMutex);
373
374 int bytes_remaining = uio_resid(uio);
375 while (bytes_remaining > 0 && retCode == 0) {
376 /* get the user's data */
377 int bytes_to_read = 0;
378
379 int bytes_available = kBSizeInBytes - g_bytes_used;
380 if (bytes_available == 0)
381 {
382 random_block(g_random_data);
383 g_bytes_used = 0;
384 bytes_available = kBSizeInBytes;
385 }
386
387 bytes_to_read = min (bytes_remaining, bytes_available);
388
389 retCode = uiomove(((u_int8_t*)g_random_data)+ g_bytes_used, bytes_to_read, uio);
390 g_bytes_used += bytes_to_read;
391
392 if (retCode != 0)
393 goto error_exit;
394
395 bytes_remaining = uio_resid(uio);
396 }
397
398 retCode = 0;
399
400 error_exit:
401 mutex_unlock(gYarrowMutex);
402 return retCode;
403 }
404
405 /* export good random numbers to the rest of the kernel */
406 void
407 read_random(void* buffer, u_int numbytes)
408 {
409 if (gYarrowMutex == 0) { /* are we initialized? */
410 PreliminarySetup ();
411 }
412
413 mutex_lock(gYarrowMutex);
414
415 int bytes_remaining = numbytes;
416 while (bytes_remaining > 0) {
417 int bytes_to_read = min(bytes_remaining, kBSizeInBytes - g_bytes_used);
418 if (bytes_to_read == 0)
419 {
420 random_block(g_random_data);
421 g_bytes_used = 0;
422 bytes_to_read = min(bytes_remaining, kBSizeInBytes);
423 }
424
425 memmove (buffer, ((u_int8_t*)g_random_data)+ g_bytes_used, bytes_to_read);
426 g_bytes_used += bytes_to_read;
427
428 bytes_remaining -= bytes_to_read;
429 }
430
431 mutex_unlock(gYarrowMutex);
432 }
433
434 /*
435 * Return an unsigned long pseudo-random number.
436 */
437 u_long
438 RandomULong(void)
439 {
440 u_long buf;
441 read_random(&buf, sizeof (buf));
442 return (buf);
443 }
444