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 35 #ifdef _REENTRANT 36 37 #include <pthread.h> 38 39 static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER; 40 static pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER; 41 42 #define RAND_LOCK(x) (void) pthread_mutex_lock(x) 43 #define RAND_UNLOCK(x) (void) pthread_mutex_unlock(x) 44 45 #else 46 47 #define RAND_LOCK(x) 48 #define RAND_UNLOCK(x) 49 50 #endif 51 52 #define RANDOM_DEVICE "/dev/random" /* random device name */ 53 #define URANDOM_DEVICE "/dev/urandom" /* urandom device name */ 54 55 static int random_fd = -1; 56 static int urandom_fd = -1; 57 58 /* 59 * Equivalent of open(2) insulated from EINTR. 60 * Also sets close-on-exec. 61 */ 62 int 63 open_nointr(const char *path, int oflag, ...) 64 { 65 int fd; 66 mode_t pmode; 67 va_list alist; 68 69 va_start(alist, oflag); 70 pmode = va_arg(alist, mode_t); 71 va_end(alist); 72 73 do { 74 if ((fd = open(path, oflag, pmode)) >= 0) { 75 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 76 break; 77 } 78 /* errno definitely set by failed open() */ 79 } while (errno == EINTR); 80 return (fd); 81 } 82 83 /* 84 * Equivalent of read(2) insulated from EINTR. 85 */ 86 ssize_t 87 readn_nointr(int fd, void *dbuf, size_t dlen) 88 { 89 char *marker = dbuf; 90 size_t left = dlen; 91 ssize_t nread = 0, err; 92 93 for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) { 94 if ((nread = read(fd, marker, left)) < 0) { 95 if (errno == EINTR) { /* keep trying */ 96 nread = 0; 97 continue; 98 } 99 err = nread; /* hard error */ 100 break; 101 } else if (nread == 0) { 102 break; 103 } 104 } 105 return (err != 0 ? err : dlen - left); 106 } 107 108 /* 109 * Equivalent of write(2) insulated from EINTR. 110 */ 111 ssize_t 112 writen_nointr(int fd, void *dbuf, size_t dlen) 113 { 114 char *marker = dbuf; 115 size_t left = dlen; 116 ssize_t nwrite = 0, err; 117 118 for (err = 0; left > 0 && nwrite != -1; marker += nwrite, 119 left -= nwrite) { 120 if ((nwrite = write(fd, marker, left)) < 0) { 121 if (errno == EINTR) { /* keep trying */ 122 nwrite = 0; 123 continue; 124 } 125 err = nwrite; /* hard error */ 126 break; 127 } else if (nwrite == 0) { 128 break; 129 } 130 } 131 return (err != 0 ? err : dlen - left); 132 } 133 134 /* 135 * Opens the random number generator devices if not already open. 136 * Always returns the opened fd of the device, or error. 137 */ 138 int 139 pkcs11_open_random(void) 140 { 141 RAND_LOCK(&random_mutex); 142 if (random_fd < 0) 143 random_fd = open_nointr(RANDOM_DEVICE, O_RDONLY); 144 RAND_UNLOCK(&random_mutex); 145 return (random_fd); 146 } 147 148 int 149 pkcs11_open_urandom(void) 150 { 151 RAND_LOCK(&urandom_mutex); 152 if (urandom_fd < 0) 153 urandom_fd = open_nointr(URANDOM_DEVICE, O_RDONLY); 154 RAND_UNLOCK(&urandom_mutex); 155 return (urandom_fd); 156 } 157 158 /* 159 * Close the random number generator devices if already open. 160 */ 161 void 162 pkcs11_close_random(void) 163 { 164 if (random_fd < 0) 165 return; 166 RAND_LOCK(&random_mutex); 167 (void) close(random_fd); 168 random_fd = -1; 169 RAND_UNLOCK(&random_mutex); 170 } 171 172 void 173 pkcs11_close_urandom(void) 174 { 175 if (urandom_fd < 0) 176 return; 177 RAND_LOCK(&urandom_mutex); 178 (void) close(urandom_fd); 179 urandom_fd = -1; 180 RAND_UNLOCK(&urandom_mutex); 181 } 182 183 /* 184 * Put the requested amount of random data into a preallocated buffer. 185 * Good for passphrase salts, initialization vectors. 186 */ 187 int 188 pkcs11_random_data(void *dbuf, size_t dlen) 189 { 190 if (dbuf == NULL || dlen == 0) 191 return (0); 192 193 /* Read random data directly from /dev/urandom */ 194 if (pkcs11_open_urandom() < 0) 195 return (-1); 196 197 if (readn_nointr(urandom_fd, dbuf, dlen) == dlen) 198 return (0); 199 return (-1); 200 } 201 202 /* 203 * Same as pkcs11_random_data but ensures non zero data. 204 */ 205 int 206 pkcs11_nzero_random_data(void *dbuf, size_t dlen) 207 { 208 char extrarand[32]; 209 size_t bytesleft = 0; 210 size_t i = 0; 211 212 /* Start with some random data */ 213 if (pkcs11_random_data(dbuf, dlen) < 0) 214 return (-1); 215 216 /* Walk through data replacing any 0 bytes with more random data */ 217 while (i < dlen) { 218 if (((char *)dbuf)[i] != 0) { 219 i++; 220 continue; 221 } 222 223 if (bytesleft == 0) { 224 bytesleft = sizeof (extrarand); 225 if (pkcs11_random_data(extrarand, bytesleft) < 0) 226 return (-1); 227 } 228 bytesleft--; 229 230 ((char *)dbuf)[i] = extrarand[bytesleft]; 231 } 232 return (0); 233 } 234