Branch data Line data Source code
1 : : /* crypto/rand/randfile.c */
2 : : /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 : : * All rights reserved.
4 : : *
5 : : * This package is an SSL implementation written
6 : : * by Eric Young (eay@cryptsoft.com).
7 : : * The implementation was written so as to conform with Netscapes SSL.
8 : : *
9 : : * This library is free for commercial and non-commercial use as long as
10 : : * the following conditions are aheared to. The following conditions
11 : : * apply to all code found in this distribution, be it the RC4, RSA,
12 : : * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13 : : * included with this distribution is covered by the same copyright terms
14 : : * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 : : *
16 : : * Copyright remains Eric Young's, and as such any Copyright notices in
17 : : * the code are not to be removed.
18 : : * If this package is used in a product, Eric Young should be given attribution
19 : : * as the author of the parts of the library used.
20 : : * This can be in the form of a textual message at program startup or
21 : : * in documentation (online or textual) provided with the package.
22 : : *
23 : : * Redistribution and use in source and binary forms, with or without
24 : : * modification, are permitted provided that the following conditions
25 : : * are met:
26 : : * 1. Redistributions of source code must retain the copyright
27 : : * notice, this list of conditions and the following disclaimer.
28 : : * 2. Redistributions in binary form must reproduce the above copyright
29 : : * notice, this list of conditions and the following disclaimer in the
30 : : * documentation and/or other materials provided with the distribution.
31 : : * 3. All advertising materials mentioning features or use of this software
32 : : * must display the following acknowledgement:
33 : : * "This product includes cryptographic software written by
34 : : * Eric Young (eay@cryptsoft.com)"
35 : : * The word 'cryptographic' can be left out if the rouines from the library
36 : : * being used are not cryptographic related :-).
37 : : * 4. If you include any Windows specific code (or a derivative thereof) from
38 : : * the apps directory (application code) you must include an acknowledgement:
39 : : * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 : : *
41 : : * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 : : * SUCH DAMAGE.
52 : : *
53 : : * The licence and distribution terms for any publically available version or
54 : : * derivative of this code cannot be changed. i.e. this code cannot simply be
55 : : * copied and put under another distribution licence
56 : : * [including the GNU Public Licence.]
57 : : */
58 : :
59 : : #include "e_os.h"
60 : :
61 : : /* We need to define this to get macros like S_IFBLK and S_IFCHR */
62 : : #if !defined(OPENSSL_SYS_VXWORKS)
63 : : #define _XOPEN_SOURCE 500
64 : : #endif
65 : :
66 : : #include <errno.h>
67 : : #include <stdio.h>
68 : : #include <stdlib.h>
69 : : #include <string.h>
70 : :
71 : : #include <openssl/crypto.h>
72 : : #include <openssl/rand.h>
73 : : #include <openssl/buffer.h>
74 : :
75 : : #ifdef OPENSSL_SYS_VMS
76 : : #include <unixio.h>
77 : : #endif
78 : : #ifndef NO_SYS_TYPES_H
79 : : # include <sys/types.h>
80 : : #endif
81 : : #ifndef OPENSSL_NO_POSIX_IO
82 : : # include <sys/stat.h>
83 : : # include <fcntl.h>
84 : : #endif
85 : :
86 : : #ifdef _WIN32
87 : : #define stat _stat
88 : : #define chmod _chmod
89 : : #define open _open
90 : : #define fdopen _fdopen
91 : : #endif
92 : :
93 : : #undef BUFSIZE
94 : : #define BUFSIZE 1024
95 : : #define RAND_DATA 1024
96 : :
97 : : #ifdef OPENSSL_SYS_VMS
98 : : /* This declaration is a nasty hack to get around vms' extension to fopen
99 : : * for passing in sharing options being disabled by our /STANDARD=ANSI89 */
100 : : static FILE *(*const vms_fopen)(const char *, const char *, ...) =
101 : : (FILE *(*)(const char *, const char *, ...))fopen;
102 : : #define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
103 : : #endif
104 : :
105 : : /* #define RFILE ".rnd" - defined in ../../e_os.h */
106 : :
107 : : /* Note that these functions are intended for seed files only.
108 : : * Entropy devices and EGD sockets are handled in rand_unix.c */
109 : :
110 : 83 : int RAND_load_file(const char *file, long bytes)
111 : : {
112 : : /* If bytes >= 0, read up to 'bytes' bytes.
113 : : * if bytes == -1, read complete file. */
114 : :
115 : : MS_STATIC unsigned char buf[BUFSIZE];
116 : : #ifndef OPENSSL_NO_POSIX_IO
117 : : struct stat sb;
118 : : #endif
119 : 83 : int i,ret=0,n;
120 : : FILE *in;
121 : :
122 [ + - ]: 83 : if (file == NULL) return(0);
123 : :
124 : : #ifndef OPENSSL_NO_POSIX_IO
125 : : #ifdef PURIFY
126 : : /* struct stat can have padding and unused fields that may not be
127 : : * initialized in the call to stat(). We need to clear the entire
128 : : * structure before calling RAND_add() to avoid complaints from
129 : : * applications such as Valgrind.
130 : : */
131 : : memset(&sb, 0, sizeof(sb));
132 : : #endif
133 [ + + ]: 83 : if (stat(file,&sb) < 0) return(0);
134 : 82 : RAND_add(&sb,sizeof(sb),0.0);
135 : : #endif
136 [ + - ]: 82 : if (bytes == 0) return(ret);
137 : :
138 : : #ifdef OPENSSL_SYS_VMS
139 : : in=vms_fopen(file,"rb",VMS_OPEN_ATTRS);
140 : : #else
141 : 82 : in=fopen(file,"rb");
142 : : #endif
143 [ + - ]: 82 : if (in == NULL) goto err;
144 : : #if defined(S_IFBLK) && defined(S_IFCHR) && !defined(OPENSSL_NO_POSIX_IO)
145 [ - + ]: 82 : if (sb.st_mode & (S_IFBLK | S_IFCHR)) {
146 : : /* this file is a device. we don't want read an infinite number
147 : : * of bytes from a random device, nor do we want to use buffered
148 : : * I/O because we will waste system entropy.
149 : : */
150 [ # # ]: 0 : bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
151 : : #ifndef OPENSSL_NO_SETVBUF_IONBF
152 : 171 : setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */
153 : : #endif /* ndef OPENSSL_NO_SETVBUF_IONBF */
154 : : }
155 : : #endif
156 : : for (;;)
157 : : {
158 [ - + ]: 171 : if (bytes > 0)
159 [ # # ]: 0 : n = (bytes < BUFSIZE)?(int)bytes:BUFSIZE;
160 : : else
161 : : n = BUFSIZE;
162 : 342 : i=fread(buf,1,n,in);
163 [ + + ]: 171 : if (i <= 0) break;
164 : : #ifdef PURIFY
165 : : RAND_add(buf,i,(double)i);
166 : : #else
167 : : /* even if n != i, use the full array */
168 : 89 : RAND_add(buf,n,(double)i);
169 : : #endif
170 : 89 : ret+=i;
171 [ + - ]: 89 : if (bytes > 0)
172 : : {
173 : 0 : bytes-=n;
174 [ # # ]: 0 : if (bytes <= 0) break;
175 : : }
176 : : }
177 : 82 : fclose(in);
178 : 82 : OPENSSL_cleanse(buf,BUFSIZE);
179 : : err:
180 : 82 : return(ret);
181 : : }
182 : :
183 : 83 : int RAND_write_file(const char *file)
184 : : {
185 : : unsigned char buf[BUFSIZE];
186 : 83 : int i,ret=0,rand_err=0;
187 : 83 : FILE *out = NULL;
188 : : int n;
189 : : #ifndef OPENSSL_NO_POSIX_IO
190 : : struct stat sb;
191 : :
192 : 83 : i=stat(file,&sb);
193 [ + + ]: 83 : if (i != -1) {
194 : : #if defined(S_ISBLK) && defined(S_ISCHR)
195 [ + - ]: 82 : if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
196 : : /* this file is a device. we don't write back to it.
197 : : * we "succeed" on the assumption this is some sort
198 : : * of random device. Otherwise attempting to write to
199 : : * and chmod the device causes problems.
200 : : */
201 : : return(1);
202 : : }
203 : : #endif
204 : : }
205 : : #endif
206 : :
207 : : #if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS)
208 : : {
209 : : #ifndef O_BINARY
210 : : #define O_BINARY 0
211 : : #endif
212 : : /* chmod(..., 0600) is too late to protect the file,
213 : : * permissions should be restrictive from the start */
214 : 83 : int fd = open(file, O_WRONLY|O_CREAT|O_BINARY, 0600);
215 [ + - ]: 83 : if (fd != -1)
216 : 83 : out = fdopen(fd, "wb");
217 : : }
218 : : #endif
219 : :
220 : : #ifdef OPENSSL_SYS_VMS
221 : : /* VMS NOTE: Prior versions of this routine created a _new_
222 : : * version of the rand file for each call into this routine, then
223 : : * deleted all existing versions named ;-1, and finally renamed
224 : : * the current version as ';1'. Under concurrent usage, this
225 : : * resulted in an RMS race condition in rename() which could
226 : : * orphan files (see vms message help for RMS$_REENT). With the
227 : : * fopen() calls below, openssl/VMS now shares the top-level
228 : : * version of the rand file. Note that there may still be
229 : : * conditions where the top-level rand file is locked. If so, this
230 : : * code will then create a new version of the rand file. Without
231 : : * the delete and rename code, this can result in ascending file
232 : : * versions that stop at version 32767, and this routine will then
233 : : * return an error. The remedy for this is to recode the calling
234 : : * application to avoid concurrent use of the rand file, or
235 : : * synchronize usage at the application level. Also consider
236 : : * whether or not you NEED a persistent rand file in a concurrent
237 : : * use situation.
238 : : */
239 : :
240 : : out = vms_fopen(file,"rb+",VMS_OPEN_ATTRS);
241 : : if (out == NULL)
242 : : out = vms_fopen(file,"wb",VMS_OPEN_ATTRS);
243 : : #else
244 [ - + ]: 83 : if (out == NULL)
245 : 0 : out = fopen(file,"wb");
246 : : #endif
247 [ + - ]: 83 : if (out == NULL) goto err;
248 : :
249 : : #ifndef NO_CHMOD
250 : 83 : chmod(file,0600);
251 : : #endif
252 : 83 : n=RAND_DATA;
253 : : for (;;)
254 : : {
255 : 83 : i=(n > BUFSIZE)?BUFSIZE:n;
256 : 83 : n-=BUFSIZE;
257 [ - + ]: 83 : if (RAND_bytes(buf,i) <= 0)
258 : 0 : rand_err=1;
259 : 83 : i=fwrite(buf,1,i,out);
260 [ + - ]: 83 : if (i <= 0)
261 : : {
262 : : ret=0;
263 : : break;
264 : : }
265 : 83 : ret+=i;
266 : : if (n <= 0) break;
267 : : }
268 : :
269 : 83 : fclose(out);
270 : 83 : OPENSSL_cleanse(buf,BUFSIZE);
271 : : err:
272 [ + - ]: 83 : return (rand_err ? -1 : ret);
273 : : }
274 : :
275 : 142 : const char *RAND_file_name(char *buf, size_t size)
276 : : {
277 : 142 : char *s=NULL;
278 : : #ifdef __OpenBSD__
279 : : struct stat sb;
280 : : #endif
281 : :
282 [ + - ]: 142 : if (OPENSSL_issetugid() == 0)
283 : 142 : s=getenv("RANDFILE");
284 [ - + ][ # # ]: 142 : if (s != NULL && *s && strlen(s) + 1 < size)
[ # # ]
285 : : {
286 [ # # ]: 0 : if (BUF_strlcpy(buf,s,size) >= size)
287 : : return NULL;
288 : : }
289 : : else
290 : : {
291 [ + - ]: 142 : if (OPENSSL_issetugid() == 0)
292 : 142 : s=getenv("HOME");
293 : : #ifdef DEFAULT_HOME
294 : : if (s == NULL)
295 : : {
296 : : s = DEFAULT_HOME;
297 : : }
298 : : #endif
299 [ + - ][ + - ]: 142 : if (s && *s && strlen(s)+strlen(RFILE)+2 < size)
[ + - ]
300 : : {
301 : 142 : BUF_strlcpy(buf,s,size);
302 : : #ifndef OPENSSL_SYS_VMS
303 : 142 : BUF_strlcat(buf,"/",size);
304 : : #endif
305 : 142 : BUF_strlcat(buf,RFILE,size);
306 : : }
307 : : else
308 : 0 : buf[0] = '\0'; /* no file name */
309 : : }
310 : :
311 : : #ifdef __OpenBSD__
312 : : /* given that all random loads just fail if the file can't be
313 : : * seen on a stat, we stat the file we're returning, if it
314 : : * fails, use /dev/arandom instead. this allows the user to
315 : : * use their own source for good random data, but defaults
316 : : * to something hopefully decent if that isn't available.
317 : : */
318 : :
319 : : if (!buf[0])
320 : : if (BUF_strlcpy(buf,"/dev/arandom",size) >= size) {
321 : : return(NULL);
322 : : }
323 : : if (stat(buf,&sb) == -1)
324 : : if (BUF_strlcpy(buf,"/dev/arandom",size) >= size) {
325 : : return(NULL);
326 : : }
327 : :
328 : : #endif
329 : 142 : return(buf);
330 : : }
|