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 */ 21*41cf421dSDina K Nimeh 221c9bd843Sdinak /* 23*41cf421dSDina K Nimeh * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 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> 3219193bb6SDina K Nimeh #include <stdarg.h> 331c9bd843Sdinak #include <cryptoutil.h> 3426ff1ce9Sdinak #include <pthread.h> 3526ff1ce9Sdinak 367b79d846SDina K Nimeh 3726ff1ce9Sdinak static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER; 3826ff1ce9Sdinak static pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER; 3926ff1ce9Sdinak 407b79d846SDina K Nimeh static pthread_mutex_t random_seed_mutex = PTHREAD_MUTEX_INITIALIZER; 417b79d846SDina K Nimeh static pthread_mutex_t urandom_seed_mutex = PTHREAD_MUTEX_INITIALIZER; 4226ff1ce9Sdinak 4326ff1ce9Sdinak #define RANDOM_DEVICE "/dev/random" /* random device name */ 4426ff1ce9Sdinak #define URANDOM_DEVICE "/dev/urandom" /* urandom device name */ 4526ff1ce9Sdinak 4626ff1ce9Sdinak static int random_fd = -1; 4726ff1ce9Sdinak static int urandom_fd = -1; 4826ff1ce9Sdinak 497b79d846SDina K Nimeh static int random_seed_fd = -1; 507b79d846SDina K Nimeh static int urandom_seed_fd = -1; 517b79d846SDina K Nimeh 527b79d846SDina K Nimeh 5326ff1ce9Sdinak /* 5426ff1ce9Sdinak * Equivalent of open(2) insulated from EINTR. 5526ff1ce9Sdinak * Also sets close-on-exec. 5626ff1ce9Sdinak */ 5719193bb6SDina K Nimeh int 5819193bb6SDina K Nimeh open_nointr(const char *path, int oflag, ...) 5926ff1ce9Sdinak { 6026ff1ce9Sdinak int fd; 6119193bb6SDina K Nimeh mode_t pmode; 6219193bb6SDina K Nimeh va_list alist; 6319193bb6SDina K Nimeh 6419193bb6SDina K Nimeh va_start(alist, oflag); 6519193bb6SDina K Nimeh pmode = va_arg(alist, mode_t); 6619193bb6SDina K Nimeh va_end(alist); 6726ff1ce9Sdinak 6826ff1ce9Sdinak do { 6919193bb6SDina K Nimeh if ((fd = open(path, oflag, pmode)) >= 0) { 7026ff1ce9Sdinak (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 7126ff1ce9Sdinak break; 7226ff1ce9Sdinak } 7326ff1ce9Sdinak /* errno definitely set by failed open() */ 7426ff1ce9Sdinak } while (errno == EINTR); 7526ff1ce9Sdinak return (fd); 7626ff1ce9Sdinak } 7726ff1ce9Sdinak 7826ff1ce9Sdinak /* 7926ff1ce9Sdinak * Equivalent of read(2) insulated from EINTR. 8026ff1ce9Sdinak */ 8119193bb6SDina K Nimeh ssize_t 8219193bb6SDina K Nimeh readn_nointr(int fd, void *dbuf, size_t dlen) 8326ff1ce9Sdinak { 8426ff1ce9Sdinak char *marker = dbuf; 8526ff1ce9Sdinak size_t left = dlen; 8626ff1ce9Sdinak ssize_t nread = 0, err; 8726ff1ce9Sdinak 8826ff1ce9Sdinak for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) { 8926ff1ce9Sdinak if ((nread = read(fd, marker, left)) < 0) { 9026ff1ce9Sdinak if (errno == EINTR) { /* keep trying */ 9126ff1ce9Sdinak nread = 0; 9226ff1ce9Sdinak continue; 9326ff1ce9Sdinak } 9426ff1ce9Sdinak err = nread; /* hard error */ 9526ff1ce9Sdinak break; 9619193bb6SDina K Nimeh } else if (nread == 0) { 9719193bb6SDina K Nimeh break; 9819193bb6SDina K Nimeh } 9919193bb6SDina K Nimeh } 10019193bb6SDina K Nimeh return (err != 0 ? err : dlen - left); 10119193bb6SDina K Nimeh } 10219193bb6SDina K Nimeh 10319193bb6SDina K Nimeh /* 10419193bb6SDina K Nimeh * Equivalent of write(2) insulated from EINTR. 10519193bb6SDina K Nimeh */ 10619193bb6SDina K Nimeh ssize_t 10719193bb6SDina K Nimeh writen_nointr(int fd, void *dbuf, size_t dlen) 10819193bb6SDina K Nimeh { 10919193bb6SDina K Nimeh char *marker = dbuf; 11019193bb6SDina K Nimeh size_t left = dlen; 11119193bb6SDina K Nimeh ssize_t nwrite = 0, err; 11219193bb6SDina K Nimeh 11319193bb6SDina K Nimeh for (err = 0; left > 0 && nwrite != -1; marker += nwrite, 11419193bb6SDina K Nimeh left -= nwrite) { 11519193bb6SDina K Nimeh if ((nwrite = write(fd, marker, left)) < 0) { 11619193bb6SDina K Nimeh if (errno == EINTR) { /* keep trying */ 11719193bb6SDina K Nimeh nwrite = 0; 11819193bb6SDina K Nimeh continue; 11919193bb6SDina K Nimeh } 12019193bb6SDina K Nimeh err = nwrite; /* hard error */ 12119193bb6SDina K Nimeh break; 12219193bb6SDina K Nimeh } else if (nwrite == 0) { 12319193bb6SDina K Nimeh break; 12426ff1ce9Sdinak } 12526ff1ce9Sdinak } 12626ff1ce9Sdinak return (err != 0 ? err : dlen - left); 12726ff1ce9Sdinak } 12826ff1ce9Sdinak 12926ff1ce9Sdinak /* 13026ff1ce9Sdinak * Opens the random number generator devices if not already open. 13126ff1ce9Sdinak * Always returns the opened fd of the device, or error. 13226ff1ce9Sdinak */ 1337b79d846SDina K Nimeh static int 1347b79d846SDina K Nimeh pkcs11_open_common(int *fd, pthread_mutex_t *mtx, const char *dev, int oflag) 13526ff1ce9Sdinak { 1367b79d846SDina K Nimeh (void) pthread_mutex_lock(mtx); 1377b79d846SDina K Nimeh if (*fd < 0) 1387b79d846SDina K Nimeh *fd = open_nointr(dev, oflag); 1397b79d846SDina K Nimeh (void) pthread_mutex_unlock(mtx); 140*41cf421dSDina K Nimeh 1417b79d846SDina K Nimeh return (*fd); 14226ff1ce9Sdinak } 14326ff1ce9Sdinak 1447b79d846SDina K Nimeh static int 1457b79d846SDina K Nimeh pkcs11_open_random(void) 1467b79d846SDina K Nimeh { 1477b79d846SDina K Nimeh return (pkcs11_open_common(&random_fd, &random_mutex, 1487b79d846SDina K Nimeh RANDOM_DEVICE, O_RDONLY)); 1497b79d846SDina K Nimeh } 1507b79d846SDina K Nimeh 1517b79d846SDina K Nimeh static int 15226ff1ce9Sdinak pkcs11_open_urandom(void) 15326ff1ce9Sdinak { 1547b79d846SDina K Nimeh return (pkcs11_open_common(&urandom_fd, &urandom_mutex, 1557b79d846SDina K Nimeh URANDOM_DEVICE, O_RDONLY)); 1567b79d846SDina K Nimeh } 1577b79d846SDina K Nimeh 1587b79d846SDina K Nimeh static int 1597b79d846SDina K Nimeh pkcs11_open_random_seed(void) 1607b79d846SDina K Nimeh { 1617b79d846SDina K Nimeh return (pkcs11_open_common(&random_seed_fd, &random_seed_mutex, 1627b79d846SDina K Nimeh RANDOM_DEVICE, O_WRONLY)); 1637b79d846SDina K Nimeh } 1647b79d846SDina K Nimeh 1657b79d846SDina K Nimeh static int 1667b79d846SDina K Nimeh pkcs11_open_urandom_seed(void) 1677b79d846SDina K Nimeh { 1687b79d846SDina K Nimeh return (pkcs11_open_common(&urandom_seed_fd, &urandom_seed_mutex, 1697b79d846SDina K Nimeh URANDOM_DEVICE, O_WRONLY)); 17026ff1ce9Sdinak } 17126ff1ce9Sdinak 17226ff1ce9Sdinak /* 17326ff1ce9Sdinak * Close the random number generator devices if already open. 17426ff1ce9Sdinak */ 1757b79d846SDina K Nimeh static void 1767b79d846SDina K Nimeh pkcs11_close_common(int *fd, pthread_mutex_t *mtx) 1777b79d846SDina K Nimeh { 1787b79d846SDina K Nimeh (void) pthread_mutex_lock(mtx); 1797b79d846SDina K Nimeh (void) close(*fd); 1807b79d846SDina K Nimeh *fd = -1; 1817b79d846SDina K Nimeh (void) pthread_mutex_unlock(mtx); 1827b79d846SDina K Nimeh } 1837b79d846SDina K Nimeh 18426ff1ce9Sdinak void 18526ff1ce9Sdinak pkcs11_close_random(void) 18626ff1ce9Sdinak { 1877b79d846SDina K Nimeh pkcs11_close_common(&random_fd, &random_mutex); 18826ff1ce9Sdinak } 18926ff1ce9Sdinak 19026ff1ce9Sdinak void 19126ff1ce9Sdinak pkcs11_close_urandom(void) 19226ff1ce9Sdinak { 1937b79d846SDina K Nimeh pkcs11_close_common(&urandom_fd, &urandom_mutex); 1947b79d846SDina K Nimeh } 1957b79d846SDina K Nimeh 1967b79d846SDina K Nimeh static void 1977b79d846SDina K Nimeh pkcs11_close_random_seed(void) 1987b79d846SDina K Nimeh { 1997b79d846SDina K Nimeh pkcs11_close_common(&random_seed_fd, &random_seed_mutex); 2007b79d846SDina K Nimeh } 2017b79d846SDina K Nimeh 2027b79d846SDina K Nimeh void 2037b79d846SDina K Nimeh pkcs11_close_urandom_seed(void) 2047b79d846SDina K Nimeh { 2057b79d846SDina K Nimeh pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex); 2067b79d846SDina K Nimeh } 2077b79d846SDina K Nimeh 2087b79d846SDina K Nimeh /* 209*41cf421dSDina K Nimeh * Read from the random number generator devices. 210*41cf421dSDina K Nimeh */ 211*41cf421dSDina K Nimeh static size_t 212*41cf421dSDina K Nimeh pkcs11_read_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen) 213*41cf421dSDina K Nimeh { 214*41cf421dSDina K Nimeh size_t n; 215*41cf421dSDina K Nimeh 216*41cf421dSDina K Nimeh (void) pthread_mutex_lock(mtx); 217*41cf421dSDina K Nimeh n = readn_nointr(*fd, dbuf, dlen); 218*41cf421dSDina K Nimeh (void) pthread_mutex_unlock(mtx); 219*41cf421dSDina K Nimeh 220*41cf421dSDina K Nimeh return (n); 221*41cf421dSDina K Nimeh } 222*41cf421dSDina K Nimeh 223*41cf421dSDina K Nimeh static size_t 224*41cf421dSDina K Nimeh pkcs11_read_random(void *dbuf, size_t dlen) 225*41cf421dSDina K Nimeh { 226*41cf421dSDina K Nimeh return (pkcs11_read_common(&random_fd, &random_mutex, dbuf, dlen)); 227*41cf421dSDina K Nimeh } 228*41cf421dSDina K Nimeh 229*41cf421dSDina K Nimeh static size_t 230*41cf421dSDina K Nimeh pkcs11_read_urandom(void *dbuf, size_t dlen) 231*41cf421dSDina K Nimeh { 232*41cf421dSDina K Nimeh return (pkcs11_read_common(&urandom_fd, &urandom_mutex, dbuf, dlen)); 233*41cf421dSDina K Nimeh } 234*41cf421dSDina K Nimeh 235*41cf421dSDina K Nimeh /* 236*41cf421dSDina K Nimeh * Write to the random number generator devices. 237*41cf421dSDina K Nimeh */ 238*41cf421dSDina K Nimeh static size_t 239*41cf421dSDina K Nimeh pkcs11_write_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen) 240*41cf421dSDina K Nimeh { 241*41cf421dSDina K Nimeh size_t n; 242*41cf421dSDina K Nimeh 243*41cf421dSDina K Nimeh (void) pthread_mutex_lock(mtx); 244*41cf421dSDina K Nimeh n = writen_nointr(*fd, dbuf, dlen); 245*41cf421dSDina K Nimeh (void) pthread_mutex_unlock(mtx); 246*41cf421dSDina K Nimeh 247*41cf421dSDina K Nimeh return (n); 248*41cf421dSDina K Nimeh } 249*41cf421dSDina K Nimeh 250*41cf421dSDina K Nimeh static size_t 251*41cf421dSDina K Nimeh pkcs11_write_random_seed(void *dbuf, size_t dlen) 252*41cf421dSDina K Nimeh { 253*41cf421dSDina K Nimeh return (pkcs11_write_common(&random_seed_fd, &random_seed_mutex, 254*41cf421dSDina K Nimeh dbuf, dlen)); 255*41cf421dSDina K Nimeh } 256*41cf421dSDina K Nimeh 257*41cf421dSDina K Nimeh static size_t 258*41cf421dSDina K Nimeh pkcs11_write_urandom_seed(void *dbuf, size_t dlen) 259*41cf421dSDina K Nimeh { 260*41cf421dSDina K Nimeh return (pkcs11_write_common(&urandom_seed_fd, &urandom_seed_mutex, 261*41cf421dSDina K Nimeh dbuf, dlen)); 262*41cf421dSDina K Nimeh } 263*41cf421dSDina K Nimeh 264*41cf421dSDina K Nimeh /* 2657b79d846SDina K Nimeh * Seed /dev/random with the data in the buffer. 2667b79d846SDina K Nimeh */ 2677b79d846SDina K Nimeh int 2687b79d846SDina K Nimeh pkcs11_seed_random(void *sbuf, size_t slen) 2697b79d846SDina K Nimeh { 270*41cf421dSDina K Nimeh int rv; 271*41cf421dSDina K Nimeh 2727b79d846SDina K Nimeh if (sbuf == NULL || slen == 0) 2737b79d846SDina K Nimeh return (0); 2747b79d846SDina K Nimeh 2757b79d846SDina K Nimeh /* Seeding error could mean it's not supported (errno = EACCES) */ 2767b79d846SDina K Nimeh if (pkcs11_open_random_seed() < 0) 2777b79d846SDina K Nimeh return (-1); 2787b79d846SDina K Nimeh 279*41cf421dSDina K Nimeh rv = -1; 280*41cf421dSDina K Nimeh if (pkcs11_write_random_seed(sbuf, slen) == slen) 281*41cf421dSDina K Nimeh rv = 0; 282*41cf421dSDina K Nimeh 2837b79d846SDina K Nimeh pkcs11_close_random_seed(); 284*41cf421dSDina K Nimeh return (rv); 2857b79d846SDina K Nimeh } 2867b79d846SDina K Nimeh 2877b79d846SDina K Nimeh /* 2887b79d846SDina K Nimeh * Seed /dev/urandom with the data in the buffer. 2897b79d846SDina K Nimeh */ 2907b79d846SDina K Nimeh int 2917b79d846SDina K Nimeh pkcs11_seed_urandom(void *sbuf, size_t slen) 2927b79d846SDina K Nimeh { 293*41cf421dSDina K Nimeh int rv; 294*41cf421dSDina K Nimeh 2957b79d846SDina K Nimeh if (sbuf == NULL || slen == 0) 2967b79d846SDina K Nimeh return (0); 2977b79d846SDina K Nimeh 2987b79d846SDina K Nimeh /* Seeding error could mean it's not supported (errno = EACCES) */ 2997b79d846SDina K Nimeh if (pkcs11_open_urandom_seed() < 0) 3007b79d846SDina K Nimeh return (-1); 3017b79d846SDina K Nimeh 302*41cf421dSDina K Nimeh rv = -1; 303*41cf421dSDina K Nimeh if (pkcs11_write_urandom_seed(sbuf, slen) == slen) 304*41cf421dSDina K Nimeh rv = 0; 305*41cf421dSDina K Nimeh 3067b79d846SDina K Nimeh pkcs11_close_urandom_seed(); 307*41cf421dSDina K Nimeh return (rv); 3087b79d846SDina K Nimeh } 3097b79d846SDina K Nimeh 3107b79d846SDina K Nimeh /* 3117b79d846SDina K Nimeh * Put the requested amount of random data into a preallocated buffer. 3127b79d846SDina K Nimeh * Good for token key data, persistent objects. 3137b79d846SDina K Nimeh */ 3147b79d846SDina K Nimeh int 3157b79d846SDina K Nimeh pkcs11_get_random(void *dbuf, size_t dlen) 3167b79d846SDina K Nimeh { 3177b79d846SDina K Nimeh if (dbuf == NULL || dlen == 0) 3187b79d846SDina K Nimeh return (0); 3197b79d846SDina K Nimeh 3207b79d846SDina K Nimeh /* Read random data directly from /dev/random */ 3217b79d846SDina K Nimeh if (pkcs11_open_random() < 0) 3227b79d846SDina K Nimeh return (-1); 3237b79d846SDina K Nimeh 324*41cf421dSDina K Nimeh if (pkcs11_read_random(dbuf, dlen) == dlen) 3257b79d846SDina K Nimeh return (0); 3267b79d846SDina K Nimeh return (-1); 32726ff1ce9Sdinak } 3281c9bd843Sdinak 3291c9bd843Sdinak /* 3301c9bd843Sdinak * Put the requested amount of random data into a preallocated buffer. 3311c9bd843Sdinak * Good for passphrase salts, initialization vectors. 3321c9bd843Sdinak */ 3331c9bd843Sdinak int 3347b79d846SDina K Nimeh pkcs11_get_urandom(void *dbuf, size_t dlen) 3351c9bd843Sdinak { 3361c9bd843Sdinak if (dbuf == NULL || dlen == 0) 3371c9bd843Sdinak return (0); 3381c9bd843Sdinak 3391c9bd843Sdinak /* Read random data directly from /dev/urandom */ 34026ff1ce9Sdinak if (pkcs11_open_urandom() < 0) 3411c9bd843Sdinak return (-1); 34226ff1ce9Sdinak 343*41cf421dSDina K Nimeh if (pkcs11_read_urandom(dbuf, dlen) == dlen) 34426ff1ce9Sdinak return (0); 34526ff1ce9Sdinak return (-1); 34626ff1ce9Sdinak } 34726ff1ce9Sdinak 34826ff1ce9Sdinak /* 3497b79d846SDina K Nimeh * Same as pkcs11_get_urandom but ensures non zero data. 35026ff1ce9Sdinak */ 35126ff1ce9Sdinak int 3527b79d846SDina K Nimeh pkcs11_get_nzero_urandom(void *dbuf, size_t dlen) 35326ff1ce9Sdinak { 35426ff1ce9Sdinak char extrarand[32]; 35526ff1ce9Sdinak size_t bytesleft = 0; 35626ff1ce9Sdinak size_t i = 0; 35726ff1ce9Sdinak 35826ff1ce9Sdinak /* Start with some random data */ 3597b79d846SDina K Nimeh if (pkcs11_get_urandom(dbuf, dlen) < 0) 36026ff1ce9Sdinak return (-1); 36126ff1ce9Sdinak 36226ff1ce9Sdinak /* Walk through data replacing any 0 bytes with more random data */ 36326ff1ce9Sdinak while (i < dlen) { 36426ff1ce9Sdinak if (((char *)dbuf)[i] != 0) { 36526ff1ce9Sdinak i++; 36626ff1ce9Sdinak continue; 36726ff1ce9Sdinak } 36826ff1ce9Sdinak 36926ff1ce9Sdinak if (bytesleft == 0) { 37026ff1ce9Sdinak bytesleft = sizeof (extrarand); 3717b79d846SDina K Nimeh if (pkcs11_get_urandom(extrarand, bytesleft) < 0) 37226ff1ce9Sdinak return (-1); 37326ff1ce9Sdinak } 37426ff1ce9Sdinak bytesleft--; 37526ff1ce9Sdinak 37626ff1ce9Sdinak ((char *)dbuf)[i] = extrarand[bytesleft]; 37726ff1ce9Sdinak } 37826ff1ce9Sdinak return (0); 3791c9bd843Sdinak } 380