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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 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 if (*fd < 0) { 137 (void) pthread_mutex_lock(mtx); 138 if (*fd < 0) 139 *fd = open_nointr(dev, oflag); 140 (void) pthread_mutex_unlock(mtx); 141 } 142 return (*fd); 143 } 144 145 static int 146 pkcs11_open_random(void) 147 { 148 return (pkcs11_open_common(&random_fd, &random_mutex, 149 RANDOM_DEVICE, O_RDONLY)); 150 } 151 152 static int 153 pkcs11_open_urandom(void) 154 { 155 return (pkcs11_open_common(&urandom_fd, &urandom_mutex, 156 URANDOM_DEVICE, O_RDONLY)); 157 } 158 159 static int 160 pkcs11_open_random_seed(void) 161 { 162 return (pkcs11_open_common(&random_seed_fd, &random_seed_mutex, 163 RANDOM_DEVICE, O_WRONLY)); 164 } 165 166 static int 167 pkcs11_open_urandom_seed(void) 168 { 169 return (pkcs11_open_common(&urandom_seed_fd, &urandom_seed_mutex, 170 URANDOM_DEVICE, O_WRONLY)); 171 } 172 173 /* 174 * Close the random number generator devices if already open. 175 */ 176 static void 177 pkcs11_close_common(int *fd, pthread_mutex_t *mtx) 178 { 179 if (*fd < 0) 180 return; 181 (void) pthread_mutex_lock(mtx); 182 (void) close(*fd); 183 *fd = -1; 184 (void) pthread_mutex_unlock(mtx); 185 } 186 187 void 188 pkcs11_close_random(void) 189 { 190 pkcs11_close_common(&random_fd, &random_mutex); 191 } 192 193 void 194 pkcs11_close_urandom(void) 195 { 196 pkcs11_close_common(&urandom_fd, &urandom_mutex); 197 } 198 199 static void 200 pkcs11_close_random_seed(void) 201 { 202 pkcs11_close_common(&random_seed_fd, &random_seed_mutex); 203 } 204 205 void 206 pkcs11_close_urandom_seed(void) 207 { 208 pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex); 209 } 210 211 /* 212 * Seed /dev/random with the data in the buffer. 213 */ 214 int 215 pkcs11_seed_random(void *sbuf, size_t slen) 216 { 217 if (sbuf == NULL || slen == 0) 218 return (0); 219 220 /* Seeding error could mean it's not supported (errno = EACCES) */ 221 if (pkcs11_open_random_seed() < 0) 222 return (-1); 223 224 if (writen_nointr(random_seed_fd, sbuf, slen) == slen) { 225 pkcs11_close_random_seed(); 226 return (0); 227 } 228 return (-1); 229 } 230 231 /* 232 * Seed /dev/urandom with the data in the buffer. 233 */ 234 int 235 pkcs11_seed_urandom(void *sbuf, size_t slen) 236 { 237 if (sbuf == NULL || slen == 0) 238 return (0); 239 240 /* Seeding error could mean it's not supported (errno = EACCES) */ 241 if (pkcs11_open_urandom_seed() < 0) 242 return (-1); 243 244 if (writen_nointr(urandom_seed_fd, sbuf, slen) == slen) { 245 pkcs11_close_urandom_seed(); 246 return (0); 247 } 248 return (-1); 249 } 250 251 /* 252 * Put the requested amount of random data into a preallocated buffer. 253 * Good for token key data, persistent objects. 254 */ 255 int 256 pkcs11_get_random(void *dbuf, size_t dlen) 257 { 258 if (dbuf == NULL || dlen == 0) 259 return (0); 260 261 /* Read random data directly from /dev/random */ 262 if (pkcs11_open_random() < 0) 263 return (-1); 264 265 if (readn_nointr(random_fd, dbuf, dlen) == dlen) 266 return (0); 267 return (-1); 268 } 269 270 /* 271 * Put the requested amount of random data into a preallocated buffer. 272 * Good for passphrase salts, initialization vectors. 273 */ 274 int 275 pkcs11_get_urandom(void *dbuf, size_t dlen) 276 { 277 if (dbuf == NULL || dlen == 0) 278 return (0); 279 280 /* Read random data directly from /dev/urandom */ 281 if (pkcs11_open_urandom() < 0) 282 return (-1); 283 284 if (readn_nointr(urandom_fd, dbuf, dlen) == dlen) 285 return (0); 286 return (-1); 287 } 288 289 /* 290 * Same as pkcs11_get_urandom but ensures non zero data. 291 */ 292 int 293 pkcs11_get_nzero_urandom(void *dbuf, size_t dlen) 294 { 295 char extrarand[32]; 296 size_t bytesleft = 0; 297 size_t i = 0; 298 299 /* Start with some random data */ 300 if (pkcs11_get_urandom(dbuf, dlen) < 0) 301 return (-1); 302 303 /* Walk through data replacing any 0 bytes with more random data */ 304 while (i < dlen) { 305 if (((char *)dbuf)[i] != 0) { 306 i++; 307 continue; 308 } 309 310 if (bytesleft == 0) { 311 bytesleft = sizeof (extrarand); 312 if (pkcs11_get_urandom(extrarand, bytesleft) < 0) 313 return (-1); 314 } 315 bytesleft--; 316 317 ((char *)dbuf)[i] = extrarand[bytesleft]; 318 } 319 return (0); 320 } 321