diff options
author | Linus Nordberg <linus@nordberg.se> | 2013-12-18 20:37:44 +0100 |
---|---|---|
committer | Linus Nordberg <linus@nordberg.se> | 2013-12-20 19:00:12 +0100 |
commit | 11570f6201548b957b70e8b93e954538f01d09c7 (patch) | |
tree | c2ee2c80df6862842292f11878ab184b3464b9d4 | |
parent | da72e14ca91c1bdbee8bec0fcdd28054517cd200 (diff) |
Improve initialisation of OpenSSL PRNG.
Basic idea taken from Tor.
-rw-r--r-- | lib/event.c | 2 | ||||
-rw-r--r-- | lib/examples/client-blocking.c | 3 | ||||
-rw-r--r-- | lib/radsec.c | 10 | ||||
-rw-r--r-- | lib/radsecproxy/tlscommon.c | 15 | ||||
-rw-r--r-- | lib/radsecproxy/tlscommon.h | 1 | ||||
-rw-r--r-- | lib/tls.c | 81 | ||||
-rw-r--r-- | 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 <regex.h> #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); @@ -6,11 +6,15 @@ #endif #include <stdlib.h> +#include <unistd.h> #include <assert.h> +#include <fcntl.h> +#include <limits.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/bn.h> #include <openssl/x509v3.h> +#include <openssl/rand.h> #include <radsec/radsec.h> #include <radsec/radsec-impl.h> @@ -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; @@ -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 |