From 11570f6201548b957b70e8b93e954538f01d09c7 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 18 Dec 2013 20:37:44 +0100 Subject: [PATCH] Improve initialisation of OpenSSL PRNG. Basic idea taken from Tor. --- lib/event.c | 2 +- lib/examples/client-blocking.c | 3 +- lib/radsec.c | 10 +++--- lib/radsecproxy/tlscommon.c | 15 -------- lib/radsecproxy/tlscommon.h | 1 - lib/tls.c | 81 +++++++++++++++++++++++++++++++++++++++++- lib/tls.h | 12 ++++++- 7 files changed, 99 insertions(+), 25 deletions(-) diff --git a/lib/event.c b/lib/event.c index b572184..a532da9 100644 --- a/lib/event.c +++ b/lib/event.c @@ -158,7 +158,7 @@ event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer) #if defined (RS_ENABLE_TLS) else if (conn->realm->type == RS_CONN_TYPE_TLS) { - if (rs_tls_init (conn)) + if (tls_init_conn (conn)) return -1; /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things seem to break when be_openssl_ctrl() (in libevent) calls diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index cce00bf..a50ee8a 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -26,8 +26,7 @@ blocking_client (const char *config_fn, const char *configuration, r = rs_context_create (&h); if (r) { - assert(r == RSE_NOMEM); - assert (!"out of RAM -- unable to create libradsec context"); + assert (!"unable to create libradsec context"); } #if !defined (USE_CONFIG_FILE) diff --git a/lib/radsec.c b/lib/radsec.c index efd2dc3..83ce6c5 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -21,6 +21,7 @@ #include "debug.h" #include "radsecproxy/debug.h" #if defined (RS_ENABLE_TLS) +#include "tls.h" #include #include "radsecproxy/list.h" #include "radsecproxy/radsecproxy.h" @@ -32,14 +33,15 @@ rs_context_create (struct rs_context **ctx) { struct rs_context *h; +#if defined (RS_ENABLE_TLS) + if (tls_init ()) + return RSE_SSLERR; +#endif + h = calloc (1, sizeof(*h)); if (h == NULL) return RSE_NOMEM; -#if defined (RS_ENABLE_TLS) - ssl_init (); -#endif - debug_init ("libradsec"); /* radsecproxy compat, FIXME: remove */ if (ctx != NULL) diff --git a/lib/radsecproxy/tlscommon.c b/lib/radsecproxy/tlscommon.c index 002788d..e7b53bf 100644 --- a/lib/radsecproxy/tlscommon.c +++ b/lib/radsecproxy/tlscommon.c @@ -39,21 +39,6 @@ static struct hash *tlsconfs = NULL; -void ssl_init(void) { - time_t t; - pid_t pid; - - SSL_load_error_strings(); - SSL_library_init(); - - while (!RAND_status()) { - t = time(NULL); - pid = getpid(); - RAND_seed((unsigned char *)&t, sizeof(time_t)); - RAND_seed((unsigned char *)&pid, sizeof(pid)); - } -} - static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) { int pwdlen = strlen(userdata); if (rwflag != 0 || pwdlen > size) /* not for decryption or too large */ diff --git a/lib/radsecproxy/tlscommon.h b/lib/radsecproxy/tlscommon.h index da2092e..ddfba2d 100644 --- a/lib/radsecproxy/tlscommon.h +++ b/lib/radsecproxy/tlscommon.h @@ -26,7 +26,6 @@ struct tls { }; #if defined(RADPROT_TLS) || defined(RADPROT_DTLS) -void ssl_init(); struct tls *tlsgettls(char *alt1, char *alt2); SSL_CTX *tlsgetctx(uint8_t type, struct tls *t); X509 *verifytlscert(SSL *ssl); diff --git a/lib/tls.c b/lib/tls.c index 62b281f..e5e7440 100644 --- a/lib/tls.c +++ b/lib/tls.c @@ -6,11 +6,15 @@ #endif #include +#include #include +#include +#include #include #include #include #include +#include #include #include @@ -18,6 +22,8 @@ #include "radsecproxy/list.h" #include "radsecproxy/radsecproxy.h" +#include "tls.h" + static struct tls * _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm) { @@ -112,8 +118,81 @@ psk_client_cb (SSL *ssl, } #endif /* RS_ENABLE_TLS_PSK */ +/** Read \a buf_len bytes from one of the random devices into \a + buf. Return 0 on success and -1 on failure. */ +static int +load_rand_ (uint8_t *buf, size_t buf_len) +{ + static const char *fns[] = {"/dev/urandom", "/dev/random", NULL}; + int i; + + if (buf_len > SSIZE_MAX) + return -1; + + for (i = 0; fns[i] != NULL; i++) + { + size_t nread = 0; + int fd = open (fns[i], O_RDONLY); + if (fd < 0) + continue; + while (nread != buf_len) + { + ssize_t r = read (fd, buf + nread, buf_len - nread); + if (r < 0) + return -1; + if (r == 0) + break; + nread += r; + } + close (fd); + if (nread != buf_len) + return -1; + return 0; + } + return -1; +} + +/** Initialise OpenSSL's PRNG by possibly invoking RAND_poll() and by + feeding RAND_seed() data from one of the random devices. If either + succeeds, we're happy and return 0. */ +static int +init_openssl_rand_ (void) +{ + long openssl_version = 0; + int openssl_random_init_flag = 0; + int our_random_init_flag = 0; + uint8_t buf[32]; + + /* Older OpenSSL has a crash bug in RAND_poll (when a file it opens + gets a file descriptor with a number higher than FD_SETSIZE) so + use it only for newer versions. */ + openssl_version = SSLeay (); + if (openssl_version >= OPENSSL_V (0,9,8,'c')) + openssl_random_init_flag = RAND_poll (); + + our_random_init_flag = !load_rand_ (buf, sizeof(buf)); + if (our_random_init_flag) + RAND_seed (buf, sizeof(buf)); + memset (buf, 0, sizeof(buf)); /* FIXME: What if memset() is optimised out? */ + + if (!openssl_random_init_flag && !our_random_init_flag) + return -1; + if (!RAND_bytes (buf, sizeof(buf))) + return -1; + return 0; +} + +/** Initialise the TLS library. Return 0 on success, -1 on failure. */ +int +tls_init (void) +{ + SSL_load_error_strings (); + SSL_library_init (); + return init_openssl_rand_ (); +} + int -rs_tls_init (struct rs_connection *conn) +tls_init_conn (struct rs_connection *conn) { struct rs_context *ctx = NULL; struct tls *tlsconf = NULL; diff --git a/lib/tls.h b/lib/tls.h index 4707b93..51f2a64 100644 --- a/lib/tls.h +++ b/lib/tls.h @@ -5,9 +5,19 @@ extern "C" { #endif -int rs_tls_init (struct rs_connection *conn); +int tls_init (void); +int tls_init_conn (struct rs_connection *conn); int tls_verify_cert (struct rs_connection *conn); +#define OPENSSL_VER(a,b,c,d,e) \ + (((a)<<28) | \ + ((b)<<20) | \ + ((c)<<12) | \ + ((d)<< 4) | \ + (e)) +#define OPENSSL_V(a,b,c,d) \ + OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf) + #if defined (__cplusplus) } #endif -- 2.1.4