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  * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
  25  */
  26 
  27 #include <stdio.h>
  28 #include <unistd.h>
  29 #include <errno.h>
  30 #include <string.h>
  31 #include <fcntl.h>
  32 #include <locale.h>
  33 #include <stdarg.h>
  34 #include <cryptoutil.h>
  35 #include <pthread.h>
  36 
  37 #pragma init(pkcs11_random_init)
  38 
  39 static pthread_mutex_t  random_mutex = PTHREAD_MUTEX_INITIALIZER;
  40 static pthread_mutex_t  urandom_mutex = PTHREAD_MUTEX_INITIALIZER;
  41 
  42 static pthread_mutex_t  random_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
  43 static pthread_mutex_t  urandom_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
  44 
  45 #define RANDOM_DEVICE           "/dev/random"   /* random device name */
  46 #define URANDOM_DEVICE          "/dev/urandom"  /* urandom device name */
  47 
  48 static int      random_fd = -1;
  49 static int      urandom_fd = -1;
  50 
  51 static int      random_seed_fd = -1;
  52 static int      urandom_seed_fd = -1;
  53 
  54 
  55 /*
  56  * Equivalent of open(2) insulated from EINTR.
  57  * Also sets close-on-exec.
  58  */
  59 int
  60 open_nointr(const char *path, int oflag, ...)
  61 {
  62         int     fd;
  63         mode_t  pmode;
  64         va_list alist;
  65 
  66         va_start(alist, oflag);
  67         pmode = va_arg(alist, mode_t);
  68         va_end(alist);
  69 
  70         do {
  71                 if ((fd = open(path, oflag, pmode)) >= 0) {
  72                         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
  73                         break;
  74                 }
  75                 /* errno definitely set by failed open() */
  76         } while (errno == EINTR);
  77         return (fd);
  78 }
  79 
  80 /*
  81  * Equivalent of read(2) insulated from EINTR.
  82  */
  83 ssize_t
  84 readn_nointr(int fd, void *dbuf, size_t dlen)
  85 {
  86         char    *marker = dbuf;
  87         size_t  left = dlen;
  88         ssize_t nread = 0, err;
  89 
  90         for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) {
  91                 if ((nread = read(fd, marker, left)) < 0) {
  92                         if (errno == EINTR) {   /* keep trying */
  93                                 nread = 0;
  94                                 continue;
  95                         }
  96                         err = nread;            /* hard error */
  97                         break;
  98                 } else if (nread == 0) {
  99                         break;
 100                 }
 101         }
 102         return (err != 0 ? err : dlen - left);
 103 }
 104 
 105 /*
 106  * Equivalent of write(2) insulated from EINTR.
 107  */
 108 ssize_t
 109 writen_nointr(int fd, void *dbuf, size_t dlen)
 110 {
 111         char    *marker = dbuf;
 112         size_t  left = dlen;
 113         ssize_t nwrite = 0, err;
 114 
 115         for (err = 0; left > 0 && nwrite != -1; marker += nwrite,
 116             left -= nwrite) {
 117                 if ((nwrite = write(fd, marker, left)) < 0) {
 118                         if (errno == EINTR) {   /* keep trying */
 119                                 nwrite = 0;
 120                                 continue;
 121                         }
 122                         err = nwrite;           /* hard error */
 123                         break;
 124                 } else if (nwrite == 0) {
 125                         break;
 126                 }
 127         }
 128         return (err != 0 ? err : dlen - left);
 129 }
 130 
 131 /*
 132  * Opens the random number generator devices if not already open.
 133  * Always returns the opened fd of the device, or error.
 134  */
 135 static int
 136 pkcs11_open_common(int *fd, pthread_mutex_t *mtx, const char *dev, int oflag)
 137 {
 138         (void) pthread_mutex_lock(mtx);
 139         if (*fd < 0)
 140                 *fd = open_nointr(dev, oflag);
 141         (void) pthread_mutex_unlock(mtx);
 142 
 143         return (*fd);
 144 }
 145 
 146 static int
 147 pkcs11_open_random(void)
 148 {
 149         return (pkcs11_open_common(&random_fd, &random_mutex,
 150             RANDOM_DEVICE, O_RDONLY));
 151 }
 152 
 153 static int
 154 pkcs11_open_urandom(void)
 155 {
 156         return (pkcs11_open_common(&urandom_fd, &urandom_mutex,
 157             URANDOM_DEVICE, O_RDONLY));
 158 }
 159 
 160 static int
 161 pkcs11_open_random_seed(void)
 162 {
 163         return (pkcs11_open_common(&random_seed_fd, &random_seed_mutex,
 164             RANDOM_DEVICE, O_WRONLY));
 165 }
 166 
 167 static int
 168 pkcs11_open_urandom_seed(void)
 169 {
 170         return (pkcs11_open_common(&urandom_seed_fd, &urandom_seed_mutex,
 171             URANDOM_DEVICE, O_WRONLY));
 172 }
 173 
 174 /*
 175  * Close the random number generator devices if already open.
 176  */
 177 static void
 178 pkcs11_close_common(int *fd, pthread_mutex_t *mtx)
 179 {
 180         (void) pthread_mutex_lock(mtx);
 181         (void) close(*fd);
 182         *fd = -1;
 183         (void) pthread_mutex_unlock(mtx);
 184 }
 185 
 186 static void
 187 pkcs11_close_random(void)
 188 {
 189         pkcs11_close_common(&random_fd, &random_mutex);
 190 }
 191 
 192 static void
 193 pkcs11_close_urandom(void)
 194 {
 195         pkcs11_close_common(&urandom_fd, &urandom_mutex);
 196 }
 197 
 198 static void
 199 pkcs11_close_random_seed(void)
 200 {
 201         pkcs11_close_common(&random_seed_fd, &random_seed_mutex);
 202 }
 203 
 204 static void
 205 pkcs11_close_urandom_seed(void)
 206 {
 207         pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex);
 208 }
 209 
 210 /*
 211  * Read from the random number generator devices.
 212  */
 213 static size_t
 214 pkcs11_read_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
 215 {
 216         size_t  n;
 217 
 218         (void) pthread_mutex_lock(mtx);
 219         n = readn_nointr(*fd, dbuf, dlen);
 220         (void) pthread_mutex_unlock(mtx);
 221 
 222         return (n);
 223 }
 224 
 225 static size_t
 226 pkcs11_read_random(void *dbuf, size_t dlen)
 227 {
 228         return (pkcs11_read_common(&random_fd, &random_mutex, dbuf, dlen));
 229 }
 230 
 231 static size_t
 232 pkcs11_read_urandom(void *dbuf, size_t dlen)
 233 {
 234         return (pkcs11_read_common(&urandom_fd, &urandom_mutex, dbuf, dlen));
 235 }
 236 
 237 /*
 238  * Write to the random number generator devices.
 239  */
 240 static size_t
 241 pkcs11_write_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
 242 {
 243         size_t  n;
 244 
 245         (void) pthread_mutex_lock(mtx);
 246         n = writen_nointr(*fd, dbuf, dlen);
 247         (void) pthread_mutex_unlock(mtx);
 248 
 249         return (n);
 250 }
 251 
 252 static size_t
 253 pkcs11_write_random_seed(void *dbuf, size_t dlen)
 254 {
 255         return (pkcs11_write_common(&random_seed_fd, &random_seed_mutex,
 256             dbuf, dlen));
 257 }
 258 
 259 static size_t
 260 pkcs11_write_urandom_seed(void *dbuf, size_t dlen)
 261 {
 262         return (pkcs11_write_common(&urandom_seed_fd, &urandom_seed_mutex,
 263             dbuf, dlen));
 264 }
 265 
 266 /*
 267  * Seed /dev/random with the data in the buffer.
 268  */
 269 int
 270 pkcs11_seed_random(void *sbuf, size_t slen)
 271 {
 272         int     rv;
 273 
 274         if (sbuf == NULL || slen == 0)
 275                 return (0);
 276 
 277         /* Seeding error could mean it's not supported (errno = EACCES) */
 278         if (pkcs11_open_random_seed() < 0)
 279                 return (-1);
 280 
 281         rv = -1;
 282         if (pkcs11_write_random_seed(sbuf, slen) == slen)
 283                 rv = 0;
 284 
 285         pkcs11_close_random_seed();
 286         return (rv);
 287 }
 288 
 289 /*
 290  * Seed /dev/urandom with the data in the buffer.
 291  */
 292 int
 293 pkcs11_seed_urandom(void *sbuf, size_t slen)
 294 {
 295         int     rv;
 296 
 297         if (sbuf == NULL || slen == 0)
 298                 return (0);
 299 
 300         /* Seeding error could mean it's not supported (errno = EACCES) */
 301         if (pkcs11_open_urandom_seed() < 0)
 302                 return (-1);
 303 
 304         rv = -1;
 305         if (pkcs11_write_urandom_seed(sbuf, slen) == slen)
 306                 rv = 0;
 307 
 308         pkcs11_close_urandom_seed();
 309         return (rv);
 310 }
 311 
 312 /*
 313  * Put the requested amount of random data into a preallocated buffer.
 314  * Good for token key data, persistent objects.
 315  */
 316 int
 317 pkcs11_get_random(void *dbuf, size_t dlen)
 318 {
 319         if (dbuf == NULL || dlen == 0)
 320                 return (0);
 321 
 322         /* Read random data directly from /dev/random */
 323         if (pkcs11_open_random() < 0)
 324                 return (-1);
 325 
 326         if (pkcs11_read_random(dbuf, dlen) == dlen)
 327                 return (0);
 328         return (-1);
 329 }
 330 
 331 /*
 332  * Put the requested amount of random data into a preallocated buffer.
 333  * Good for passphrase salts, initialization vectors.
 334  */
 335 int
 336 pkcs11_get_urandom(void *dbuf, size_t dlen)
 337 {
 338         if (dbuf == NULL || dlen == 0)
 339                 return (0);
 340 
 341         /* Read random data directly from /dev/urandom */
 342         if (pkcs11_open_urandom() < 0)
 343                 return (-1);
 344 
 345         if (pkcs11_read_urandom(dbuf, dlen) == dlen)
 346                 return (0);
 347         return (-1);
 348 }
 349 
 350 /*
 351  * Same as pkcs11_get_urandom but ensures non zero data.
 352  */
 353 int
 354 pkcs11_get_nzero_urandom(void *dbuf, size_t dlen)
 355 {
 356         char    extrarand[32];
 357         size_t  bytesleft = 0;
 358         size_t  i = 0;
 359 
 360         /* Start with some random data */
 361         if (pkcs11_get_urandom(dbuf, dlen) < 0)
 362                 return (-1);
 363 
 364         /* Walk through data replacing any 0 bytes with more random data */
 365         while (i < dlen) {
 366                 if (((char *)dbuf)[i] != 0) {
 367                         i++;
 368                         continue;
 369                 }
 370 
 371                 if (bytesleft == 0) {
 372                         bytesleft = sizeof (extrarand);
 373                         if (pkcs11_get_urandom(extrarand, bytesleft) < 0)
 374                                 return (-1);
 375                 }
 376                 bytesleft--;
 377 
 378                 ((char *)dbuf)[i] = extrarand[bytesleft];
 379         }
 380         return (0);
 381 }
 382 
 383 static void
 384 pkcs11_random_prepare(void)
 385 {
 386         /*
 387          * NOTE - None of these are acquired more than one at a time.
 388          * I can therefore acquire all four without fear of deadlock.
 389          */
 390         (void) pthread_mutex_lock(&random_mutex);
 391         (void) pthread_mutex_lock(&urandom_mutex);
 392         (void) pthread_mutex_lock(&random_seed_mutex);
 393         (void) pthread_mutex_lock(&urandom_seed_mutex);
 394 }
 395 
 396 static void
 397 pkcs11_random_parent_post(void)
 398 {
 399         /* Drop the mutexes and get back to work! */
 400         (void) pthread_mutex_unlock(&urandom_seed_mutex);
 401         (void) pthread_mutex_unlock(&random_seed_mutex);
 402         (void) pthread_mutex_unlock(&urandom_mutex);
 403         (void) pthread_mutex_unlock(&random_mutex);
 404 }
 405 
 406 static void
 407 pkcs11_random_child_post(void)
 408 {
 409         pkcs11_random_parent_post();
 410 
 411         /* Also, close the FDs, just in case. */
 412         pkcs11_close_random();
 413         pkcs11_close_urandom();
 414         pkcs11_close_random_seed();
 415         pkcs11_close_urandom_seed();
 416 }
 417 
 418 static void
 419 pkcs11_random_init(void)
 420 {
 421         (void) pthread_atfork(pkcs11_random_prepare, pkcs11_random_parent_post,
 422             pkcs11_random_child_post);
 423 }