1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <locale.h>
32 #include <stdarg.h>
33 #include <cryptoutil.h>
34 #include <pthread.h>
35
36
37 static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER;
38 static pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER;
39
40 static pthread_mutex_t random_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
41 static pthread_mutex_t urandom_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
42
43 #define RANDOM_DEVICE "/dev/random" /* random device name */
44 #define URANDOM_DEVICE "/dev/urandom" /* urandom device name */
45
46 static int random_fd = -1;
47 static int urandom_fd = -1;
48
49 static int random_seed_fd = -1;
50 static int urandom_seed_fd = -1;
51
52
53 /*
54 * Equivalent of open(2) insulated from EINTR.
55 * Also sets close-on-exec.
56 */
57 int
open_nointr(const char * path,int oflag,...)58 open_nointr(const char *path, int oflag, ...)
59 {
60 int fd;
61 mode_t pmode;
62 va_list alist;
63
64 va_start(alist, oflag);
65 pmode = va_arg(alist, mode_t);
66 va_end(alist);
67
68 do {
69 if ((fd = open(path, oflag, pmode)) >= 0) {
70 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
71 break;
72 }
73 /* errno definitely set by failed open() */
74 } while (errno == EINTR);
75 return (fd);
76 }
77
78 /*
79 * Equivalent of read(2) insulated from EINTR.
80 */
81 ssize_t
readn_nointr(int fd,void * dbuf,size_t dlen)82 readn_nointr(int fd, void *dbuf, size_t dlen)
83 {
84 char *marker = dbuf;
85 size_t left = dlen;
86 ssize_t nread = 0, err;
87
88 for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) {
89 if ((nread = read(fd, marker, left)) < 0) {
90 if (errno == EINTR) { /* keep trying */
91 nread = 0;
92 continue;
93 }
94 err = nread; /* hard error */
95 break;
96 } else if (nread == 0) {
97 break;
98 }
99 }
100 return (err != 0 ? err : dlen - left);
101 }
102
103 /*
104 * Equivalent of write(2) insulated from EINTR.
105 */
106 ssize_t
writen_nointr(int fd,void * dbuf,size_t dlen)107 writen_nointr(int fd, void *dbuf, size_t dlen)
108 {
109 char *marker = dbuf;
110 size_t left = dlen;
111 ssize_t nwrite = 0, err;
112
113 for (err = 0; left > 0 && nwrite != -1; marker += nwrite,
114 left -= nwrite) {
115 if ((nwrite = write(fd, marker, left)) < 0) {
116 if (errno == EINTR) { /* keep trying */
117 nwrite = 0;
118 continue;
119 }
120 err = nwrite; /* hard error */
121 break;
122 } else if (nwrite == 0) {
123 break;
124 }
125 }
126 return (err != 0 ? err : dlen - left);
127 }
128
129 /*
130 * Opens the random number generator devices if not already open.
131 * Always returns the opened fd of the device, or error.
132 */
133 static int
pkcs11_open_common(int * fd,pthread_mutex_t * mtx,const char * dev,int oflag)134 pkcs11_open_common(int *fd, pthread_mutex_t *mtx, const char *dev, int oflag)
135 {
136 (void) pthread_mutex_lock(mtx);
137 if (*fd < 0)
138 *fd = open_nointr(dev, oflag);
139 (void) pthread_mutex_unlock(mtx);
140
141 return (*fd);
142 }
143
144 static int
pkcs11_open_random(void)145 pkcs11_open_random(void)
146 {
147 return (pkcs11_open_common(&random_fd, &random_mutex,
148 RANDOM_DEVICE, O_RDONLY));
149 }
150
151 static int
pkcs11_open_urandom(void)152 pkcs11_open_urandom(void)
153 {
154 return (pkcs11_open_common(&urandom_fd, &urandom_mutex,
155 URANDOM_DEVICE, O_RDONLY));
156 }
157
158 static int
pkcs11_open_random_seed(void)159 pkcs11_open_random_seed(void)
160 {
161 return (pkcs11_open_common(&random_seed_fd, &random_seed_mutex,
162 RANDOM_DEVICE, O_WRONLY));
163 }
164
165 static int
pkcs11_open_urandom_seed(void)166 pkcs11_open_urandom_seed(void)
167 {
168 return (pkcs11_open_common(&urandom_seed_fd, &urandom_seed_mutex,
169 URANDOM_DEVICE, O_WRONLY));
170 }
171
172 /*
173 * Close the random number generator devices if already open.
174 */
175 static void
pkcs11_close_common(int * fd,pthread_mutex_t * mtx)176 pkcs11_close_common(int *fd, pthread_mutex_t *mtx)
177 {
178 (void) pthread_mutex_lock(mtx);
179 (void) close(*fd);
180 *fd = -1;
181 (void) pthread_mutex_unlock(mtx);
182 }
183
184 void
pkcs11_close_random(void)185 pkcs11_close_random(void)
186 {
187 pkcs11_close_common(&random_fd, &random_mutex);
188 }
189
190 void
pkcs11_close_urandom(void)191 pkcs11_close_urandom(void)
192 {
193 pkcs11_close_common(&urandom_fd, &urandom_mutex);
194 }
195
196 static void
pkcs11_close_random_seed(void)197 pkcs11_close_random_seed(void)
198 {
199 pkcs11_close_common(&random_seed_fd, &random_seed_mutex);
200 }
201
202 void
pkcs11_close_urandom_seed(void)203 pkcs11_close_urandom_seed(void)
204 {
205 pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex);
206 }
207
208 /*
209 * Read from the random number generator devices.
210 */
211 static size_t
pkcs11_read_common(int * fd,pthread_mutex_t * mtx,void * dbuf,size_t dlen)212 pkcs11_read_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
213 {
214 size_t n;
215
216 (void) pthread_mutex_lock(mtx);
217 n = readn_nointr(*fd, dbuf, dlen);
218 (void) pthread_mutex_unlock(mtx);
219
220 return (n);
221 }
222
223 static size_t
pkcs11_read_random(void * dbuf,size_t dlen)224 pkcs11_read_random(void *dbuf, size_t dlen)
225 {
226 return (pkcs11_read_common(&random_fd, &random_mutex, dbuf, dlen));
227 }
228
229 static size_t
pkcs11_read_urandom(void * dbuf,size_t dlen)230 pkcs11_read_urandom(void *dbuf, size_t dlen)
231 {
232 return (pkcs11_read_common(&urandom_fd, &urandom_mutex, dbuf, dlen));
233 }
234
235 /*
236 * Write to the random number generator devices.
237 */
238 static size_t
pkcs11_write_common(int * fd,pthread_mutex_t * mtx,void * dbuf,size_t dlen)239 pkcs11_write_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
240 {
241 size_t n;
242
243 (void) pthread_mutex_lock(mtx);
244 n = writen_nointr(*fd, dbuf, dlen);
245 (void) pthread_mutex_unlock(mtx);
246
247 return (n);
248 }
249
250 static size_t
pkcs11_write_random_seed(void * dbuf,size_t dlen)251 pkcs11_write_random_seed(void *dbuf, size_t dlen)
252 {
253 return (pkcs11_write_common(&random_seed_fd, &random_seed_mutex,
254 dbuf, dlen));
255 }
256
257 static size_t
pkcs11_write_urandom_seed(void * dbuf,size_t dlen)258 pkcs11_write_urandom_seed(void *dbuf, size_t dlen)
259 {
260 return (pkcs11_write_common(&urandom_seed_fd, &urandom_seed_mutex,
261 dbuf, dlen));
262 }
263
264 /*
265 * Seed /dev/random with the data in the buffer.
266 */
267 int
pkcs11_seed_random(void * sbuf,size_t slen)268 pkcs11_seed_random(void *sbuf, size_t slen)
269 {
270 int rv;
271
272 if (sbuf == NULL || slen == 0)
273 return (0);
274
275 /* Seeding error could mean it's not supported (errno = EACCES) */
276 if (pkcs11_open_random_seed() < 0)
277 return (-1);
278
279 rv = -1;
280 if (pkcs11_write_random_seed(sbuf, slen) == slen)
281 rv = 0;
282
283 pkcs11_close_random_seed();
284 return (rv);
285 }
286
287 /*
288 * Seed /dev/urandom with the data in the buffer.
289 */
290 int
pkcs11_seed_urandom(void * sbuf,size_t slen)291 pkcs11_seed_urandom(void *sbuf, size_t slen)
292 {
293 int rv;
294
295 if (sbuf == NULL || slen == 0)
296 return (0);
297
298 /* Seeding error could mean it's not supported (errno = EACCES) */
299 if (pkcs11_open_urandom_seed() < 0)
300 return (-1);
301
302 rv = -1;
303 if (pkcs11_write_urandom_seed(sbuf, slen) == slen)
304 rv = 0;
305
306 pkcs11_close_urandom_seed();
307 return (rv);
308 }
309
310 /*
311 * Put the requested amount of random data into a preallocated buffer.
312 * Good for token key data, persistent objects.
313 */
314 int
pkcs11_get_random(void * dbuf,size_t dlen)315 pkcs11_get_random(void *dbuf, size_t dlen)
316 {
317 if (dbuf == NULL || dlen == 0)
318 return (0);
319
320 /* Read random data directly from /dev/random */
321 if (pkcs11_open_random() < 0)
322 return (-1);
323
324 if (pkcs11_read_random(dbuf, dlen) == dlen)
325 return (0);
326 return (-1);
327 }
328
329 /*
330 * Put the requested amount of random data into a preallocated buffer.
331 * Good for passphrase salts, initialization vectors.
332 */
333 int
pkcs11_get_urandom(void * dbuf,size_t dlen)334 pkcs11_get_urandom(void *dbuf, size_t dlen)
335 {
336 if (dbuf == NULL || dlen == 0)
337 return (0);
338
339 /* Read random data directly from /dev/urandom */
340 if (pkcs11_open_urandom() < 0)
341 return (-1);
342
343 if (pkcs11_read_urandom(dbuf, dlen) == dlen)
344 return (0);
345 return (-1);
346 }
347
348 /*
349 * Same as pkcs11_get_urandom but ensures non zero data.
350 */
351 int
pkcs11_get_nzero_urandom(void * dbuf,size_t dlen)352 pkcs11_get_nzero_urandom(void *dbuf, size_t dlen)
353 {
354 char extrarand[32];
355 size_t bytesleft = 0;
356 size_t i = 0;
357
358 /* Start with some random data */
359 if (pkcs11_get_urandom(dbuf, dlen) < 0)
360 return (-1);
361
362 /* Walk through data replacing any 0 bytes with more random data */
363 while (i < dlen) {
364 if (((char *)dbuf)[i] != 0) {
365 i++;
366 continue;
367 }
368
369 if (bytesleft == 0) {
370 bytesleft = sizeof (extrarand);
371 if (pkcs11_get_urandom(extrarand, bytesleft) < 0)
372 return (-1);
373 }
374 bytesleft--;
375
376 ((char *)dbuf)[i] = extrarand[bytesleft];
377 }
378 return (0);
379 }
380