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