1b091e848c61bbbff549b66ccfa19326f108edc7
[openssl.git] / crypto / rand / rand_egd.c
1 /*
2  * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <openssl/opensslconf.h>
11 #ifdef OPENSSL_NO_EGD
12 NON_EMPTY_TRANSLATION_UNIT
13 #else
14
15 # include <openssl/crypto.h>
16 # include <openssl/e_os2.h>
17 # include <openssl/rand.h>
18
19 /*-
20  * Query the EGD <URL: http://www.lothar.com/tech/crypto/>.
21  *
22  * This module supplies three routines:
23  *
24  * RAND_query_egd_bytes(path, buf, bytes)
25  *   will actually query "bytes" bytes of entropy form the egd-socket located
26  *   at path and will write them to buf (if supplied) or will directly feed
27  *   it to RAND_seed() if buf==NULL.
28  *   The number of bytes is not limited by the maximum chunk size of EGD,
29  *   which is 255 bytes. If more than 255 bytes are wanted, several chunks
30  *   of entropy bytes are requested. The connection is left open until the
31  *   query is competed.
32  *   RAND_query_egd_bytes() returns with
33  *     -1  if an error occurred during connection or communication.
34  *     num the number of bytes read from the EGD socket. This number is either
35  *         the number of bytes requested or smaller, if the EGD pool is
36  *         drained and the daemon signals that the pool is empty.
37  *   This routine does not touch any RAND_status(). This is necessary, since
38  *   PRNG functions may call it during initialization.
39  *
40  * RAND_egd_bytes(path, bytes) will query "bytes" bytes and have them
41  *   used to seed the PRNG.
42  *   RAND_egd_bytes() is a wrapper for RAND_query_egd_bytes() with buf=NULL.
43  *   Unlike RAND_query_egd_bytes(), RAND_status() is used to test the
44  *   seed status so that the return value can reflect the seed state:
45  *     -1  if an error occurred during connection or communication _or_
46  *         if the PRNG has still not received the required seeding.
47  *     num the number of bytes read from the EGD socket. This number is either
48  *         the number of bytes requested or smaller, if the EGD pool is
49  *         drained and the daemon signals that the pool is empty.
50  *
51  * RAND_egd(path) will query 255 bytes and use the bytes retrieved to seed
52  *   the PRNG.
53  *   RAND_egd() is a wrapper for RAND_egd_bytes() with numbytes=255.
54  */
55
56 # if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_VOS) || defined(OPENSSL_SYS_UEFI)
57 int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
58 {
59     return -1;
60 }
61
62 int RAND_egd(const char *path)
63 {
64     return -1;
65 }
66
67 int RAND_egd_bytes(const char *path, int bytes)
68 {
69     return -1;
70 }
71 # else
72 #  include <openssl/opensslconf.h>
73 #  include OPENSSL_UNISTD
74 #  include <stddef.h>
75 #  include <sys/types.h>
76 #  include <sys/socket.h>
77 #  ifndef NO_SYS_UN_H
78 #   ifdef OPENSSL_SYS_VXWORKS
79 #    include <streams/un.h>
80 #   else
81 #    include <sys/un.h>
82 #   endif
83 #  else
84 struct sockaddr_un {
85     short sun_family;           /* AF_UNIX */
86     char sun_path[108];         /* path name (gag) */
87 };
88 #  endif                         /* NO_SYS_UN_H */
89 #  include <string.h>
90 #  include <errno.h>
91
92 int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
93 {
94     int ret = 0;
95     struct sockaddr_un addr;
96     int len, num, numbytes;
97     int fd = -1;
98     int success;
99     unsigned char egdbuf[2], tempbuf[255], *retrievebuf;
100
101     memset(&addr, 0, sizeof(addr));
102     addr.sun_family = AF_UNIX;
103     if (strlen(path) >= sizeof(addr.sun_path))
104         return -1;
105     strcpy(addr.sun_path, path);
106     len = offsetof(struct sockaddr_un, sun_path) + strlen(path);
107     fd = socket(AF_UNIX, SOCK_STREAM, 0);
108     if (fd == -1)
109         return -1;
110     success = 0;
111     while (!success) {
112         if (connect(fd, (struct sockaddr *)&addr, len) == 0)
113             success = 1;
114         else {
115             switch (errno) {
116 #  ifdef EINTR
117             case EINTR:
118 #  endif
119 #  ifdef EAGAIN
120             case EAGAIN:
121 #  endif
122 #  ifdef EINPROGRESS
123             case EINPROGRESS:
124 #  endif
125 #  ifdef EALREADY
126             case EALREADY:
127 #  endif
128                 /* No error, try again */
129                 break;
130 #  ifdef EISCONN
131             case EISCONN:
132                 success = 1;
133                 break;
134 #  endif
135             default:
136                 ret = -1;
137                 goto err;       /* failure */
138             }
139         }
140     }
141
142     while (bytes > 0) {
143         egdbuf[0] = 1;
144         egdbuf[1] = bytes < 255 ? bytes : 255;
145         numbytes = 0;
146         while (numbytes != 2) {
147             num = write(fd, egdbuf + numbytes, 2 - numbytes);
148             if (num >= 0)
149                 numbytes += num;
150             else {
151                 switch (errno) {
152 #  ifdef EINTR
153                 case EINTR:
154 #  endif
155 #  ifdef EAGAIN
156                 case EAGAIN:
157 #  endif
158                     /* No error, try again */
159                     break;
160                 default:
161                     ret = -1;
162                     goto err;   /* failure */
163                 }
164             }
165         }
166         numbytes = 0;
167         while (numbytes != 1) {
168             num = read(fd, egdbuf, 1);
169             if (num == 0)
170                 goto err;       /* descriptor closed */
171             else if (num > 0)
172                 numbytes += num;
173             else {
174                 switch (errno) {
175 #  ifdef EINTR
176                 case EINTR:
177 #  endif
178 #  ifdef EAGAIN
179                 case EAGAIN:
180 #  endif
181                     /* No error, try again */
182                     break;
183                 default:
184                     ret = -1;
185                     goto err;   /* failure */
186                 }
187             }
188         }
189         if (egdbuf[0] == 0)
190             goto err;
191         if (buf)
192             retrievebuf = buf + ret;
193         else
194             retrievebuf = tempbuf;
195         numbytes = 0;
196         while (numbytes != egdbuf[0]) {
197             num = read(fd, retrievebuf + numbytes, egdbuf[0] - numbytes);
198             if (num == 0)
199                 goto err;       /* descriptor closed */
200             else if (num > 0)
201                 numbytes += num;
202             else {
203                 switch (errno) {
204 #  ifdef EINTR
205                 case EINTR:
206 #  endif
207 #  ifdef EAGAIN
208                 case EAGAIN:
209 #  endif
210                     /* No error, try again */
211                     break;
212                 default:
213                     ret = -1;
214                     goto err;   /* failure */
215                 }
216             }
217         }
218         ret += egdbuf[0];
219         bytes -= egdbuf[0];
220         if (!buf)
221             RAND_seed(tempbuf, egdbuf[0]);
222     }
223  err:
224     if (fd != -1)
225         close(fd);
226     return ret;
227 }
228
229 int RAND_egd_bytes(const char *path, int bytes)
230 {
231     int num, ret = -1;
232
233     num = RAND_query_egd_bytes(path, NULL, bytes);
234     if (num < 0)
235         goto err;
236     if (RAND_status() == 1)
237         ret = num;
238  err:
239     return ret;
240 }
241
242 int RAND_egd(const char *path)
243 {
244     return RAND_egd_bytes(path, 255);
245 }
246
247 # endif
248
249 #endif