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 OPENSSL_strlcpy(addr.sun_path, path, sizeof(addr.sun_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 250