xref: /titanic_52/usr/src/lib/libcryptoutil/common/random.c (revision 26ff1ce9e5494c59fafe62a0c6e3ca41cd0f2a99)
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