11c9bd843Sdinak /* 21c9bd843Sdinak * CDDL HEADER START 31c9bd843Sdinak * 41c9bd843Sdinak * The contents of this file are subject to the terms of the 51c9bd843Sdinak * Common Development and Distribution License (the "License"). 61c9bd843Sdinak * You may not use this file except in compliance with the License. 71c9bd843Sdinak * 81c9bd843Sdinak * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91c9bd843Sdinak * or http://www.opensolaris.org/os/licensing. 101c9bd843Sdinak * See the License for the specific language governing permissions 111c9bd843Sdinak * and limitations under the License. 121c9bd843Sdinak * 131c9bd843Sdinak * When distributing Covered Code, include this CDDL HEADER in each 141c9bd843Sdinak * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151c9bd843Sdinak * If applicable, add the following below this CDDL HEADER, with the 161c9bd843Sdinak * fields enclosed by brackets "[]" replaced with your own identifying 171c9bd843Sdinak * information: Portions Copyright [yyyy] [name of copyright owner] 181c9bd843Sdinak * 191c9bd843Sdinak * CDDL HEADER END 201c9bd843Sdinak */ 211c9bd843Sdinak /* 22*26ff1ce9Sdinak * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 231c9bd843Sdinak * Use is subject to license terms. 241c9bd843Sdinak */ 251c9bd843Sdinak 261c9bd843Sdinak #pragma ident "%Z%%M% %I% %E% SMI" 271c9bd843Sdinak 281c9bd843Sdinak #include <stdio.h> 29*26ff1ce9Sdinak #include <unistd.h> 30*26ff1ce9Sdinak #include <errno.h> 311c9bd843Sdinak #include <string.h> 321c9bd843Sdinak #include <fcntl.h> 331c9bd843Sdinak #include <locale.h> 341c9bd843Sdinak #include <cryptoutil.h> 351c9bd843Sdinak 36*26ff1ce9Sdinak #ifdef _REENTRANT 37*26ff1ce9Sdinak 38*26ff1ce9Sdinak #include <pthread.h> 39*26ff1ce9Sdinak 40*26ff1ce9Sdinak static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER; 41*26ff1ce9Sdinak static pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER; 42*26ff1ce9Sdinak 43*26ff1ce9Sdinak #define RAND_LOCK(x) (void) pthread_mutex_lock(x) 44*26ff1ce9Sdinak #define RAND_UNLOCK(x) (void) pthread_mutex_unlock(x) 45*26ff1ce9Sdinak 46*26ff1ce9Sdinak #else 47*26ff1ce9Sdinak 48*26ff1ce9Sdinak #define RAND_LOCK(x) 49*26ff1ce9Sdinak #define RAND_UNLOCK(x) 50*26ff1ce9Sdinak 51*26ff1ce9Sdinak #endif 52*26ff1ce9Sdinak 53*26ff1ce9Sdinak #define RANDOM_DEVICE "/dev/random" /* random device name */ 54*26ff1ce9Sdinak #define URANDOM_DEVICE "/dev/urandom" /* urandom device name */ 55*26ff1ce9Sdinak 56*26ff1ce9Sdinak static int random_fd = -1; 57*26ff1ce9Sdinak static int urandom_fd = -1; 58*26ff1ce9Sdinak 59*26ff1ce9Sdinak /* 60*26ff1ce9Sdinak * Equivalent of open(2) insulated from EINTR. 61*26ff1ce9Sdinak * Also sets close-on-exec. 62*26ff1ce9Sdinak */ 63*26ff1ce9Sdinak static int 64*26ff1ce9Sdinak OPEN(const char *path, int oflag) 65*26ff1ce9Sdinak { 66*26ff1ce9Sdinak int fd; 67*26ff1ce9Sdinak 68*26ff1ce9Sdinak do { 69*26ff1ce9Sdinak if ((fd = open(path, oflag)) >= 0) { 70*26ff1ce9Sdinak (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 71*26ff1ce9Sdinak break; 72*26ff1ce9Sdinak } 73*26ff1ce9Sdinak /* errno definitely set by failed open() */ 74*26ff1ce9Sdinak } while (errno == EINTR); 75*26ff1ce9Sdinak return (fd); 76*26ff1ce9Sdinak } 77*26ff1ce9Sdinak 78*26ff1ce9Sdinak /* 79*26ff1ce9Sdinak * Equivalent of read(2) insulated from EINTR. 80*26ff1ce9Sdinak */ 81*26ff1ce9Sdinak static ssize_t 82*26ff1ce9Sdinak READ(int fd, void *dbuf, size_t dlen) 83*26ff1ce9Sdinak { 84*26ff1ce9Sdinak char *marker = dbuf; 85*26ff1ce9Sdinak size_t left = dlen; 86*26ff1ce9Sdinak ssize_t nread = 0, err; 87*26ff1ce9Sdinak 88*26ff1ce9Sdinak for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) { 89*26ff1ce9Sdinak if ((nread = read(fd, marker, left)) < 0) { 90*26ff1ce9Sdinak if (errno == EINTR) { /* keep trying */ 91*26ff1ce9Sdinak nread = 0; 92*26ff1ce9Sdinak continue; 93*26ff1ce9Sdinak } 94*26ff1ce9Sdinak err = nread; /* hard error */ 95*26ff1ce9Sdinak break; 96*26ff1ce9Sdinak } 97*26ff1ce9Sdinak } 98*26ff1ce9Sdinak return (err != 0 ? err : dlen - left); 99*26ff1ce9Sdinak } 100*26ff1ce9Sdinak 101*26ff1ce9Sdinak /* 102*26ff1ce9Sdinak * Opens the random number generator devices if not already open. 103*26ff1ce9Sdinak * Always returns the opened fd of the device, or error. 104*26ff1ce9Sdinak */ 105*26ff1ce9Sdinak int 106*26ff1ce9Sdinak pkcs11_open_random(void) 107*26ff1ce9Sdinak { 108*26ff1ce9Sdinak RAND_LOCK(&random_mutex); 109*26ff1ce9Sdinak if (random_fd < 0) 110*26ff1ce9Sdinak random_fd = OPEN(RANDOM_DEVICE, O_RDONLY); 111*26ff1ce9Sdinak RAND_UNLOCK(&random_mutex); 112*26ff1ce9Sdinak return (random_fd); 113*26ff1ce9Sdinak } 114*26ff1ce9Sdinak 115*26ff1ce9Sdinak int 116*26ff1ce9Sdinak pkcs11_open_urandom(void) 117*26ff1ce9Sdinak { 118*26ff1ce9Sdinak RAND_LOCK(&urandom_mutex); 119*26ff1ce9Sdinak if (urandom_fd < 0) 120*26ff1ce9Sdinak urandom_fd = OPEN(URANDOM_DEVICE, O_RDONLY); 121*26ff1ce9Sdinak RAND_UNLOCK(&urandom_mutex); 122*26ff1ce9Sdinak return (urandom_fd); 123*26ff1ce9Sdinak } 124*26ff1ce9Sdinak 125*26ff1ce9Sdinak /* 126*26ff1ce9Sdinak * Close the random number generator devices if already open. 127*26ff1ce9Sdinak */ 128*26ff1ce9Sdinak void 129*26ff1ce9Sdinak pkcs11_close_random(void) 130*26ff1ce9Sdinak { 131*26ff1ce9Sdinak if (random_fd < 0) 132*26ff1ce9Sdinak return; 133*26ff1ce9Sdinak RAND_LOCK(&random_mutex); 134*26ff1ce9Sdinak (void) close(random_fd); 135*26ff1ce9Sdinak random_fd = -1; 136*26ff1ce9Sdinak RAND_UNLOCK(&random_mutex); 137*26ff1ce9Sdinak } 138*26ff1ce9Sdinak 139*26ff1ce9Sdinak void 140*26ff1ce9Sdinak pkcs11_close_urandom(void) 141*26ff1ce9Sdinak { 142*26ff1ce9Sdinak if (urandom_fd < 0) 143*26ff1ce9Sdinak return; 144*26ff1ce9Sdinak RAND_LOCK(&urandom_mutex); 145*26ff1ce9Sdinak (void) close(urandom_fd); 146*26ff1ce9Sdinak urandom_fd = -1; 147*26ff1ce9Sdinak RAND_UNLOCK(&urandom_mutex); 148*26ff1ce9Sdinak } 1491c9bd843Sdinak 1501c9bd843Sdinak /* 1511c9bd843Sdinak * Put the requested amount of random data into a preallocated buffer. 1521c9bd843Sdinak * Good for passphrase salts, initialization vectors. 1531c9bd843Sdinak */ 1541c9bd843Sdinak int 1551c9bd843Sdinak pkcs11_random_data(void *dbuf, size_t dlen) 1561c9bd843Sdinak { 1571c9bd843Sdinak if (dbuf == NULL || dlen == 0) 1581c9bd843Sdinak return (0); 1591c9bd843Sdinak 1601c9bd843Sdinak /* Read random data directly from /dev/urandom */ 161*26ff1ce9Sdinak if (pkcs11_open_urandom() < 0) 1621c9bd843Sdinak return (-1); 163*26ff1ce9Sdinak 164*26ff1ce9Sdinak if (READ(urandom_fd, dbuf, dlen) == dlen) 165*26ff1ce9Sdinak return (0); 166*26ff1ce9Sdinak return (-1); 167*26ff1ce9Sdinak } 168*26ff1ce9Sdinak 169*26ff1ce9Sdinak /* 170*26ff1ce9Sdinak * Same as pkcs11_random_data but ensures non zero data. 171*26ff1ce9Sdinak */ 172*26ff1ce9Sdinak int 173*26ff1ce9Sdinak pkcs11_nzero_random_data(void *dbuf, size_t dlen) 174*26ff1ce9Sdinak { 175*26ff1ce9Sdinak char extrarand[32]; 176*26ff1ce9Sdinak size_t bytesleft = 0; 177*26ff1ce9Sdinak size_t i = 0; 178*26ff1ce9Sdinak 179*26ff1ce9Sdinak /* Start with some random data */ 180*26ff1ce9Sdinak if (pkcs11_random_data(dbuf, dlen) < 0) 181*26ff1ce9Sdinak return (-1); 182*26ff1ce9Sdinak 183*26ff1ce9Sdinak /* Walk through data replacing any 0 bytes with more random data */ 184*26ff1ce9Sdinak while (i < dlen) { 185*26ff1ce9Sdinak if (((char *)dbuf)[i] != 0) { 186*26ff1ce9Sdinak i++; 187*26ff1ce9Sdinak continue; 188*26ff1ce9Sdinak } 189*26ff1ce9Sdinak 190*26ff1ce9Sdinak if (bytesleft == 0) { 191*26ff1ce9Sdinak bytesleft = sizeof (extrarand); 192*26ff1ce9Sdinak if (pkcs11_random_data(extrarand, bytesleft) < 0) 193*26ff1ce9Sdinak return (-1); 194*26ff1ce9Sdinak } 195*26ff1ce9Sdinak bytesleft--; 196*26ff1ce9Sdinak 197*26ff1ce9Sdinak ((char *)dbuf)[i] = extrarand[bytesleft]; 198*26ff1ce9Sdinak } 199*26ff1ce9Sdinak return (0); 2001c9bd843Sdinak } 201