]>
git.saurik.com Git - apple/xnu.git/blob - bsd/dev/random/randomdev.c
d98b1e29c47a832eaa863c0961552cd985eaf5aa
2 * Copyright (c)1999-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/systm.h>
32 #include <sys/errno.h>
33 #include <sys/ioctl.h>
35 #include <sys/fcntl.h>
37 #include <miscfs/devfs/devfs.h>
38 #include <kern/lock.h>
40 #include <sys/malloc.h>
41 #include <sys/uio_internal.h>
43 #include <dev/random/randomdev.h>
44 #include <dev/random/YarrowCoreLib/include/yarrow.h>
45 #include <crypto/sha1.h>
47 #define RANDOM_MAJOR -1 /* let the kernel pick the device number */
49 d_ioctl_t random_ioctl
;
52 * A struct describing which functions will get invoked for certain
55 static struct cdevsw random_cdevsw
=
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 */
65 eno_select
, /* select */
67 eno_strat
, /* strategy */
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;
79 #define RESEED_TICKS 50 /* how long a reseed operation can take */
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};
87 typedef BlockWord Block
[kBSize
];
89 /* define prototypes to keep the compiler happy... */
91 void add_blocks(Block a
, Block b
, BlockWord carry
);
92 void fips_initialize(void);
93 void random_block(Block b
);
96 * Get 120 bits from yarrow
100 * add block b to block a
103 add_blocks(Block a
, Block b
, BlockWord carry
)
108 u_int64_t c
= (u_int64_t
)carry
+
111 a
[i
] = c
& ((1LL << kWordSizeInBits
) - 1);
112 carry
= c
>> kWordSizeInBits
;
118 struct sha1_ctxt g_sha1_ctx
;
119 char zeros
[(512 - kBSizeInBits
) / 8];
125 * Setup for fips compliance
129 * get a random block of data per fips 186-2
132 random_block(Block b
)
136 prngOutput (gPrngRef
, (BYTE
*) &xSeed
, sizeof (xSeed
));
138 // add the seed to the previous value of g_xkey
139 add_blocks (g_xkey
, xSeed
, 0);
142 SHA1Update (&g_sha1_ctx
, (const u_int8_t
*) &g_xkey
, sizeof (g_xkey
));
144 // add zeros to fill the internal SHA-1 buffer
145 SHA1Update (&g_sha1_ctx
, (const u_int8_t
*)zeros
, sizeof (zeros
));
147 // write the resulting block
148 memmove(b
, g_sha1_ctx
.h
.b8
, sizeof (Block
));
150 // fix up the next value of g_xkey
151 add_blocks (g_xkey
, b
, 1);
155 *Initialize ONLY the Yarrow generator.
158 PreliminarySetup(void)
160 prng_error_status perr
;
164 /* create a Yarrow object */
165 perr
= prngInitialize(&gPrngRef
);
167 printf ("Couldn't initialize Yarrow, /dev/random will not work.\n");
171 /* clear the error flag, reads and write should then work */
174 /* get a little non-deterministic data as an initial seed. */
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.
184 perr
= prngInput(gPrngRef
, (BYTE
*) &tt
, sizeof (tt
), SYSTEM_SOURCE
, 8);
186 /* an error, complain */
187 printf ("Couldn't seed Yarrow.\n");
191 /* turn the data around */
192 perr
= prngOutput(gPrngRef
, (BYTE
*)buffer
, sizeof (buffer
));
194 /* and scramble it some more */
195 perr
= prngForceReseed(gPrngRef
, RESEED_TICKS
);
197 /* make a mutex to control access */
198 gYarrowMutex
= mutex_alloc(0);
204 fips_initialize(void)
206 /* Read the initial value of g_xkey from yarrow */
207 prngOutput (gPrngRef
, (BYTE
*) &g_xkey
, sizeof (g_xkey
));
209 /* initialize our SHA1 generator */
210 SHA1Init (&g_sha1_ctx
);
212 /* other initializations */
213 memset (zeros
, 0, sizeof (zeros
));
215 random_block(g_random_data
);
219 * Called to initialize our device,
220 * and to register ourselves with devfs
227 if (gRandomInstalled
)
230 /* install us in the file system */
231 gRandomInstalled
= 1;
233 /* setup yarrow and the mutex */
236 ret
= cdevsw_add(RANDOM_MAJOR
, &random_cdevsw
);
238 printf("random_init: failed to allocate a major number!\n");
239 gRandomInstalled
= 0;
243 devfs_make_node(makedev (ret
, 0), DEVFS_CHAR
,
244 UID_ROOT
, GID_WHEEL
, 0666, "random", 0);
248 * (which is exactly the same thing in our context)
250 devfs_make_node(makedev (ret
, 1), DEVFS_CHAR
,
251 UID_ROOT
, GID_WHEEL
, 0666, "urandom", 0);
255 random_ioctl( __unused dev_t dev
, u_long cmd
, __unused caddr_t data
,
256 __unused
int flag
, __unused
struct proc
*p
)
270 * Open the device. Make sure init happened, and make sure the caller is
275 random_open(__unused dev_t dev
, int flags
, __unused
int devtype
, __unused
struct proc
*p
)
277 if (gRandomError
!= 0) {
278 /* forget it, yarrow didn't come up */
283 * if we are being opened for write,
284 * make sure that we have privledges do so
286 if (flags
& FWRITE
) {
287 if (securelevel
>= 2)
290 if ((securelevel
>= 1) && proc_suser(p
))
292 #endif /* !__APPLE__ */
304 random_close(__unused dev_t dev
, __unused
int flags
, __unused
int mode
, __unused
struct proc
*p
)
311 * Get entropic data from the Security Server, and use it to reseed the
315 random_write (__unused dev_t dev
, struct uio
*uio
, __unused
int ioflag
)
320 if (gRandomError
!= 0) {
324 /* get control of the Yarrow instance, Yarrow is NOT thread safe */
325 mutex_lock(gYarrowMutex
);
327 /* Security server is sending us entropy */
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
);
335 goto /*ugh*/ error_exit
;
337 /* put it in Yarrow */
338 if (prngInput(gPrngRef
, (BYTE
*)rdBuffer
,
339 bytesToInput
, SYSTEM_SOURCE
,
340 bytesToInput
* 8) != 0) {
347 if (prngForceReseed(gPrngRef
, RESEED_TICKS
) != 0) {
352 /* retCode should be 0 at this point */
354 error_exit
: /* do this to make sure the mutex unlocks. */
355 mutex_unlock(gYarrowMutex
);
360 * return data to the caller. Results unpredictable.
362 int random_read(__unused dev_t dev
, struct uio
*uio
, __unused
int ioflag
)
366 if (gRandomError
!= 0)
369 /* lock down the mutex */
370 mutex_lock(gYarrowMutex
);
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;
377 int bytes_available
= kBSizeInBytes
- g_bytes_used
;
378 if (bytes_available
== 0)
380 random_block(g_random_data
);
382 bytes_available
= kBSizeInBytes
;
385 bytes_to_read
= min (bytes_remaining
, bytes_available
);
387 retCode
= uiomove(((u_int8_t
*)g_random_data
)+ g_bytes_used
, bytes_to_read
, uio
);
388 g_bytes_used
+= bytes_to_read
;
393 bytes_remaining
= uio_resid(uio
);
399 mutex_unlock(gYarrowMutex
);
403 /* export good random numbers to the rest of the kernel */
405 read_random(void* buffer
, u_int numbytes
)
407 if (gYarrowMutex
== 0) { /* are we initialized? */
411 mutex_lock(gYarrowMutex
);
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)
418 random_block(g_random_data
);
420 bytes_to_read
= min(bytes_remaining
, kBSizeInBytes
);
423 memmove (buffer
, ((u_int8_t
*)g_random_data
)+ g_bytes_used
, bytes_to_read
);
424 g_bytes_used
+= bytes_to_read
;
426 bytes_remaining
-= bytes_to_read
;
429 mutex_unlock(gYarrowMutex
);
433 * Return an unsigned long pseudo-random number.
439 read_random(&buf
, sizeof (buf
));