We occasionally see OpenSSL fail to seed its random number generator in heavily loaded hypervisors. I suspect the following scenario:
1. OpenSSL calls read() to get 32 bytes from /dev/urandom. 2. The kernel generates 10 bytes of randomness and copies it out. 3. A signal arrives (perhaps SIGALRM). 4. The kernel interrupts the system call to service the signal. 5. Userspace gets 10 bytes of entropy. 6. OpenSSL doesn't read again to get the final 22 bytes. Therefore OpenSSL doesn't have enough entropy to consider itself initialized. It never tries again, so we're stuck forever. The only part I'm not entirely sure about is #6, because the OpenSSL code is so hard to read. Thanks to Alex Yip for suggesting that this might be a startup problem. Bug #10164. Reported-by: Ram Jothikumar <[email protected]> Signed-off-by: Ben Pfaff <[email protected]> --- lib/stream-ssl.c | 33 ++++++++++++++++++++++++++++++++- 1 files changed, 32 insertions(+), 1 deletions(-) diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c index 42690e4..c97e83c 100644 --- a/lib/stream-ssl.c +++ b/lib/stream-ssl.c @@ -26,6 +26,7 @@ #include <sys/socket.h> #include <netinet/tcp.h> #include <openssl/err.h> +#include <openssl/rand.h> #include <openssl/ssl.h> #include <openssl/x509v3.h> #include <poll.h> @@ -34,6 +35,7 @@ #include <unistd.h> #include "coverage.h" #include "dynamic-string.h" +#include "entropy.h" #include "leak-checker.h" #include "ofpbuf.h" #include "openflow/openflow.h" @@ -228,7 +230,7 @@ new_ssl_stream(const char *name, int fd, enum session_type type, VLOG_ERR("CA certificate must be configured to use SSL"); retval = ENOPROTOOPT; } - if (!SSL_CTX_check_private_key(ctx)) { + if (!retval && !SSL_CTX_check_private_key(ctx)) { VLOG_ERR("Private key does not match certificate public key: %s", ERR_error_string(ERR_get_error(), NULL)); retval = ENOPROTOOPT; @@ -900,6 +902,35 @@ do_ssl_init(void) SSL_library_init(); SSL_load_error_strings(); + if (!RAND_status()) { + /* We occasionally see OpenSSL fail to seed its random number generator + * in heavily loaded hypervisors. I suspect the following scenario: + * + * 1. OpenSSL calls read() to get 32 bytes from /dev/urandom. + * 2. The kernel generates 10 bytes of randomness and copies it out. + * 3. A signal arrives (perhaps SIGALRM). + * 4. The kernel interrupts the system call to service the signal. + * 5. Userspace gets 10 bytes of entropy. + * 6. OpenSSL doesn't read again to get the final 22 bytes. Therefore + * OpenSSL doesn't have enough entropy to consider itself + * initialized. + * + * The only part I'm not entirely sure about is #6, because the OpenSSL + * code is so hard to read. */ + uint8_t seed[32]; + int retval; + + VLOG_WARN("OpenSSL random seeding failed, reseeding ourselves"); + + retval = get_entropy(seed, sizeof seed); + if (!retval) { + RAND_seed(seed, sizeof seed); + } else { + VLOG_ERR("failed to obtain entropy (%s)", + ovs_retval_to_string(retval)); + } + } + /* New OpenSSL changed TLSv1_method() to return a "const" pointer, so the * cast is needed to avoid a warning with those newer versions. */ method = CONST_CAST(SSL_METHOD *, TLSv1_method()); -- 1.7.2.5 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
