1/* 2 * Copyright (c) 2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include <config.h> 35 36#include <sys/types.h> 37#ifdef HAVE_SYS_UN_H 38#include <sys/un.h> 39#endif 40 41#include <stdio.h> 42#include <stdlib.h> 43#ifdef HAVE_UNISTD_H 44#include <unistd.h> 45#endif 46#include <assert.h> 47 48#include <rand.h> 49#include <randi.h> 50 51#include <roken.h> 52 53static const char *egd_path = "/var/run/egd-pool"; 54 55#define MAX_EGD_DATA 255 56 57static int 58connect_egd(const char *path) 59{ 60 struct sockaddr_un addr; 61 int fd; 62 63 memset(&addr, 0, sizeof(addr)); 64 65 if (strlen(path) > sizeof(addr.sun_path)) 66 return -1; 67 68 addr.sun_family = AF_UNIX; 69 strlcpy(addr.sun_path, path, sizeof(addr.sun_path)); 70 71 fd = socket(AF_UNIX, SOCK_STREAM, 0); 72 if (fd < 0) 73 return -1; 74 75 rk_cloexec(fd); 76 77 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { 78 close(fd); 79 return -1; 80 } 81 82 return fd; 83} 84 85static int 86get_entropy(int fd, void *data, size_t len) 87{ 88 unsigned char msg[2]; 89 90 assert(len <= MAX_EGD_DATA); 91 92 msg[0] = 0x02; /* read blocking data */ 93 msg[1] = len; /* wanted length */ 94 95 if (net_write(fd, msg, sizeof(msg)) != sizeof(msg)) 96 return 0; 97 98 if (net_read(fd, data, len) != len) 99 return 0; 100 101 return 1; 102} 103 104static int 105put_entropy(int fd, const void *data, size_t len) 106{ 107 unsigned char msg[4]; 108 109 assert (len <= MAX_EGD_DATA); 110 111 msg[0] = 0x03; /* write data */ 112 msg[1] = 0; /* dummy */ 113 msg[2] = 0; /* entropy */ 114 msg[3] = len; /* length */ 115 116 if (net_write(fd, msg, sizeof(msg)) != sizeof(msg)) 117 return 0; 118 if (net_write(fd, data, len) != len) 119 return 0; 120 121 return 1; 122} 123 124/* 125 * 126 */ 127 128static void 129egd_seed(const void *indata, int size) 130{ 131 size_t len; 132 int fd, ret = 1; 133 134 fd = connect_egd(egd_path); 135 if (fd < 0) 136 return; 137 138 while(size) { 139 len = size; 140 if (len > MAX_EGD_DATA) 141 len = MAX_EGD_DATA; 142 ret = put_entropy(fd, indata, len); 143 if (ret != 1) 144 break; 145 indata = ((unsigned char *)indata) + len; 146 size -= len; 147 } 148 close(fd); 149} 150 151static int 152get_bytes(const char *path, unsigned char *outdata, int size) 153{ 154 size_t len; 155 int fd, ret = 1; 156 157 if (path == NULL) 158 path = egd_path; 159 160 fd = connect_egd(path); 161 if (fd < 0) 162 return 0; 163 164 while(size) { 165 len = size; 166 if (len > MAX_EGD_DATA) 167 len = MAX_EGD_DATA; 168 ret = get_entropy(fd, outdata, len); 169 if (ret != 1) 170 break; 171 outdata += len; 172 size -= len; 173 } 174 close(fd); 175 176 return ret; 177} 178 179static int 180egd_bytes(unsigned char *outdata, int size) 181{ 182 return get_bytes(NULL, outdata, size); 183} 184 185static void 186egd_cleanup(void) 187{ 188} 189 190static void 191egd_add(const void *indata, int size, double entropi) 192{ 193 egd_seed(indata, size); 194} 195 196static int 197egd_pseudorand(unsigned char *outdata, int size) 198{ 199 return get_bytes(NULL, outdata, size); 200} 201 202static int 203egd_status(void) 204{ 205 int fd; 206 fd = connect_egd(egd_path); 207 if (fd < 0) 208 return 0; 209 close(fd); 210 return 1; 211} 212 213const RAND_METHOD hc_rand_egd_method = { 214 egd_seed, 215 egd_bytes, 216 egd_cleanup, 217 egd_add, 218 egd_pseudorand, 219 egd_status 220}; 221 222const RAND_METHOD * 223RAND_egd_method(void) 224{ 225 return &hc_rand_egd_method; 226} 227 228 229int 230RAND_egd(const char *filename) 231{ 232 return RAND_egd_bytes(filename, 128); 233} 234 235int 236RAND_egd_bytes(const char *filename, int size) 237{ 238 void *data; 239 int ret; 240 241 if (size <= 0) 242 return 0; 243 244 data = malloc(size); 245 if (data == NULL) 246 return 0; 247 248 ret = get_bytes(filename, data, size); 249 if (ret != 1) { 250 free(data); 251 return ret; 252 } 253 254 RAND_seed(data, size); 255 256 memset(data, 0, size); 257 free(data); 258 259 return 1; 260} 261