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*19193bb6SDina K Nimeh * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 231c9bd843Sdinak * Use is subject to license terms. 241c9bd843Sdinak */ 251c9bd843Sdinak 261c9bd843Sdinak #include <stdio.h> 2726ff1ce9Sdinak #include <unistd.h> 2826ff1ce9Sdinak #include <errno.h> 291c9bd843Sdinak #include <string.h> 301c9bd843Sdinak #include <fcntl.h> 311c9bd843Sdinak #include <locale.h> 32*19193bb6SDina K Nimeh #include <stdarg.h> 331c9bd843Sdinak #include <cryptoutil.h> 341c9bd843Sdinak 3526ff1ce9Sdinak #ifdef _REENTRANT 3626ff1ce9Sdinak 3726ff1ce9Sdinak #include <pthread.h> 3826ff1ce9Sdinak 3926ff1ce9Sdinak static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER; 4026ff1ce9Sdinak static pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER; 4126ff1ce9Sdinak 4226ff1ce9Sdinak #define RAND_LOCK(x) (void) pthread_mutex_lock(x) 4326ff1ce9Sdinak #define RAND_UNLOCK(x) (void) pthread_mutex_unlock(x) 4426ff1ce9Sdinak 4526ff1ce9Sdinak #else 4626ff1ce9Sdinak 4726ff1ce9Sdinak #define RAND_LOCK(x) 4826ff1ce9Sdinak #define RAND_UNLOCK(x) 4926ff1ce9Sdinak 5026ff1ce9Sdinak #endif 5126ff1ce9Sdinak 5226ff1ce9Sdinak #define RANDOM_DEVICE "/dev/random" /* random device name */ 5326ff1ce9Sdinak #define URANDOM_DEVICE "/dev/urandom" /* urandom device name */ 5426ff1ce9Sdinak 5526ff1ce9Sdinak static int random_fd = -1; 5626ff1ce9Sdinak static int urandom_fd = -1; 5726ff1ce9Sdinak 5826ff1ce9Sdinak /* 5926ff1ce9Sdinak * Equivalent of open(2) insulated from EINTR. 6026ff1ce9Sdinak * Also sets close-on-exec. 6126ff1ce9Sdinak */ 62*19193bb6SDina K Nimeh int 63*19193bb6SDina K Nimeh open_nointr(const char *path, int oflag, ...) 6426ff1ce9Sdinak { 6526ff1ce9Sdinak int fd; 66*19193bb6SDina K Nimeh mode_t pmode; 67*19193bb6SDina K Nimeh va_list alist; 68*19193bb6SDina K Nimeh 69*19193bb6SDina K Nimeh va_start(alist, oflag); 70*19193bb6SDina K Nimeh pmode = va_arg(alist, mode_t); 71*19193bb6SDina K Nimeh va_end(alist); 7226ff1ce9Sdinak 7326ff1ce9Sdinak do { 74*19193bb6SDina K Nimeh if ((fd = open(path, oflag, pmode)) >= 0) { 7526ff1ce9Sdinak (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 7626ff1ce9Sdinak break; 7726ff1ce9Sdinak } 7826ff1ce9Sdinak /* errno definitely set by failed open() */ 7926ff1ce9Sdinak } while (errno == EINTR); 8026ff1ce9Sdinak return (fd); 8126ff1ce9Sdinak } 8226ff1ce9Sdinak 8326ff1ce9Sdinak /* 8426ff1ce9Sdinak * Equivalent of read(2) insulated from EINTR. 8526ff1ce9Sdinak */ 86*19193bb6SDina K Nimeh ssize_t 87*19193bb6SDina K Nimeh readn_nointr(int fd, void *dbuf, size_t dlen) 8826ff1ce9Sdinak { 8926ff1ce9Sdinak char *marker = dbuf; 9026ff1ce9Sdinak size_t left = dlen; 9126ff1ce9Sdinak ssize_t nread = 0, err; 9226ff1ce9Sdinak 9326ff1ce9Sdinak for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) { 9426ff1ce9Sdinak if ((nread = read(fd, marker, left)) < 0) { 9526ff1ce9Sdinak if (errno == EINTR) { /* keep trying */ 9626ff1ce9Sdinak nread = 0; 9726ff1ce9Sdinak continue; 9826ff1ce9Sdinak } 9926ff1ce9Sdinak err = nread; /* hard error */ 10026ff1ce9Sdinak break; 101*19193bb6SDina K Nimeh } else if (nread == 0) { 102*19193bb6SDina K Nimeh break; 103*19193bb6SDina K Nimeh } 104*19193bb6SDina K Nimeh } 105*19193bb6SDina K Nimeh return (err != 0 ? err : dlen - left); 106*19193bb6SDina K Nimeh } 107*19193bb6SDina K Nimeh 108*19193bb6SDina K Nimeh /* 109*19193bb6SDina K Nimeh * Equivalent of write(2) insulated from EINTR. 110*19193bb6SDina K Nimeh */ 111*19193bb6SDina K Nimeh ssize_t 112*19193bb6SDina K Nimeh writen_nointr(int fd, void *dbuf, size_t dlen) 113*19193bb6SDina K Nimeh { 114*19193bb6SDina K Nimeh char *marker = dbuf; 115*19193bb6SDina K Nimeh size_t left = dlen; 116*19193bb6SDina K Nimeh ssize_t nwrite = 0, err; 117*19193bb6SDina K Nimeh 118*19193bb6SDina K Nimeh for (err = 0; left > 0 && nwrite != -1; marker += nwrite, 119*19193bb6SDina K Nimeh left -= nwrite) { 120*19193bb6SDina K Nimeh if ((nwrite = write(fd, marker, left)) < 0) { 121*19193bb6SDina K Nimeh if (errno == EINTR) { /* keep trying */ 122*19193bb6SDina K Nimeh nwrite = 0; 123*19193bb6SDina K Nimeh continue; 124*19193bb6SDina K Nimeh } 125*19193bb6SDina K Nimeh err = nwrite; /* hard error */ 126*19193bb6SDina K Nimeh break; 127*19193bb6SDina K Nimeh } else if (nwrite == 0) { 128*19193bb6SDina K Nimeh break; 12926ff1ce9Sdinak } 13026ff1ce9Sdinak } 13126ff1ce9Sdinak return (err != 0 ? err : dlen - left); 13226ff1ce9Sdinak } 13326ff1ce9Sdinak 13426ff1ce9Sdinak /* 13526ff1ce9Sdinak * Opens the random number generator devices if not already open. 13626ff1ce9Sdinak * Always returns the opened fd of the device, or error. 13726ff1ce9Sdinak */ 13826ff1ce9Sdinak int 13926ff1ce9Sdinak pkcs11_open_random(void) 14026ff1ce9Sdinak { 14126ff1ce9Sdinak RAND_LOCK(&random_mutex); 14226ff1ce9Sdinak if (random_fd < 0) 143*19193bb6SDina K Nimeh random_fd = open_nointr(RANDOM_DEVICE, O_RDONLY); 14426ff1ce9Sdinak RAND_UNLOCK(&random_mutex); 14526ff1ce9Sdinak return (random_fd); 14626ff1ce9Sdinak } 14726ff1ce9Sdinak 14826ff1ce9Sdinak int 14926ff1ce9Sdinak pkcs11_open_urandom(void) 15026ff1ce9Sdinak { 15126ff1ce9Sdinak RAND_LOCK(&urandom_mutex); 15226ff1ce9Sdinak if (urandom_fd < 0) 153*19193bb6SDina K Nimeh urandom_fd = open_nointr(URANDOM_DEVICE, O_RDONLY); 15426ff1ce9Sdinak RAND_UNLOCK(&urandom_mutex); 15526ff1ce9Sdinak return (urandom_fd); 15626ff1ce9Sdinak } 15726ff1ce9Sdinak 15826ff1ce9Sdinak /* 15926ff1ce9Sdinak * Close the random number generator devices if already open. 16026ff1ce9Sdinak */ 16126ff1ce9Sdinak void 16226ff1ce9Sdinak pkcs11_close_random(void) 16326ff1ce9Sdinak { 16426ff1ce9Sdinak if (random_fd < 0) 16526ff1ce9Sdinak return; 16626ff1ce9Sdinak RAND_LOCK(&random_mutex); 16726ff1ce9Sdinak (void) close(random_fd); 16826ff1ce9Sdinak random_fd = -1; 16926ff1ce9Sdinak RAND_UNLOCK(&random_mutex); 17026ff1ce9Sdinak } 17126ff1ce9Sdinak 17226ff1ce9Sdinak void 17326ff1ce9Sdinak pkcs11_close_urandom(void) 17426ff1ce9Sdinak { 17526ff1ce9Sdinak if (urandom_fd < 0) 17626ff1ce9Sdinak return; 17726ff1ce9Sdinak RAND_LOCK(&urandom_mutex); 17826ff1ce9Sdinak (void) close(urandom_fd); 17926ff1ce9Sdinak urandom_fd = -1; 18026ff1ce9Sdinak RAND_UNLOCK(&urandom_mutex); 18126ff1ce9Sdinak } 1821c9bd843Sdinak 1831c9bd843Sdinak /* 1841c9bd843Sdinak * Put the requested amount of random data into a preallocated buffer. 1851c9bd843Sdinak * Good for passphrase salts, initialization vectors. 1861c9bd843Sdinak */ 1871c9bd843Sdinak int 1881c9bd843Sdinak pkcs11_random_data(void *dbuf, size_t dlen) 1891c9bd843Sdinak { 1901c9bd843Sdinak if (dbuf == NULL || dlen == 0) 1911c9bd843Sdinak return (0); 1921c9bd843Sdinak 1931c9bd843Sdinak /* Read random data directly from /dev/urandom */ 19426ff1ce9Sdinak if (pkcs11_open_urandom() < 0) 1951c9bd843Sdinak return (-1); 19626ff1ce9Sdinak 197*19193bb6SDina K Nimeh if (readn_nointr(urandom_fd, dbuf, dlen) == dlen) 19826ff1ce9Sdinak return (0); 19926ff1ce9Sdinak return (-1); 20026ff1ce9Sdinak } 20126ff1ce9Sdinak 20226ff1ce9Sdinak /* 20326ff1ce9Sdinak * Same as pkcs11_random_data but ensures non zero data. 20426ff1ce9Sdinak */ 20526ff1ce9Sdinak int 20626ff1ce9Sdinak pkcs11_nzero_random_data(void *dbuf, size_t dlen) 20726ff1ce9Sdinak { 20826ff1ce9Sdinak char extrarand[32]; 20926ff1ce9Sdinak size_t bytesleft = 0; 21026ff1ce9Sdinak size_t i = 0; 21126ff1ce9Sdinak 21226ff1ce9Sdinak /* Start with some random data */ 21326ff1ce9Sdinak if (pkcs11_random_data(dbuf, dlen) < 0) 21426ff1ce9Sdinak return (-1); 21526ff1ce9Sdinak 21626ff1ce9Sdinak /* Walk through data replacing any 0 bytes with more random data */ 21726ff1ce9Sdinak while (i < dlen) { 21826ff1ce9Sdinak if (((char *)dbuf)[i] != 0) { 21926ff1ce9Sdinak i++; 22026ff1ce9Sdinak continue; 22126ff1ce9Sdinak } 22226ff1ce9Sdinak 22326ff1ce9Sdinak if (bytesleft == 0) { 22426ff1ce9Sdinak bytesleft = sizeof (extrarand); 22526ff1ce9Sdinak if (pkcs11_random_data(extrarand, bytesleft) < 0) 22626ff1ce9Sdinak return (-1); 22726ff1ce9Sdinak } 22826ff1ce9Sdinak bytesleft--; 22926ff1ce9Sdinak 23026ff1ce9Sdinak ((char *)dbuf)[i] = extrarand[bytesleft]; 23126ff1ce9Sdinak } 23226ff1ce9Sdinak return (0); 2331c9bd843Sdinak } 234