From e43a898043faa3a965dbaa1193cc60e0b479033d Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 18 Jun 2021 18:32:51 +1000 Subject: [PATCH] Split EGD/PRNGD interface into its own file. This will allow us to use it when building --without-openssl. --- entropy.c | 123 --------------------------- openbsd-compat/Makefile.in | 1 + openbsd-compat/bsd-misc.h | 1 + openbsd-compat/port-prngd.c | 162 ++++++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 123 deletions(-) create mode 100644 openbsd-compat/port-prngd.c diff --git a/entropy.c b/entropy.c index 19ddeeafa..a4088e43c 100644 --- a/entropy.c +++ b/entropy.c @@ -29,20 +29,12 @@ #ifdef WITH_OPENSSL #include -#include -#ifdef HAVE_SYS_UN_H -# include -#endif - -#include -#include #include #include #include #include #include -#include /* for offsetof */ #include #include @@ -67,121 +59,6 @@ */ #ifndef OPENSSL_PRNG_ONLY -/* - * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon - * listening either on 'tcp_port', or via Unix domain socket at * - * 'socket_path'. - * Either a non-zero tcp_port or a non-null socket_path must be - * supplied. - * Returns 0 on success, -1 on error - */ -int -get_random_bytes_prngd(unsigned char *buf, int len, - unsigned short tcp_port, char *socket_path) -{ - int fd, addr_len, rval, errors; - u_char msg[2]; - struct sockaddr_storage addr; - struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; - struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr; - sshsig_t old_sigpipe; - - /* Sanity checks */ - if (socket_path == NULL && tcp_port == 0) - fatal("You must specify a port or a socket"); - if (socket_path != NULL && - strlen(socket_path) >= sizeof(addr_un->sun_path)) - fatal("Random pool path is too long"); - if (len <= 0 || len > 255) - fatal("Too many bytes (%d) to read from PRNGD", len); - - memset(&addr, '\0', sizeof(addr)); - - if (tcp_port != 0) { - addr_in->sin_family = AF_INET; - addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr_in->sin_port = htons(tcp_port); - addr_len = sizeof(*addr_in); - } else { - addr_un->sun_family = AF_UNIX; - strlcpy(addr_un->sun_path, socket_path, - sizeof(addr_un->sun_path)); - addr_len = offsetof(struct sockaddr_un, sun_path) + - strlen(socket_path) + 1; - } - - old_sigpipe = ssh_signal(SIGPIPE, SIG_IGN); - - errors = 0; - rval = -1; -reopen: - fd = socket(addr.ss_family, SOCK_STREAM, 0); - if (fd == -1) { - error("Couldn't create socket: %s", strerror(errno)); - goto done; - } - - if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) { - if (tcp_port != 0) { - error("Couldn't connect to PRNGD port %d: %s", - tcp_port, strerror(errno)); - } else { - error("Couldn't connect to PRNGD socket \"%s\": %s", - addr_un->sun_path, strerror(errno)); - } - goto done; - } - - /* Send blocking read request to PRNGD */ - msg[0] = 0x02; - msg[1] = len; - - if (atomicio(vwrite, fd, msg, sizeof(msg)) != sizeof(msg)) { - if (errno == EPIPE && errors < 10) { - close(fd); - errors++; - goto reopen; - } - error("Couldn't write to PRNGD socket: %s", - strerror(errno)); - goto done; - } - - if (atomicio(read, fd, buf, len) != (size_t)len) { - if (errno == EPIPE && errors < 10) { - close(fd); - errors++; - goto reopen; - } - error("Couldn't read from PRNGD socket: %s", - strerror(errno)); - goto done; - } - - rval = 0; -done: - ssh_signal(SIGPIPE, old_sigpipe); - if (fd != -1) - close(fd); - return rval; -} - -static int -seed_from_prngd(unsigned char *buf, size_t bytes) -{ -#ifdef PRNGD_PORT - debug("trying egd/prngd port %d", PRNGD_PORT); - if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0) - return 0; -#endif -#ifdef PRNGD_SOCKET - debug("trying egd/prngd socket %s", PRNGD_SOCKET); - if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0) - return 0; -#endif - return -1; -} - void rexec_send_rng_seed(struct sshbuf *m) { diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in index 555e09b5e..5d53bef57 100644 --- a/openbsd-compat/Makefile.in +++ b/openbsd-compat/Makefile.in @@ -95,6 +95,7 @@ COMPAT= arc4random.o \ PORTS= port-aix.o \ port-irix.o \ port-linux.o \ + port-prngd.o \ port-solaris.o \ port-net.o \ port-uw.o diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h index def64238a..2206e1a82 100644 --- a/openbsd-compat/bsd-misc.h +++ b/openbsd-compat/bsd-misc.h @@ -20,6 +20,7 @@ #include "includes.h" char *ssh_get_progname(char *); +int seed_from_prngd(unsigned char *, size_t); #ifndef HAVE_SETSID #define setsid() setpgrp(0, getpid()) diff --git a/openbsd-compat/port-prngd.c b/openbsd-compat/port-prngd.c new file mode 100644 index 000000000..915f82062 --- /dev/null +++ b/openbsd-compat/port-prngd.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#include +#include +#ifdef HAVE_SYS_UN_H +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include /* for offsetof */ + +#include "atomicio.h" +#include "misc.h" +#include "log.h" + +/* + * EGD/PRNGD interface. + * + * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon + * listening either on 'tcp_port', or via Unix domain socket at * + * 'socket_path'. + * Either a non-zero tcp_port or a non-null socket_path must be + * supplied. + * Returns 0 on success, -1 on error + */ +static int +get_random_bytes_prngd(unsigned char *buf, int len, + unsigned short tcp_port, char *socket_path) +{ + int fd, addr_len, rval, errors; + u_char msg[2]; + struct sockaddr_storage addr; + struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; + struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr; + sshsig_t old_sigpipe; + + /* Sanity checks */ + if (socket_path == NULL && tcp_port == 0) + fatal("You must specify a port or a socket"); + if (socket_path != NULL && + strlen(socket_path) >= sizeof(addr_un->sun_path)) + fatal("Random pool path is too long"); + if (len <= 0 || len > 255) + fatal("Too many bytes (%d) to read from PRNGD", len); + + memset(&addr, '\0', sizeof(addr)); + + if (tcp_port != 0) { + addr_in->sin_family = AF_INET; + addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr_in->sin_port = htons(tcp_port); + addr_len = sizeof(*addr_in); + } else { + addr_un->sun_family = AF_UNIX; + strlcpy(addr_un->sun_path, socket_path, + sizeof(addr_un->sun_path)); + addr_len = offsetof(struct sockaddr_un, sun_path) + + strlen(socket_path) + 1; + } + + old_sigpipe = ssh_signal(SIGPIPE, SIG_IGN); + + errors = 0; + rval = -1; +reopen: + fd = socket(addr.ss_family, SOCK_STREAM, 0); + if (fd == -1) { + error("Couldn't create socket: %s", strerror(errno)); + goto done; + } + + if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) { + if (tcp_port != 0) { + error("Couldn't connect to PRNGD port %d: %s", + tcp_port, strerror(errno)); + } else { + error("Couldn't connect to PRNGD socket \"%s\": %s", + addr_un->sun_path, strerror(errno)); + } + goto done; + } + + /* Send blocking read request to PRNGD */ + msg[0] = 0x02; + msg[1] = len; + + if (atomicio(vwrite, fd, msg, sizeof(msg)) != sizeof(msg)) { + if (errno == EPIPE && errors < 10) { + close(fd); + errors++; + goto reopen; + } + error("Couldn't write to PRNGD socket: %s", + strerror(errno)); + goto done; + } + + if (atomicio(read, fd, buf, len) != (size_t)len) { + if (errno == EPIPE && errors < 10) { + close(fd); + errors++; + goto reopen; + } + error("Couldn't read from PRNGD socket: %s", + strerror(errno)); + goto done; + } + + rval = 0; +done: + ssh_signal(SIGPIPE, old_sigpipe); + if (fd != -1) + close(fd); + return rval; +} + +int +seed_from_prngd(unsigned char *buf, size_t bytes) +{ +#ifdef PRNGD_PORT + debug("trying egd/prngd port %d", PRNGD_PORT); + if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0) + return 0; +#endif +#ifdef PRNGD_SOCKET + debug("trying egd/prngd socket %s", PRNGD_SOCKET); + if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0) + return 0; +#endif + return -1; +}