1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <unistd.h>
  28 #include <errno.h>
  29 #include <string.h>
  30 #include <fcntl.h>
  31 #include <locale.h>
  32 #include <stdarg.h>
  33 #include <cryptoutil.h>
  34 #include <pthread.h>
  35 
  36 
  37 static pthread_mutex_t  random_mutex = PTHREAD_MUTEX_INITIALIZER;
  38 static pthread_mutex_t  urandom_mutex = PTHREAD_MUTEX_INITIALIZER;
  39 
  40 static pthread_mutex_t  random_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
  41 static pthread_mutex_t  urandom_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
  42 
  43 #define RANDOM_DEVICE           "/dev/random"   /* random device name */
  44 #define URANDOM_DEVICE          "/dev/urandom"  /* urandom device name */
  45 
  46 static int      random_fd = -1;
  47 static int      urandom_fd = -1;
  48 
  49 static int      random_seed_fd = -1;
  50 static int      urandom_seed_fd = -1;
  51 
  52 
  53 /*
  54  * Equivalent of open(2) insulated from EINTR.
  55  * Also sets close-on-exec.
  56  */
  57 int
  58 open_nointr(const char *path, int oflag, ...)
  59 {
  60         int     fd;
  61         mode_t  pmode;
  62         va_list alist;
  63 
  64         va_start(alist, oflag);
  65         pmode = va_arg(alist, mode_t);
  66         va_end(alist);
  67 
  68         do {
  69                 if ((fd = open(path, oflag, pmode)) >= 0) {
  70                         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
  71                         break;
  72                 }
  73                 /* errno definitely set by failed open() */
  74         } while (errno == EINTR);
  75         return (fd);
  76 }
  77 
  78 /*
  79  * Equivalent of read(2) insulated from EINTR.
  80  */
  81 ssize_t
  82 readn_nointr(int fd, void *dbuf, size_t dlen)
  83 {
  84         char    *marker = dbuf;
  85         size_t  left = dlen;
  86         ssize_t nread = 0, err;
  87 
  88         for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) {
  89                 if ((nread = read(fd, marker, left)) < 0) {
  90                         if (errno == EINTR) {   /* keep trying */
  91                                 nread = 0;
  92                                 continue;
  93                         }
  94                         err = nread;            /* hard error */
  95                         break;
  96                 } else if (nread == 0) {
  97                         break;
  98                 }
  99         }
 100         return (err != 0 ? err : dlen - left);
 101 }
 102 
 103 /*
 104  * Equivalent of write(2) insulated from EINTR.
 105  */
 106 ssize_t
 107 writen_nointr(int fd, void *dbuf, size_t dlen)
 108 {
 109         char    *marker = dbuf;
 110         size_t  left = dlen;
 111         ssize_t nwrite = 0, err;
 112 
 113         for (err = 0; left > 0 && nwrite != -1; marker += nwrite,
 114             left -= nwrite) {
 115                 if ((nwrite = write(fd, marker, left)) < 0) {
 116                         if (errno == EINTR) {   /* keep trying */
 117                                 nwrite = 0;
 118                                 continue;
 119                         }
 120                         err = nwrite;           /* hard error */
 121                         break;
 122                 } else if (nwrite == 0) {
 123                         break;
 124                 }
 125         }
 126         return (err != 0 ? err : dlen - left);
 127 }
 128 
 129 /*
 130  * Opens the random number generator devices if not already open.
 131  * Always returns the opened fd of the device, or error.
 132  */
 133 static int
 134 pkcs11_open_common(int *fd, pthread_mutex_t *mtx, const char *dev, int oflag)
 135 {
 136         (void) pthread_mutex_lock(mtx);
 137         if (*fd < 0)
 138                 *fd = open_nointr(dev, oflag);
 139         (void) pthread_mutex_unlock(mtx);
 140 
 141         return (*fd);
 142 }
 143 
 144 static int
 145 pkcs11_open_random(void)
 146 {
 147         return (pkcs11_open_common(&random_fd, &random_mutex,
 148             RANDOM_DEVICE, O_RDONLY));
 149 }
 150 
 151 static int
 152 pkcs11_open_urandom(void)
 153 {
 154         return (pkcs11_open_common(&urandom_fd, &urandom_mutex,
 155             URANDOM_DEVICE, O_RDONLY));
 156 }
 157 
 158 static int
 159 pkcs11_open_random_seed(void)
 160 {
 161         return (pkcs11_open_common(&random_seed_fd, &random_seed_mutex,
 162             RANDOM_DEVICE, O_WRONLY));
 163 }
 164 
 165 static int
 166 pkcs11_open_urandom_seed(void)
 167 {
 168         return (pkcs11_open_common(&urandom_seed_fd, &urandom_seed_mutex,
 169             URANDOM_DEVICE, O_WRONLY));
 170 }
 171 
 172 /*
 173  * Close the random number generator devices if already open.
 174  */
 175 static void
 176 pkcs11_close_common(int *fd, pthread_mutex_t *mtx)
 177 {
 178         (void) pthread_mutex_lock(mtx);
 179         (void) close(*fd);
 180         *fd = -1;
 181         (void) pthread_mutex_unlock(mtx);
 182 }
 183 
 184 void
 185 pkcs11_close_random(void)
 186 {
 187         pkcs11_close_common(&random_fd, &random_mutex);
 188 }
 189 
 190 void
 191 pkcs11_close_urandom(void)
 192 {
 193         pkcs11_close_common(&urandom_fd, &urandom_mutex);
 194 }
 195 
 196 static void
 197 pkcs11_close_random_seed(void)
 198 {
 199         pkcs11_close_common(&random_seed_fd, &random_seed_mutex);
 200 }
 201 
 202 void
 203 pkcs11_close_urandom_seed(void)
 204 {
 205         pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex);
 206 }
 207 
 208 /*
 209  * Read from the random number generator devices.
 210  */
 211 static size_t
 212 pkcs11_read_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
 213 {
 214         size_t  n;
 215 
 216         (void) pthread_mutex_lock(mtx);
 217         n = readn_nointr(*fd, dbuf, dlen);
 218         (void) pthread_mutex_unlock(mtx);
 219 
 220         return (n);
 221 }
 222 
 223 static size_t
 224 pkcs11_read_random(void *dbuf, size_t dlen)
 225 {
 226         return (pkcs11_read_common(&random_fd, &random_mutex, dbuf, dlen));
 227 }
 228 
 229 static size_t
 230 pkcs11_read_urandom(void *dbuf, size_t dlen)
 231 {
 232         return (pkcs11_read_common(&urandom_fd, &urandom_mutex, dbuf, dlen));
 233 }
 234 
 235 /*
 236  * Write to the random number generator devices.
 237  */
 238 static size_t
 239 pkcs11_write_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
 240 {
 241         size_t  n;
 242 
 243         (void) pthread_mutex_lock(mtx);
 244         n = writen_nointr(*fd, dbuf, dlen);
 245         (void) pthread_mutex_unlock(mtx);
 246 
 247         return (n);
 248 }
 249 
 250 static size_t
 251 pkcs11_write_random_seed(void *dbuf, size_t dlen)
 252 {
 253         return (pkcs11_write_common(&random_seed_fd, &random_seed_mutex,
 254             dbuf, dlen));
 255 }
 256 
 257 static size_t
 258 pkcs11_write_urandom_seed(void *dbuf, size_t dlen)
 259 {
 260         return (pkcs11_write_common(&urandom_seed_fd, &urandom_seed_mutex,
 261             dbuf, dlen));
 262 }
 263 
 264 /*
 265  * Seed /dev/random with the data in the buffer.
 266  */
 267 int
 268 pkcs11_seed_random(void *sbuf, size_t slen)
 269 {
 270         int     rv;
 271 
 272         if (sbuf == NULL || slen == 0)
 273                 return (0);
 274 
 275         /* Seeding error could mean it's not supported (errno = EACCES) */
 276         if (pkcs11_open_random_seed() < 0)
 277                 return (-1);
 278 
 279         rv = -1;
 280         if (pkcs11_write_random_seed(sbuf, slen) == slen)
 281                 rv = 0;
 282 
 283         pkcs11_close_random_seed();
 284         return (rv);
 285 }
 286 
 287 /*
 288  * Seed /dev/urandom with the data in the buffer.
 289  */
 290 int
 291 pkcs11_seed_urandom(void *sbuf, size_t slen)
 292 {
 293         int     rv;
 294 
 295         if (sbuf == NULL || slen == 0)
 296                 return (0);
 297 
 298         /* Seeding error could mean it's not supported (errno = EACCES) */
 299         if (pkcs11_open_urandom_seed() < 0)
 300                 return (-1);
 301 
 302         rv = -1;
 303         if (pkcs11_write_urandom_seed(sbuf, slen) == slen)
 304                 rv = 0;
 305 
 306         pkcs11_close_urandom_seed();
 307         return (rv);
 308 }
 309 
 310 /*
 311  * Put the requested amount of random data into a preallocated buffer.
 312  * Good for token key data, persistent objects.
 313  */
 314 int
 315 pkcs11_get_random(void *dbuf, size_t dlen)
 316 {
 317         if (dbuf == NULL || dlen == 0)
 318                 return (0);
 319 
 320         /* Read random data directly from /dev/random */
 321         if (pkcs11_open_random() < 0)
 322                 return (-1);
 323 
 324         if (pkcs11_read_random(dbuf, dlen) == dlen)
 325                 return (0);
 326         return (-1);
 327 }
 328 
 329 /*
 330  * Put the requested amount of random data into a preallocated buffer.
 331  * Good for passphrase salts, initialization vectors.
 332  */
 333 int
 334 pkcs11_get_urandom(void *dbuf, size_t dlen)
 335 {
 336         if (dbuf == NULL || dlen == 0)
 337                 return (0);
 338 
 339         /* Read random data directly from /dev/urandom */
 340         if (pkcs11_open_urandom() < 0)
 341                 return (-1);
 342 
 343         if (pkcs11_read_urandom(dbuf, dlen) == dlen)
 344                 return (0);
 345         return (-1);
 346 }
 347 
 348 /*
 349  * Same as pkcs11_get_urandom but ensures non zero data.
 350  */
 351 int
 352 pkcs11_get_nzero_urandom(void *dbuf, size_t dlen)
 353 {
 354         char    extrarand[32];
 355         size_t  bytesleft = 0;
 356         size_t  i = 0;
 357 
 358         /* Start with some random data */
 359         if (pkcs11_get_urandom(dbuf, dlen) < 0)
 360                 return (-1);
 361 
 362         /* Walk through data replacing any 0 bytes with more random data */
 363         while (i < dlen) {
 364                 if (((char *)dbuf)[i] != 0) {
 365                         i++;
 366                         continue;
 367                 }
 368 
 369                 if (bytesleft == 0) {
 370                         bytesleft = sizeof (extrarand);
 371                         if (pkcs11_get_urandom(extrarand, bytesleft) < 0)
 372                                 return (-1);
 373                 }
 374                 bytesleft--;
 375 
 376                 ((char *)dbuf)[i] = extrarand[bytesleft];
 377         }
 378         return (0);
 379 }