]>
git.saurik.com Git - apple/xnu.git/blob - bsd/dev/random/randomdev.c
2339353fe95cd6c625e9ae95434148026b5fe6c0
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
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.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <sys/param.h>
32 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/ioctl.h>
37 #include <sys/fcntl.h>
39 #include <miscfs/devfs/devfs.h>
40 #include <kern/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/uio_internal.h>
45 #include <dev/random/randomdev.h>
46 #include <dev/random/YarrowCoreLib/include/yarrow.h>
47 #include <crypto/sha1.h>
49 #define RANDOM_MAJOR -1 /* let the kernel pick the device number */
51 d_ioctl_t random_ioctl
;
54 * A struct describing which functions will get invoked for certain
57 static struct cdevsw random_cdevsw
=
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 */
67 eno_select
, /* select */
69 eno_strat
, /* strategy */
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;
81 #define RESEED_TICKS 50 /* how long a reseed operation can take */
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};
89 typedef BlockWord Block
[kBSize
];
91 /* define prototypes to keep the compiler happy... */
93 void add_blocks(Block a
, Block b
, BlockWord carry
);
94 void fips_initialize(void);
95 void random_block(Block b
);
98 * Get 120 bits from yarrow
102 * add block b to block a
105 add_blocks(Block a
, Block b
, BlockWord carry
)
110 u_int64_t c
= (u_int64_t
)carry
+
113 a
[i
] = c
& ((1LL << kWordSizeInBits
) - 1);
114 carry
= c
>> kWordSizeInBits
;
120 struct sha1_ctxt g_sha1_ctx
;
121 char zeros
[(512 - kBSizeInBits
) / 8];
127 * Setup for fips compliance
131 * get a random block of data per fips 186-2
134 random_block(Block b
)
138 prngOutput (gPrngRef
, (BYTE
*) &xSeed
, sizeof (xSeed
));
140 // add the seed to the previous value of g_xkey
141 add_blocks (g_xkey
, xSeed
, 0);
144 SHA1Update (&g_sha1_ctx
, (const u_int8_t
*) &g_xkey
, sizeof (g_xkey
));
146 // add zeros to fill the internal SHA-1 buffer
147 SHA1Update (&g_sha1_ctx
, (const u_int8_t
*)zeros
, sizeof (zeros
));
149 // write the resulting block
150 memmove(b
, g_sha1_ctx
.h
.b8
, sizeof (Block
));
152 // fix up the next value of g_xkey
153 add_blocks (g_xkey
, b
, 1);
157 *Initialize ONLY the Yarrow generator.
160 PreliminarySetup(void)
162 prng_error_status perr
;
166 /* create a Yarrow object */
167 perr
= prngInitialize(&gPrngRef
);
169 printf ("Couldn't initialize Yarrow, /dev/random will not work.\n");
173 /* clear the error flag, reads and write should then work */
176 /* get a little non-deterministic data as an initial seed. */
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.
186 perr
= prngInput(gPrngRef
, (BYTE
*) &tt
, sizeof (tt
), SYSTEM_SOURCE
, 8);
188 /* an error, complain */
189 printf ("Couldn't seed Yarrow.\n");
193 /* turn the data around */
194 perr
= prngOutput(gPrngRef
, (BYTE
*)buffer
, sizeof (buffer
));
196 /* and scramble it some more */
197 perr
= prngForceReseed(gPrngRef
, RESEED_TICKS
);
199 /* make a mutex to control access */
200 gYarrowMutex
= mutex_alloc(0);
206 fips_initialize(void)
208 /* Read the initial value of g_xkey from yarrow */
209 prngOutput (gPrngRef
, (BYTE
*) &g_xkey
, sizeof (g_xkey
));
211 /* initialize our SHA1 generator */
212 SHA1Init (&g_sha1_ctx
);
214 /* other initializations */
215 memset (zeros
, 0, sizeof (zeros
));
217 random_block(g_random_data
);
221 * Called to initialize our device,
222 * and to register ourselves with devfs
229 if (gRandomInstalled
)
232 /* install us in the file system */
233 gRandomInstalled
= 1;
235 /* setup yarrow and the mutex */
238 ret
= cdevsw_add(RANDOM_MAJOR
, &random_cdevsw
);
240 printf("random_init: failed to allocate a major number!\n");
241 gRandomInstalled
= 0;
245 devfs_make_node(makedev (ret
, 0), DEVFS_CHAR
,
246 UID_ROOT
, GID_WHEEL
, 0666, "random", 0);
250 * (which is exactly the same thing in our context)
252 devfs_make_node(makedev (ret
, 1), DEVFS_CHAR
,
253 UID_ROOT
, GID_WHEEL
, 0666, "urandom", 0);
257 random_ioctl( __unused dev_t dev
, u_long cmd
, __unused caddr_t data
,
258 __unused
int flag
, __unused
struct proc
*p
)
272 * Open the device. Make sure init happened, and make sure the caller is
277 random_open(__unused dev_t dev
, int flags
, __unused
int devtype
, __unused
struct proc
*p
)
279 if (gRandomError
!= 0) {
280 /* forget it, yarrow didn't come up */
285 * if we are being opened for write,
286 * make sure that we have privledges do so
288 if (flags
& FWRITE
) {
289 if (securelevel
>= 2)
292 if ((securelevel
>= 1) && proc_suser(p
))
294 #endif /* !__APPLE__ */
306 random_close(__unused dev_t dev
, __unused
int flags
, __unused
int mode
, __unused
struct proc
*p
)
313 * Get entropic data from the Security Server, and use it to reseed the
317 random_write (__unused dev_t dev
, struct uio
*uio
, __unused
int ioflag
)
322 if (gRandomError
!= 0) {
326 /* get control of the Yarrow instance, Yarrow is NOT thread safe */
327 mutex_lock(gYarrowMutex
);
329 /* Security server is sending us entropy */
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
);
337 goto /*ugh*/ error_exit
;
339 /* put it in Yarrow */
340 if (prngInput(gPrngRef
, (BYTE
*)rdBuffer
,
341 bytesToInput
, SYSTEM_SOURCE
,
342 bytesToInput
* 8) != 0) {
349 if (prngForceReseed(gPrngRef
, RESEED_TICKS
) != 0) {
354 /* retCode should be 0 at this point */
356 error_exit
: /* do this to make sure the mutex unlocks. */
357 mutex_unlock(gYarrowMutex
);
362 * return data to the caller. Results unpredictable.
364 int random_read(__unused dev_t dev
, struct uio
*uio
, __unused
int ioflag
)
368 if (gRandomError
!= 0)
371 /* lock down the mutex */
372 mutex_lock(gYarrowMutex
);
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;
379 int bytes_available
= kBSizeInBytes
- g_bytes_used
;
380 if (bytes_available
== 0)
382 random_block(g_random_data
);
384 bytes_available
= kBSizeInBytes
;
387 bytes_to_read
= min (bytes_remaining
, bytes_available
);
389 retCode
= uiomove(((u_int8_t
*)g_random_data
)+ g_bytes_used
, bytes_to_read
, uio
);
390 g_bytes_used
+= bytes_to_read
;
395 bytes_remaining
= uio_resid(uio
);
401 mutex_unlock(gYarrowMutex
);
405 /* export good random numbers to the rest of the kernel */
407 read_random(void* buffer
, u_int numbytes
)
409 if (gYarrowMutex
== 0) { /* are we initialized? */
413 mutex_lock(gYarrowMutex
);
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)
420 random_block(g_random_data
);
422 bytes_to_read
= min(bytes_remaining
, kBSizeInBytes
);
425 memmove (buffer
, ((u_int8_t
*)g_random_data
)+ g_bytes_used
, bytes_to_read
);
426 g_bytes_used
+= bytes_to_read
;
428 bytes_remaining
-= bytes_to_read
;
431 mutex_unlock(gYarrowMutex
);
435 * Return an unsigned long pseudo-random number.
441 read_random(&buf
, sizeof (buf
));