]>
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
));