159191Skris/* crypto/rand/rand_egd.c */ 2109998Smarkm/* Written by Ulf Moeller and Lutz Jaenicke for the OpenSSL project. */ 359191Skris/* ==================================================================== 459191Skris * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. 559191Skris * 659191Skris * Redistribution and use in source and binary forms, with or without 759191Skris * modification, are permitted provided that the following conditions 859191Skris * are met: 959191Skris * 1059191Skris * 1. Redistributions of source code must retain the above copyright 11280304Sjkim * notice, this list of conditions and the following disclaimer. 1259191Skris * 1359191Skris * 2. Redistributions in binary form must reproduce the above copyright 1459191Skris * notice, this list of conditions and the following disclaimer in 1559191Skris * the documentation and/or other materials provided with the 1659191Skris * distribution. 1759191Skris * 1859191Skris * 3. All advertising materials mentioning features or use of this 1959191Skris * software must display the following acknowledgment: 2059191Skris * "This product includes software developed by the OpenSSL Project 2159191Skris * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 2259191Skris * 2359191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2459191Skris * endorse or promote products derived from this software without 2559191Skris * prior written permission. For written permission, please contact 2659191Skris * openssl-core@openssl.org. 2759191Skris * 2859191Skris * 5. Products derived from this software may not be called "OpenSSL" 2959191Skris * nor may "OpenSSL" appear in their names without prior written 3059191Skris * permission of the OpenSSL Project. 3159191Skris * 3259191Skris * 6. Redistributions of any form whatsoever must retain the following 3359191Skris * acknowledgment: 3459191Skris * "This product includes software developed by the OpenSSL Project 3559191Skris * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 3659191Skris * 3759191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 3859191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3959191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4059191Skris * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 4159191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4259191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4359191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4459191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4559191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4659191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4759191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 4859191Skris * OF THE POSSIBILITY OF SUCH DAMAGE. 4959191Skris * ==================================================================== 5059191Skris * 5159191Skris * This product includes cryptographic software written by Eric Young 5259191Skris * (eay@cryptsoft.com). This product includes software written by Tim 5359191Skris * Hudson (tjh@cryptsoft.com). 5459191Skris * 5559191Skris */ 5659191Skris 57109998Smarkm#include <openssl/e_os2.h> 5859191Skris#include <openssl/rand.h> 59127128Snectar#include <openssl/buffer.h> 6059191Skris 61280304Sjkim/*- 62109998Smarkm * Query the EGD <URL: http://www.lothar.com/tech/crypto/>. 63109998Smarkm * 64109998Smarkm * This module supplies three routines: 65109998Smarkm * 66109998Smarkm * RAND_query_egd_bytes(path, buf, bytes) 67109998Smarkm * will actually query "bytes" bytes of entropy form the egd-socket located 68109998Smarkm * at path and will write them to buf (if supplied) or will directly feed 69109998Smarkm * it to RAND_seed() if buf==NULL. 70109998Smarkm * The number of bytes is not limited by the maximum chunk size of EGD, 71109998Smarkm * which is 255 bytes. If more than 255 bytes are wanted, several chunks 72109998Smarkm * of entropy bytes are requested. The connection is left open until the 73109998Smarkm * query is competed. 74109998Smarkm * RAND_query_egd_bytes() returns with 75109998Smarkm * -1 if an error occured during connection or communication. 76109998Smarkm * num the number of bytes read from the EGD socket. This number is either 77109998Smarkm * the number of bytes requested or smaller, if the EGD pool is 78109998Smarkm * drained and the daemon signals that the pool is empty. 79109998Smarkm * This routine does not touch any RAND_status(). This is necessary, since 80109998Smarkm * PRNG functions may call it during initialization. 81109998Smarkm * 82109998Smarkm * RAND_egd_bytes(path, bytes) will query "bytes" bytes and have them 83109998Smarkm * used to seed the PRNG. 84109998Smarkm * RAND_egd_bytes() is a wrapper for RAND_query_egd_bytes() with buf=NULL. 85109998Smarkm * Unlike RAND_query_egd_bytes(), RAND_status() is used to test the 86109998Smarkm * seed status so that the return value can reflect the seed state: 87109998Smarkm * -1 if an error occured during connection or communication _or_ 88109998Smarkm * if the PRNG has still not received the required seeding. 89109998Smarkm * num the number of bytes read from the EGD socket. This number is either 90109998Smarkm * the number of bytes requested or smaller, if the EGD pool is 91109998Smarkm * drained and the daemon signals that the pool is empty. 92109998Smarkm * 93109998Smarkm * RAND_egd(path) will query 255 bytes and use the bytes retreived to seed 94109998Smarkm * the PRNG. 95109998Smarkm * RAND_egd() is a wrapper for RAND_egd_bytes() with numbytes=255. 9659191Skris */ 9759191Skris 98238405Sjkim#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_VOS) || defined(OPENSSL_SYS_BEOS) 99109998Smarkmint RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes) 100280304Sjkim{ 101280304Sjkim return (-1); 102280304Sjkim} 103280304Sjkim 10459191Skrisint RAND_egd(const char *path) 105280304Sjkim{ 106280304Sjkim return (-1); 107280304Sjkim} 10868651Skris 109280304Sjkimint RAND_egd_bytes(const char *path, int bytes) 110280304Sjkim{ 111280304Sjkim return (-1); 112280304Sjkim} 11359191Skris#else 114280304Sjkim# include <openssl/opensslconf.h> 115280304Sjkim# include OPENSSL_UNISTD 116280304Sjkim# include <stddef.h> 117280304Sjkim# include <sys/types.h> 118280304Sjkim# include <sys/socket.h> 119280304Sjkim# ifndef NO_SYS_UN_H 120280304Sjkim# ifdef OPENSSL_SYS_VXWORKS 121100928Snectar# include <streams/un.h> 122280304Sjkim# else 123280304Sjkim# include <sys/un.h> 124280304Sjkim# endif 125100928Snectar# else 126280304Sjkimstruct sockaddr_un { 127280304Sjkim short sun_family; /* AF_UNIX */ 128280304Sjkim char sun_path[108]; /* path name (gag) */ 12976866Skris}; 130280304Sjkim# endif /* NO_SYS_UN_H */ 131280304Sjkim# include <string.h> 132280304Sjkim# include <errno.h> 13359191Skris 134280304Sjkim# ifndef offsetof 13559191Skris# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 136280304Sjkim# endif 13759191Skris 138109998Smarkmint RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes) 139280304Sjkim{ 140280304Sjkim int ret = 0; 141280304Sjkim struct sockaddr_un addr; 142280304Sjkim int len, num, numbytes; 143280304Sjkim int fd = -1; 144280304Sjkim int success; 145280304Sjkim unsigned char egdbuf[2], tempbuf[255], *retrievebuf; 14668651Skris 147280304Sjkim memset(&addr, 0, sizeof(addr)); 148280304Sjkim addr.sun_family = AF_UNIX; 149280304Sjkim if (strlen(path) >= sizeof(addr.sun_path)) 150280304Sjkim return (-1); 151280304Sjkim BUF_strlcpy(addr.sun_path, path, sizeof addr.sun_path); 152280304Sjkim len = offsetof(struct sockaddr_un, sun_path) + strlen(path); 153280304Sjkim fd = socket(AF_UNIX, SOCK_STREAM, 0); 154280304Sjkim if (fd == -1) 155280304Sjkim return (-1); 156280304Sjkim success = 0; 157280304Sjkim while (!success) { 158280304Sjkim if (connect(fd, (struct sockaddr *)&addr, len) == 0) 159280304Sjkim success = 1; 160280304Sjkim else { 161280304Sjkim switch (errno) { 162280304Sjkim# ifdef EINTR 163280304Sjkim case EINTR: 164280304Sjkim# endif 165280304Sjkim# ifdef EAGAIN 166280304Sjkim case EAGAIN: 167280304Sjkim# endif 168280304Sjkim# ifdef EINPROGRESS 169280304Sjkim case EINPROGRESS: 170280304Sjkim# endif 171280304Sjkim# ifdef EALREADY 172280304Sjkim case EALREADY: 173280304Sjkim# endif 174280304Sjkim /* No error, try again */ 175280304Sjkim break; 176280304Sjkim# ifdef EISCONN 177280304Sjkim case EISCONN: 178280304Sjkim success = 1; 179280304Sjkim break; 180280304Sjkim# endif 181280304Sjkim default: 182280304Sjkim goto err; /* failure */ 183280304Sjkim } 184280304Sjkim } 185280304Sjkim } 18668651Skris 187280304Sjkim while (bytes > 0) { 188280304Sjkim egdbuf[0] = 1; 189280304Sjkim egdbuf[1] = bytes < 255 ? bytes : 255; 190280304Sjkim numbytes = 0; 191280304Sjkim while (numbytes != 2) { 192280304Sjkim num = write(fd, egdbuf + numbytes, 2 - numbytes); 193280304Sjkim if (num >= 0) 194280304Sjkim numbytes += num; 195280304Sjkim else { 196280304Sjkim switch (errno) { 197280304Sjkim# ifdef EINTR 198280304Sjkim case EINTR: 199280304Sjkim# endif 200280304Sjkim# ifdef EAGAIN 201280304Sjkim case EAGAIN: 202280304Sjkim# endif 203280304Sjkim /* No error, try again */ 204280304Sjkim break; 205280304Sjkim default: 206280304Sjkim ret = -1; 207280304Sjkim goto err; /* failure */ 208280304Sjkim } 209280304Sjkim } 210280304Sjkim } 211280304Sjkim numbytes = 0; 212280304Sjkim while (numbytes != 1) { 213280304Sjkim num = read(fd, egdbuf, 1); 214280304Sjkim if (num == 0) 215280304Sjkim goto err; /* descriptor closed */ 216280304Sjkim else if (num > 0) 217280304Sjkim numbytes += num; 218280304Sjkim else { 219280304Sjkim switch (errno) { 220280304Sjkim# ifdef EINTR 221280304Sjkim case EINTR: 222280304Sjkim# endif 223280304Sjkim# ifdef EAGAIN 224280304Sjkim case EAGAIN: 225280304Sjkim# endif 226280304Sjkim /* No error, try again */ 227280304Sjkim break; 228280304Sjkim default: 229280304Sjkim ret = -1; 230280304Sjkim goto err; /* failure */ 231280304Sjkim } 232280304Sjkim } 233280304Sjkim } 234280304Sjkim if (egdbuf[0] == 0) 235280304Sjkim goto err; 236280304Sjkim if (buf) 237280304Sjkim retrievebuf = buf + ret; 238280304Sjkim else 239280304Sjkim retrievebuf = tempbuf; 240280304Sjkim numbytes = 0; 241280304Sjkim while (numbytes != egdbuf[0]) { 242280304Sjkim num = read(fd, retrievebuf + numbytes, egdbuf[0] - numbytes); 243280304Sjkim if (num == 0) 244280304Sjkim goto err; /* descriptor closed */ 245280304Sjkim else if (num > 0) 246280304Sjkim numbytes += num; 247280304Sjkim else { 248280304Sjkim switch (errno) { 249280304Sjkim# ifdef EINTR 250280304Sjkim case EINTR: 251280304Sjkim# endif 252280304Sjkim# ifdef EAGAIN 253280304Sjkim case EAGAIN: 254280304Sjkim# endif 255280304Sjkim /* No error, try again */ 256280304Sjkim break; 257280304Sjkim default: 258280304Sjkim ret = -1; 259280304Sjkim goto err; /* failure */ 260280304Sjkim } 261280304Sjkim } 262280304Sjkim } 263280304Sjkim ret += egdbuf[0]; 264280304Sjkim bytes -= egdbuf[0]; 265280304Sjkim if (!buf) 266280304Sjkim RAND_seed(tempbuf, egdbuf[0]); 267280304Sjkim } 26868651Skris err: 269280304Sjkim if (fd != -1) 270280304Sjkim close(fd); 271280304Sjkim return (ret); 272280304Sjkim} 27368651Skris 274109998Smarkmint RAND_egd_bytes(const char *path, int bytes) 275280304Sjkim{ 276280304Sjkim int num, ret = 0; 277109998Smarkm 278280304Sjkim num = RAND_query_egd_bytes(path, NULL, bytes); 279280304Sjkim if (num < 1) 280280304Sjkim goto err; 281280304Sjkim if (RAND_status() == 1) 282280304Sjkim ret = num; 283109998Smarkm err: 284280304Sjkim return (ret); 285280304Sjkim} 286109998Smarkm 287109998Smarkmint RAND_egd(const char *path) 288280304Sjkim{ 289280304Sjkim return (RAND_egd_bytes(path, 255)); 290280304Sjkim} 291109998Smarkm 29259191Skris#endif 293