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 } 424