diff options
Diffstat (limited to 'src/openssl_stream.c')
| -rw-r--r-- | src/openssl_stream.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/openssl_stream.c b/src/openssl_stream.c index 54dd761ca..0705d90e7 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -31,6 +31,115 @@ #include <openssl/x509v3.h> #include <openssl/bio.h> +SSL_CTX *git__ssl_ctx; + +#ifdef GIT_THREADS + +static git_mutex *openssl_locks; + +static 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]); + } +} + +static void shutdown_ssl_locking(void) +{ + int num_locks, i; + + num_locks = CRYPTO_num_locks(); + CRYPTO_set_locking_callback(NULL); + + for (i = 0; i < num_locks; ++i) + git_mutex_free(openssl_locks); + git__free(openssl_locks); +} + +#endif /* GIT_THREADS */ + +/** + * This function aims to clean-up the SSL context which + * we allocated. + */ +static void shutdown_ssl(void) +{ + if (git__ssl_ctx) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } +} + +int git_openssl_stream_global_init(void) +{ +#ifdef GIT_OPENSSL + long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + + /* Older OpenSSL and MacOS OpenSSL doesn't have this */ +#ifdef SSL_OP_NO_COMPRESSION + ssl_opts |= SSL_OP_NO_COMPRESSION; +#endif + + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + /* + * Load SSLv{2,3} and TLSv1 so that we can talk with servers + * which use the SSL hellos, which are often used for + * compatibility. We then disable SSL so we only allow OpenSSL + * to speak TLSv1 to perform the encryption itself. + */ + git__ssl_ctx = SSL_CTX_new(SSLv23_method()); + SSL_CTX_set_options(git__ssl_ctx, ssl_opts); + 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; + return -1; + } +#endif + + git__on_shutdown(shutdown_ssl); + + return 0; +} + +int git_openssl_set_locking(void) +{ +#ifdef GIT_THREADS + int num_locks, i; + + num_locks = CRYPTO_num_locks(); + openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); + GITERR_CHECK_ALLOC(openssl_locks); + + for (i = 0; i < num_locks; i++) { + if (git_mutex_init(&openssl_locks[i]) != 0) { + giterr_set(GITERR_SSL, "failed to initialize openssl locks"); + return -1; + } + } + + CRYPTO_set_locking_callback(openssl_locking_function); + git__on_shutdown(shutdown_ssl_locking); + return 0; +#else + giterr_set(GITERR_THREAD, "libgit2 as not built with threads"); + return -1; +#endif +} + + static int bio_create(BIO *b) { b->init = 1; @@ -472,6 +581,17 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port) #include "stream.h" +int git_openssl_stream_global_init(void) +{ + return 0; +} + +int git_openssl_set_locking(void) +{ + giterr_set(GITERR_SSL, "libgit2 was not built with OpenSSL support"); + return -1; +} + int git_openssl_stream_new(git_stream **out, const char *host, const char *port) { GIT_UNUSED(out); |
