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