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