random.c revision 19193bb63b10fe65b6e01f1ce7232407a18a917a
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * CDDL HEADER START
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi *
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * The contents of this file are subject to the terms of the
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Common Development and Distribution License (the "License").
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * You may not use this file except in compliance with the License.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi *
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * or http://www.opensolaris.org/os/licensing.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * See the License for the specific language governing permissions
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * and limitations under the License.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi *
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * When distributing Covered Code, include this CDDL HEADER in each
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * If applicable, add the following below this CDDL HEADER, with the
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * fields enclosed by brackets "[]" replaced with your own identifying
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * information: Portions Copyright [yyyy] [name of copyright owner]
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi *
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * CDDL HEADER END
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Use is subject to license terms.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <stdio.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <unistd.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <errno.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <string.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <fcntl.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <locale.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <stdarg.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <cryptoutil.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#ifdef _REENTRANT
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#include <pthread.h>
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchistatic pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchistatic pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#define RAND_LOCK(x) (void) pthread_mutex_lock(x)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#define RAND_UNLOCK(x) (void) pthread_mutex_unlock(x)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#else
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#define RAND_LOCK(x)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#define RAND_UNLOCK(x)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#endif
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#define RANDOM_DEVICE "/dev/random" /* random device name */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi#define URANDOM_DEVICE "/dev/urandom" /* urandom device name */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchistatic int random_fd = -1;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchistatic int urandom_fd = -1;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Equivalent of open(2) insulated from EINTR.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Also sets close-on-exec.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchiint
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchiopen_nointr(const char *path, int oflag, ...)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi int fd;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi mode_t pmode;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi va_list alist;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi va_start(alist, oflag);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi pmode = va_arg(alist, mode_t);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi va_end(alist);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi do {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if ((fd = open(path, oflag, pmode)) >= 0) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi break;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi /* errno definitely set by failed open() */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi } while (errno == EINTR);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (fd);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Equivalent of read(2) insulated from EINTR.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchissize_t
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchireadn_nointr(int fd, void *dbuf, size_t dlen)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi char *marker = dbuf;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi size_t left = dlen;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi ssize_t nread = 0, err;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if ((nread = read(fd, marker, left)) < 0) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (errno == EINTR) { /* keep trying */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi nread = 0;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi continue;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi err = nread; /* hard error */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi break;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi } else if (nread == 0) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi break;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (err != 0 ? err : dlen - left);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Equivalent of write(2) insulated from EINTR.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchissize_t
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchiwriten_nointr(int fd, void *dbuf, size_t dlen)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi char *marker = dbuf;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi size_t left = dlen;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi ssize_t nwrite = 0, err;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi for (err = 0; left > 0 && nwrite != -1; marker += nwrite,
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi left -= nwrite) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if ((nwrite = write(fd, marker, left)) < 0) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (errno == EINTR) { /* keep trying */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi nwrite = 0;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi continue;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi err = nwrite; /* hard error */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi break;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi } else if (nwrite == 0) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi break;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (err != 0 ? err : dlen - left);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Opens the random number generator devices if not already open.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Always returns the opened fd of the device, or error.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchiint
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchipkcs11_open_random(void)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_LOCK(&random_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (random_fd < 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi random_fd = open_nointr(RANDOM_DEVICE, O_RDONLY);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_UNLOCK(&random_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (random_fd);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchiint
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchipkcs11_open_urandom(void)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_LOCK(&urandom_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (urandom_fd < 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi urandom_fd = open_nointr(URANDOM_DEVICE, O_RDONLY);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_UNLOCK(&urandom_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (urandom_fd);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Close the random number generator devices if already open.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchivoid
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchipkcs11_close_random(void)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (random_fd < 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_LOCK(&random_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi (void) close(random_fd);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi random_fd = -1;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_UNLOCK(&random_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchivoid
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchipkcs11_close_urandom(void)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (urandom_fd < 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_LOCK(&urandom_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi (void) close(urandom_fd);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi urandom_fd = -1;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi RAND_UNLOCK(&urandom_mutex);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Put the requested amount of random data into a preallocated buffer.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Good for passphrase salts, initialization vectors.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchiint
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchipkcs11_random_data(void *dbuf, size_t dlen)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (dbuf == NULL || dlen == 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (0);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi /* Read random data directly from /dev/urandom */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (pkcs11_open_urandom() < 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (-1);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (readn_nointr(urandom_fd, dbuf, dlen) == dlen)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (0);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (-1);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi/*
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi * Same as pkcs11_random_data but ensures non zero data.
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchiint
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchipkcs11_nzero_random_data(void *dbuf, size_t dlen)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi{
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi char extrarand[32];
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi size_t bytesleft = 0;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi size_t i = 0;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi /* Start with some random data */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (pkcs11_random_data(dbuf, dlen) < 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (-1);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi /* Walk through data replacing any 0 bytes with more random data */
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi while (i < dlen) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (((char *)dbuf)[i] != 0) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi i++;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi continue;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (bytesleft == 0) {
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi bytesleft = sizeof (extrarand);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi if (pkcs11_random_data(extrarand, bytesleft) < 0)
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (-1);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi bytesleft--;
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi ((char *)dbuf)[i] = extrarand[bytesleft];
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi }
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi return (0);
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi}
d14abf155341d55053c76eeec58b787a456b753bRobert Mustacchi