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