1 /* 2 * Copyright (c) 1999, 2000-2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/proc.h> 26 #include <sys/errno.h> 27 #include <sys/ioctl.h> 28 #include <sys/conf.h> 29 #include <sys/fcntl.h> 30 #include <miscfs/devfs/devfs.h> 31 #include <kern/lock.h> 32 #include <sys/time.h> 33 #include <sys/malloc.h> 34 35 #include <dev/random/randomdev.h> 36 #include <dev/random/YarrowCoreLib/include/yarrow.h> 37 38 #define RANDOM_MAJOR -1 /* let the kernel pick the device number */ 39 40 /* 41 * A struct describing which functions will get invoked for certain 42 * actions. 43 */ 44 static struct cdevsw random_cdevsw = 45 { 46 random_open, /* open */ 47 random_close, /* close */ 48 random_read, /* read */ 49 random_write, /* write */ 50 eno_ioctl, /* ioctl */ 51 nulldev, /* stop */ 52 nulldev, /* reset */ 53 NULL, /* tty's */ 54 eno_select, /* select */ 55 eno_mmap, /* mmap */ 56 eno_strat, /* strategy */ 57 eno_getc, /* getc */ 58 eno_putc, /* putc */ 59 0 /* type */ 60 }; 61 62 /* Used to detect whether we've already been initialized */ 63 static int gRandomInstalled = 0; 64 static PrngRef gPrngRef; 65 static int gRandomError = 1; 66 static mutex_t *gYarrowMutex = 0; 67 68 #define RESEED_TICKS 50 /* how long a reseed operation can take */ 69 70 /* 71 *Initialize ONLY the Yarrow generator. 72 */ 73 void PreliminarySetup () 74 { 75 prng_error_status perr; 76 struct timeval tt; 77 char buffer [16]; 78 79 /* create a Yarrow object */ 80 perr = prngInitialize(&gPrngRef); 81 if (perr != 0) { 82 printf ("Couldn't initialize Yarrow, /dev/random will not work.\n"); 83 return; 84 } 85 86 /* clear the error flag, reads and write should then work */ 87 gRandomError = 0; 88 89 /* get a little non-deterministic data as an initial seed. */ 90 microtime(&tt); 91 92 /* 93 * So how much of the system clock is entropic? 94 * It's hard to say, but assume that at least the 95 * least significant byte of a 64 bit structure 96 * is entropic. It's probably more, how can you figure 97 * the exact time the user turned the computer on, for example. 98 */ 99 perr = prngInput(gPrngRef, (BYTE*) &tt, sizeof (tt), SYSTEM_SOURCE, 8); 100 if (perr != 0) { 101 /* an error, complain */ 102 printf ("Couldn't seed Yarrow.\n"); 103 return; 104 } 105 106 /* turn the data around */ 107 perr = prngOutput(gPrngRef, (BYTE*) buffer, sizeof (buffer)); 108 109 /* and scramble it some more */ 110 perr = prngForceReseed(gPrngRef, RESEED_TICKS); 111 112 /* make a mutex to control access */ 113 gYarrowMutex = mutex_alloc(0); 114 } 115 116 /* 117 * Called to initialize our device, 118 * and to register ourselves with devfs 119 */ 120 void 121 random_init() 122 { 123 int ret; 124 125 if (gRandomInstalled) 126 return; 127 128 /* install us in the file system */ 129 gRandomInstalled = 1; 130 131 /* setup yarrow and the mutex */ 132 PreliminarySetup(); 133 134 ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw); 135 if (ret < 0) { 136 printf("random_init: failed to allocate a major number!\n"); 137 gRandomInstalled = 0; 138 return; 139 } 140 141 devfs_make_node(makedev (ret, 0), DEVFS_CHAR, 142 UID_ROOT, GID_WHEEL, 0644, "random", 0); 143 144 /* 145 * also make urandom 146 * (which is exactly the same thing in our context) 147 */ 148 devfs_make_node(makedev (ret, 1), DEVFS_CHAR, 149 UID_ROOT, GID_WHEEL, 0644, "urandom", 0); 150 } 151 152 /* 153 * Open the device. Make sure init happened, and make sure the caller is 154 * authorized. 155 */ 156 157 int 158 random_open(dev_t dev, int flags, int devtype, struct proc *p) 159 { 160 if (gRandomError != 0) { 161 /* forget it, yarrow didn't come up */ 162 return (ENOTSUP); 163 } 164 165 /* 166 * if we are being opened for write, 167 * make sure that we have privledges do so 168 */ 169 if (flags & FWRITE) { 170 if (securelevel >= 2) 171 return (EPERM); 172 if ((securelevel >= 1) && suser(p->p_ucred, &p->p_acflag)) 173 return (EPERM); 174 } 175 176 return (0); 177 } 178 179 180 /* 181 * close the device. 182 */ 183 184 int 185 random_close(dev_t dev, int flags, int mode, struct proc *p) 186 { 187 return (0); 188 } 189 190 191 /* 192 * Get entropic data from the Security Server, and use it to reseed the 193 * prng. 194 */ 195 int 196 random_write (dev_t dev, struct uio *uio, int ioflag) 197 { 198 int retCode = 0; 199 char rdBuffer[256]; 200 201 if (gRandomError != 0) { 202 return (ENOTSUP); 203 } 204 205 /* get control of the Yarrow instance, Yarrow is NOT thread safe */ 206 mutex_lock(gYarrowMutex); 207 208 /* Security server is sending us entropy */ 209 210 while (uio->uio_resid > 0 && retCode == 0) { 211 /* get the user's data */ 212 int bytesToInput = min(uio->uio_resid, sizeof (rdBuffer)); 213 retCode = uiomove(rdBuffer, bytesToInput, uio); 214 if (retCode != 0) 215 goto /*ugh*/ error_exit; 216 217 /* put it in Yarrow */ 218 if (prngInput(gPrngRef, (BYTE*) rdBuffer, 219 sizeof (rdBuffer), SYSTEM_SOURCE, 220 sizeof (rdBuffer) * 8) != 0) { 221 retCode = EIO; 222 goto error_exit; 223 } 224 } 225 226 /* force a reseed */ 227 if (prngForceReseed(gPrngRef, RESEED_TICKS) != 0) { 228 retCode = EIO; 229 goto error_exit; 230 } 231 232 /* retCode should be 0 at this point */ 233 234 error_exit: /* do this to make sure the mutex unlocks. */ 235 mutex_unlock(gYarrowMutex); 236 return (retCode); 237 } 238 239 /* 240 * return data to the caller. Results unpredictable. 241 */ 242 int 243 random_read(dev_t dev, struct uio *uio, int ioflag) 244 { 245 int retCode = 0; 246 char wrBuffer[512]; 247 248 if (gRandomError != 0) 249 return (ENOTSUP); 250 251 /* lock down the mutex */ 252 mutex_lock(gYarrowMutex); 253 254 while (uio->uio_resid > 0 && retCode == 0) { 255 /* get the user's data */ 256 int bytesToRead = min(uio->uio_resid, sizeof (wrBuffer)); 257 258 /* get the data from Yarrow */ 259 if (prngOutput(gPrngRef, (BYTE *) wrBuffer, sizeof (wrBuffer)) != 0) { 260 printf ("Couldn't read data from Yarrow.\n"); 261 262 /* something's really weird */ 263 retCode = EIO; 264 goto error_exit; 265 } 266 267 retCode = uiomove(wrBuffer, bytesToRead, uio); 268 269 if (retCode != 0) 270 goto error_exit; 271 } 272 273 retCode = 0; 274 275 error_exit: 276 mutex_unlock(gYarrowMutex); 277 return retCode; 278 } 279 280 /* export good random numbers to the rest of the kernel */ 281 void 282 read_random(void* buffer, u_int numbytes) 283 { 284 if (gYarrowMutex == 0) { /* are we initialized? */ 285 PreliminarySetup (); 286 } 287 288 mutex_lock(gYarrowMutex); 289 prngOutput(gPrngRef, (BYTE *) buffer, numbytes); 290 mutex_unlock(gYarrowMutex); 291 } 292 293 /* 294 * Return an unsigned long pseudo-random number. 295 */ 296 u_long 297 RandomULong() 298 { 299 u_long buf; 300 read_random(&buf, sizeof (buf)); 301 return (buf); 302 } 303 304