diff options
author | Vicent Marti <vicent@github.com> | 2014-06-14 12:58:03 +0200 |
---|---|---|
committer | Vicent Marti <vicent@github.com> | 2014-06-14 12:58:03 +0200 |
commit | e93206e0f5bd9a1f2ad17d0d566b1e815a762420 (patch) | |
tree | 33648b927df9bfddb3262ea8aba1d12995ab68cf | |
parent | 9c3e4e97f6995bde7879a5907497c35f83ef6b56 (diff) | |
parent | 081e76bac26e1ed6adafb402d15b30c622866d61 (diff) | |
download | libgit2-e93206e0f5bd9a1f2ad17d0d566b1e815a762420.tar.gz |
Merge pull request #2421 from libgit2/cmn/init-ssl-once
netops: init OpenSSL once under lock
-rw-r--r-- | src/global.c | 67 | ||||
-rw-r--r-- | src/global.h | 5 | ||||
-rw-r--r-- | src/netops.c | 24 | ||||
-rw-r--r-- | src/netops.h | 1 |
4 files changed, 81 insertions, 16 deletions
diff --git a/src/global.c b/src/global.c index 1c4a7a1a9..03a4bcedf 100644 --- a/src/global.c +++ b/src/global.c @@ -16,6 +16,12 @@ git_mutex git__mwindow_mutex; #define MAX_SHUTDOWN_CB 8 +#ifdef GIT_SSL +# include <openssl/ssl.h> +SSL_CTX *git__ssl_ctx; +static git_mutex *openssl_locks; +#endif + static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_atomic git__n_shutdown_callbacks; static git_atomic git__n_inits; @@ -39,6 +45,62 @@ static void git__shutdown(void) } +#if defined(GIT_THREADS) && defined(GIT_SSL) +void openssl_locking_function(int mode, int n, const char *file, int line) +{ + int lock; + + GIT_UNUSED(file); + GIT_UNUSED(line); + + lock = mode & CRYPTO_LOCK; + + if (lock) { + git_mutex_lock(&openssl_locks[n]); + } else { + git_mutex_unlock(&openssl_locks[n]); + } +} +#endif + + +static void init_ssl(void) +{ +#ifdef GIT_SSL + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + git__ssl_ctx = SSL_CTX_new(SSLv23_method()); + SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); + SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); + if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } + +# ifdef GIT_THREADS + { + int num_locks, i; + + num_locks = CRYPTO_num_locks(); + openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); + if (openssl_locks == NULL) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } + + for (i = 0; i < num_locks; i++) { + if (git_mutex_init(&openssl_locks[i]) != 0) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } + } + + CRYPTO_set_locking_callback(openssl_locking_function); + } +# endif +#endif +} + /** * Handle the global state with TLS * @@ -168,10 +230,14 @@ static void init_once(void) return; pthread_key_create(&_tls_key, &cb__free_status); + /* Initialize any other subsystems that have global state */ if ((init_error = git_hash_global_init()) >= 0) init_error = git_sysdir_global_init(); + /* OpenSSL needs to be initialized from the main thread */ + init_ssl(); + GIT_MEMORY_BARRIER; } @@ -225,6 +291,7 @@ static git_global_st __state; int git_threads_init(void) { + init_ssl(); git_atomic_inc(&git__n_inits); return 0; } diff --git a/src/global.h b/src/global.h index 778250376..745df3e4a 100644 --- a/src/global.h +++ b/src/global.h @@ -15,6 +15,11 @@ typedef struct { git_error error_t; } git_global_st; +#ifdef GIT_SSL +# include <openssl/ssl.h> +extern SSL_CTX *git__ssl_ctx; +#endif + git_global_st *git__global_state(void); extern git_mutex git__mwindow_mutex; diff --git a/src/netops.c b/src/netops.c index a0193a022..965e4775d 100644 --- a/src/netops.c +++ b/src/netops.c @@ -33,6 +33,7 @@ #include "posix.h" #include "buffer.h" #include "http_parser.h" +#include "global.h" #ifdef GIT_WIN32 static void net_set_error(const char *str) @@ -157,7 +158,7 @@ void gitno_buffer_setup_callback( void gitno_buffer_setup(gitno_socket *socket, gitno_buffer *buf, char *data, size_t len) { #ifdef GIT_SSL - if (socket->ssl.ctx) { + if (socket->ssl.ssl) { gitno_buffer_setup_callback(socket, buf, data, len, gitno__recv_ssl, NULL); return; } @@ -202,7 +203,6 @@ static int gitno_ssl_teardown(gitno_ssl *ssl) ret = 0; SSL_free(ssl->ssl); - SSL_CTX_free(ssl->ctx); return ret; } @@ -390,18 +390,12 @@ static int ssl_setup(gitno_socket *socket, const char *host, int flags) { int ret; - SSL_library_init(); - SSL_load_error_strings(); - socket->ssl.ctx = SSL_CTX_new(SSLv23_method()); - if (socket->ssl.ctx == NULL) - return ssl_set_error(&socket->ssl, 0); - - SSL_CTX_set_mode(socket->ssl.ctx, SSL_MODE_AUTO_RETRY); - SSL_CTX_set_verify(socket->ssl.ctx, SSL_VERIFY_NONE, NULL); - if (!SSL_CTX_set_default_verify_paths(socket->ssl.ctx)) - return ssl_set_error(&socket->ssl, 0); + if (git__ssl_ctx == NULL) { + giterr_set(GITERR_NET, "OpenSSL initialization failed"); + return -1; + } - socket->ssl.ssl = SSL_new(socket->ssl.ctx); + socket->ssl.ssl = SSL_new(git__ssl_ctx); if (socket->ssl.ssl == NULL) return ssl_set_error(&socket->ssl, 0); @@ -538,7 +532,7 @@ int gitno_send(gitno_socket *socket, const char *msg, size_t len, int flags) size_t off = 0; #ifdef GIT_SSL - if (socket->ssl.ctx) + if (socket->ssl.ssl) return gitno_send_ssl(&socket->ssl, msg, len, flags); #endif @@ -559,7 +553,7 @@ int gitno_send(gitno_socket *socket, const char *msg, size_t len, int flags) int gitno_close(gitno_socket *s) { #ifdef GIT_SSL - if (s->ssl.ctx && + if (s->ssl.ssl && gitno_ssl_teardown(&s->ssl) < 0) return -1; #endif diff --git a/src/netops.h b/src/netops.h index 8e3a2524f..dfb4ab7b4 100644 --- a/src/netops.h +++ b/src/netops.h @@ -16,7 +16,6 @@ struct gitno_ssl { #ifdef GIT_SSL - SSL_CTX *ctx; SSL *ssl; #else size_t dummy; |