]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/random/randomdev.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / bsd / dev / random / randomdev.c
CommitLineData
0b4e3aa0 1/*
5d5c5d0d
A
2 * Copyright (c)1999-2004 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0b4e3aa0 5 *
8f6c56a5
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.
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
0b4e3aa0
A
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>
8ad349bb 36#include <string.h>
0b4e3aa0
A
37#include <miscfs/devfs/devfs.h>
38#include <kern/lock.h>
0b4e3aa0
A
39#include <sys/time.h>
40#include <sys/malloc.h>
91447636 41#include <sys/uio_internal.h>
0b4e3aa0
A
42
43#include <dev/random/randomdev.h>
44#include <dev/random/YarrowCoreLib/include/yarrow.h>
8ad349bb 45#include <crypto/sha1.h>
0b4e3aa0
A
46
47#define RANDOM_MAJOR -1 /* let the kernel pick the device number */
48
55e303ae
A
49d_ioctl_t random_ioctl;
50
0b4e3aa0
A
51/*
52 * A struct describing which functions will get invoked for certain
53 * actions.
54 */
55static struct cdevsw random_cdevsw =
56{
57 random_open, /* open */
58 random_close, /* close */
59 random_read, /* read */
60 random_write, /* write */
91447636
A
61 random_ioctl, /* ioctl */
62 (stop_fcn_t *)nulldev, /* stop */
63 (reset_fcn_t *)nulldev, /* reset */
0b4e3aa0
A
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 */
74static int gRandomInstalled = 0;
75static PrngRef gPrngRef;
76static int gRandomError = 1;
77static mutex_t *gYarrowMutex = 0;
78
79#define RESEED_TICKS 50 /* how long a reseed operation can take */
80
91447636 81
8ad349bb
A
82enum {kBSizeInBits = 160}; // MUST be a multiple of 32!!!
83enum {kBSizeInBytes = kBSizeInBits / 8};
84typedef u_int32_t BlockWord;
85enum {kWordSizeInBits = 32};
86enum {kBSize = 5};
87typedef BlockWord Block[kBSize];
88
89/* define prototypes to keep the compiler happy... */
90
91void add_blocks(Block a, Block b, BlockWord carry);
92void fips_initialize(void);
93void random_block(Block b);
94
95/*
96 * Get 120 bits from yarrow
97 */
98
99/*
100 * add block b to block a
101 */
102void
103add_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
118struct sha1_ctxt g_sha1_ctx;
119char zeros[(512 - kBSizeInBits) / 8];
120Block g_xkey;
121Block g_random_data;
122int 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 */
131void
132random_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
0b4e3aa0
A
154/*
155 *Initialize ONLY the Yarrow generator.
156 */
8ad349bb
A
157void
158PreliminarySetup(void)
0b4e3aa0
A
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 */
8ad349bb 192 perr = prngOutput(gPrngRef, (BYTE*)buffer, sizeof (buffer));
0b4e3aa0
A
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);
8ad349bb
A
199
200 fips_initialize ();
201}
202
203void
204fips_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);
0b4e3aa0
A
216}
217
218/*
219 * Called to initialize our device,
220 * and to register ourselves with devfs
221 */
222void
8ad349bb 223random_init(void)
0b4e3aa0
A
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,
55e303ae 244 UID_ROOT, GID_WHEEL, 0666, "random", 0);
0b4e3aa0
A
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,
55e303ae
A
251 UID_ROOT, GID_WHEEL, 0666, "urandom", 0);
252}
253
254int
91447636
A
255random_ioctl( __unused dev_t dev, u_long cmd, __unused caddr_t data,
256 __unused int flag, __unused struct proc *p )
55e303ae
A
257{
258 switch (cmd) {
259 case FIONBIO:
260 case FIOASYNC:
261 break;
262 default:
263 return ENODEV;
264 }
265
266 return (0);
0b4e3aa0
A
267}
268
269/*
270 * Open the device. Make sure init happened, and make sure the caller is
271 * authorized.
272 */
273
274int
91447636 275random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
0b4e3aa0
A
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);
55e303ae 289#ifndef __APPLE__
91447636 290 if ((securelevel >= 1) && proc_suser(p))
0b4e3aa0 291 return (EPERM);
55e303ae 292#endif /* !__APPLE__ */
0b4e3aa0
A
293 }
294
295 return (0);
296}
297
298
299/*
300 * close the device.
301 */
302
303int
91447636 304random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p)
0b4e3aa0
A
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 */
314int
91447636 315random_write (__unused dev_t dev, struct uio *uio, __unused int ioflag)
0b4e3aa0
A
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
91447636 329 while (uio_resid(uio) > 0 && retCode == 0) {
0b4e3aa0 330 /* get the user's data */
91447636
A
331 // LP64todo - fix this! uio_resid may be 64-bit value
332 int bytesToInput = min(uio_resid(uio), sizeof (rdBuffer));
0b4e3aa0
A
333 retCode = uiomove(rdBuffer, bytesToInput, uio);
334 if (retCode != 0)
335 goto /*ugh*/ error_exit;
336
337 /* put it in Yarrow */
8ad349bb 338 if (prngInput(gPrngRef, (BYTE*)rdBuffer,
c0fea474
A
339 bytesToInput, SYSTEM_SOURCE,
340 bytesToInput * 8) != 0) {
0b4e3aa0
A
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
354error_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 */
8ad349bb 362int random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag)
0b4e3aa0
A
363{
364 int retCode = 0;
8ad349bb 365
0b4e3aa0
A
366 if (gRandomError != 0)
367 return (ENOTSUP);
368
369 /* lock down the mutex */
370 mutex_lock(gYarrowMutex);
371
8ad349bb
A
372 int bytes_remaining = uio_resid(uio);
373 while (bytes_remaining > 0 && retCode == 0) {
0b4e3aa0 374 /* get the user's data */
8ad349bb
A
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
0b4e3aa0
A
390 if (retCode != 0)
391 goto error_exit;
8ad349bb
A
392
393 bytes_remaining = uio_resid(uio);
0b4e3aa0
A
394 }
395
396 retCode = 0;
397
398error_exit:
399 mutex_unlock(gYarrowMutex);
400 return retCode;
401}
402
403/* export good random numbers to the rest of the kernel */
404void
405read_random(void* buffer, u_int numbytes)
406{
407 if (gYarrowMutex == 0) { /* are we initialized? */
408 PreliminarySetup ();
409 }
410
411 mutex_lock(gYarrowMutex);
8ad349bb
A
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
0b4e3aa0
A
429 mutex_unlock(gYarrowMutex);
430}
431
432/*
433 * Return an unsigned long pseudo-random number.
434 */
435u_long
8ad349bb 436RandomULong(void)
0b4e3aa0
A
437{
438 u_long buf;
439 read_random(&buf, sizeof (buf));
440 return (buf);
441}
442