diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2021-08-24 18:28:28 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-24 18:28:28 -0400 |
commit | c8f4b5699ad0e7f57f0c0b82c1149efc0926e083 (patch) | |
tree | 868185b7690d5b41bf882cced9a999e81f0052c8 | |
parent | a09d4367495fb8a1300aeea5fd6ee22f26745ec8 (diff) | |
parent | 314469f90aefe86900c00bff21fa84be5e99f985 (diff) | |
download | libgit2-c8f4b5699ad0e7f57f0c0b82c1149efc0926e083.tar.gz |
Merge pull request #5974 from libgit2/ethomson/dlopen_ssl
Dynamically load OpenSSL (optionally)
31 files changed, 1852 insertions, 546 deletions
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e235a3ce7..47ebf464d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -59,6 +59,14 @@ jobs: CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON CMAKE_GENERATOR: Ninja os: ubuntu-latest + - # Xenial, Clang, OpenSSL (dynamically loaded) + container: + name: xenial + env: + CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON + CMAKE_GENERATOR: Ninja + os: ubuntu-latest - # Focal, Clang 10, mbedTLS, MemorySanitizer container: name: focal @@ -115,6 +123,14 @@ jobs: PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true os: ubuntu-latest + - # CentOS 7, OpenSSL (dynamically loaded) + container: + name: centos7 + env: + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON + PKG_CONFIG_PATH: /usr/local/lib/pkgconfig + SKIP_NEGOTIATE_TESTS: true + os: ubuntu-latest - # CentOS 8 container: name: centos8 @@ -124,6 +140,15 @@ jobs: SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true os: ubuntu-latest + - # CentOS 8, OpenSSL (dynamically loaded) + container: + name: centos8 + env: + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON + PKG_CONFIG_PATH: /usr/local/lib/pkgconfig + SKIP_NEGOTIATE_TESTS: true + SKIP_SSH_TESTS: true + os: ubuntu-latest - # macOS os: macos-10.15 env: @@ -180,6 +205,16 @@ jobs: BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + - # Bionic, GCC, OpenSSL (dynamically loaded) + container: + name: bionic + dockerfile: bionic + env: + CC: gcc + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON + RUN_INVASIVE_TESTS: true + os: ubuntu-latest - # Bionic, x86, Clang, OpenSSL container: name: bionic-x86 @@ -420,7 +420,7 @@ The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -1019,3 +1019,111 @@ following restrictions are are met: THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +---------------------------------------------------------------------- + +Portions of the OpenSSL headers are included under the OpenSSL license: + +Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) +All rights reserved. + +This package is an SSL implementation written +by Eric Young (eay@cryptsoft.com). +The implementation was written so as to conform with Netscapes SSL. + +This library is free for commercial and non-commercial use as long as +the following conditions are aheared to. The following conditions +apply to all code found in this distribution, be it the RC4, RSA, +lhash, DES, etc., code; not just the SSL code. The SSL documentation +included with this distribution is covered by the same copyright terms +except that the holder is Tim Hudson (tjh@cryptsoft.com). + +Copyright remains Eric Young's, and as such any Copyright notices in +the code are not to be removed. +If this package is used in a product, Eric Young should be given attribution +as the author of the parts of the library used. +This can be in the form of a textual message at program startup or +in documentation (online or textual) provided with the package. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + "This product includes cryptographic software written by + Eric Young (eay@cryptsoft.com)" + The word 'cryptographic' can be left out if the rouines from the library + being used are not cryptographic related :-). +4. If you include any Windows specific code (or a derivative thereof) from + the apps directory (application code) you must include an acknowledgement: + "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + +THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +The licence and distribution terms for any publically available version or +derivative of this code cannot be changed. i.e. this code cannot simply be +copied and put under another distribution licence +[including the GNU Public Licence.] + +==================================================================== +Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + +4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + endorse or promote products derived from this software without + prior written permission. For written permission, please contact + openssl-core@openssl.org. + +5. Products derived from this software may not be called "OpenSSL" + nor may "OpenSSL" appear in their names without prior written + permission of the OpenSSL Project. + +6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit (http://www.openssl.org/)" + +THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR +ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/cmake/SelectHTTPSBackend.cmake b/cmake/SelectHTTPSBackend.cmake index afbeac424..4998f0f2a 100644 --- a/cmake/SelectHTTPSBackend.cmake +++ b/cmake/SelectHTTPSBackend.cmake @@ -108,6 +108,10 @@ IF(USE_HTTPS) LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) ELSEIF (USE_HTTPS STREQUAL "WinHTTP") # WinHTTP setup was handled in the WinHTTP-specific block above + ELSEIF (USE_HTTPS STREQUAL "OpenSSL-Dynamic") + SET(GIT_OPENSSL 1) + SET(GIT_OPENSSL_DYNAMIC 1) + LIST(APPEND LIBGIT2_LIBS dl) ELSE() MESSAGE(FATAL_ERROR "Asked for backend ${USE_HTTPS} but it wasn't found") ENDIF() diff --git a/deps/ntlmclient/CMakeLists.txt b/deps/ntlmclient/CMakeLists.txt index d933f4919..3e0d2c817 100644 --- a/deps/ntlmclient/CMakeLists.txt +++ b/deps/ntlmclient/CMakeLists.txt @@ -1,25 +1,37 @@ -FILE(GLOB SRC_NTLMCLIENT "ntlm.c" "unicode_builtin.c" "util.c") +FILE(GLOB SRC_NTLMCLIENT "ntlm.c" "ntlm.h" "util.c" "util.h") LIST(SORT SRC_NTLMCLIENT) ADD_DEFINITIONS(-DNTLM_STATIC=1) DISABLE_WARNINGS(implicit-fallthrough) +IF(USE_ICONV) + ADD_DEFINITIONS(-DUNICODE_ICONV=1) + FILE(GLOB SRC_NTLMCLIENT_UNICODE "unicode_iconv.c" "unicode_iconv.h") +ELSE() + ADD_DEFINITIONS(-DUNICODE_BUILTIN=1) + FILE(GLOB SRC_NTLMCLIENT_UNICODE "unicode_builtin.c" "unicode_builtin.h") +ENDIF() + IF(USE_HTTPS STREQUAL "SecureTransport") ADD_DEFINITIONS(-DCRYPT_COMMONCRYPTO) - SET(SRC_NTLMCLIENT_CRYPTO "crypt_commoncrypto.c") + SET(SRC_NTLMCLIENT_CRYPTO "crypt_commoncrypto.c" "crypt_commoncrypto.h") # CC_MD4 has been deprecated in macOS 10.15. SET_SOURCE_FILES_PROPERTIES("crypt_commoncrypto.c" COMPILE_FLAGS "-Wno-deprecated") ELSEIF(USE_HTTPS STREQUAL "OpenSSL") ADD_DEFINITIONS(-DCRYPT_OPENSSL) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) - SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c") + SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h") +ELSEIF(USE_HTTPS STREQUAL "OpenSSL-Dynamic") + ADD_DEFINITIONS(-DCRYPT_OPENSSL) + ADD_DEFINITIONS(-DCRYPT_OPENSSL_DYNAMIC) + SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h") ELSEIF(USE_HTTPS STREQUAL "mbedTLS") ADD_DEFINITIONS(-DCRYPT_MBEDTLS) INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR}) - SET(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c") + SET(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c" "crypt_mbedtls.h") ELSE() MESSAGE(FATAL_ERROR "Unable to use libgit2's HTTPS backend (${USE_HTTPS}) for NTLM crypto") ENDIF() -ADD_LIBRARY(ntlmclient OBJECT ${SRC_NTLMCLIENT} ${SRC_NTLMCLIENT_CRYPTO}) +ADD_LIBRARY(ntlmclient OBJECT ${SRC_NTLMCLIENT} ${SRC_NTLMCLIENT_UNICODE} ${SRC_NTLMCLIENT_CRYPTO}) diff --git a/deps/ntlmclient/crypt.h b/deps/ntlmclient/crypt.h index 48be39946..4ad543ef7 100644 --- a/deps/ntlmclient/crypt.h +++ b/deps/ntlmclient/crypt.h @@ -9,6 +9,9 @@ #ifndef PRIVATE_CRYPT_COMMON_H__ #define PRIVATE_CRYPT_COMMON_H__ +#include "ntlmclient.h" +#include "ntlm.h" + #if defined(CRYPT_OPENSSL) # include "crypt_openssl.h" #elif defined(CRYPT_MBEDTLS) @@ -25,40 +28,42 @@ typedef unsigned char ntlm_des_block[CRYPT_DES_BLOCKSIZE]; +typedef struct ntlm_crypt_ctx ntlm_crypt_ctx; + +extern bool ntlm_crypt_init(ntlm_client *ntlm); + extern bool ntlm_random_bytes( - ntlm_client *ntlm, unsigned char *out, + ntlm_client *ntlm, size_t len); extern bool ntlm_des_encrypt( ntlm_des_block *out, + ntlm_client *ntlm, ntlm_des_block *plaintext, ntlm_des_block *key); extern bool ntlm_md4_digest( unsigned char out[CRYPT_MD4_DIGESTSIZE], + ntlm_client *ntlm, const unsigned char *in, size_t in_len); -extern ntlm_hmac_ctx *ntlm_hmac_ctx_init(void); - -extern bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx); - extern bool ntlm_hmac_md5_init( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *key, size_t key_len); extern bool ntlm_hmac_md5_update( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *data, size_t data_len); extern bool ntlm_hmac_md5_final( unsigned char *out, size_t *out_len, - ntlm_hmac_ctx *ctx); + ntlm_client *ntlm); -extern void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx); +extern void ntlm_crypt_shutdown(ntlm_client *ntlm); #endif /* PRIVATE_CRYPT_COMMON_H__ */ diff --git a/deps/ntlmclient/crypt_commoncrypto.c b/deps/ntlmclient/crypt_commoncrypto.c index 54a0f097b..4ff57edd2 100644 --- a/deps/ntlmclient/crypt_commoncrypto.c +++ b/deps/ntlmclient/crypt_commoncrypto.c @@ -18,9 +18,15 @@ #include "ntlm.h" #include "crypt.h" +bool ntlm_crypt_init(ntlm_client *ntlm) +{ + memset(&ntlm->crypt_ctx, 0, sizeof(ntlm_crypt_ctx)); + return true; +} + bool ntlm_random_bytes( - ntlm_client *ntlm, unsigned char *out, + ntlm_client *ntlm, size_t len) { int fd, ret; @@ -49,11 +55,14 @@ bool ntlm_random_bytes( bool ntlm_des_encrypt( ntlm_des_block *out, + ntlm_client *ntlm, ntlm_des_block *plaintext, ntlm_des_block *key) { size_t written; + NTLM_UNUSED(ntlm); + CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, sizeof(ntlm_des_block), NULL, @@ -65,56 +74,47 @@ bool ntlm_des_encrypt( bool ntlm_md4_digest( unsigned char out[CRYPT_MD4_DIGESTSIZE], + ntlm_client *ntlm, const unsigned char *in, size_t in_len) { + NTLM_UNUSED(ntlm); return !!CC_MD4(in, in_len, out); } -ntlm_hmac_ctx *ntlm_hmac_ctx_init(void) -{ - return calloc(1, sizeof(ntlm_hmac_ctx)); -} - -bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx) -{ - memset(ctx, 0, sizeof(ntlm_hmac_ctx)); - return true; -} - bool ntlm_hmac_md5_init( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *key, size_t key_len) { - CCHmacInit(&ctx->native, kCCHmacAlgMD5, key, key_len); + CCHmacInit(&ntlm->crypt_ctx.hmac, kCCHmacAlgMD5, key, key_len); return true; } bool ntlm_hmac_md5_update( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *data, size_t data_len) { - CCHmacUpdate(&ctx->native, data, data_len); + CCHmacUpdate(&ntlm->crypt_ctx.hmac, data, data_len); return true; } bool ntlm_hmac_md5_final( unsigned char *out, size_t *out_len, - ntlm_hmac_ctx *ctx) + ntlm_client *ntlm) { if (*out_len < CRYPT_MD5_DIGESTSIZE) return false; - CCHmacFinal(&ctx->native, out); + CCHmacFinal(&ntlm->crypt_ctx.hmac, out); *out_len = CRYPT_MD5_DIGESTSIZE; return true; } -void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx) +void ntlm_crypt_shutdown(ntlm_client *ntlm) { - free(ctx); + NTLM_UNUSED(ntlm); } diff --git a/deps/ntlmclient/crypt_commoncrypto.h b/deps/ntlmclient/crypt_commoncrypto.h index e4075c9f6..e4df91d29 100644 --- a/deps/ntlmclient/crypt_commoncrypto.h +++ b/deps/ntlmclient/crypt_commoncrypto.h @@ -11,8 +11,8 @@ #include <CommonCrypto/CommonCrypto.h> -typedef struct { - CCHmacContext native; -} ntlm_hmac_ctx; +struct ntlm_crypt_ctx { + CCHmacContext hmac; +}; #endif /* PRIVATE_CRYPT_COMMONCRYPTO_H__ */ diff --git a/deps/ntlmclient/crypt_mbedtls.c b/deps/ntlmclient/crypt_mbedtls.c index bbab02d7d..6283c3eec 100644 --- a/deps/ntlmclient/crypt_mbedtls.c +++ b/deps/ntlmclient/crypt_mbedtls.c @@ -17,9 +17,24 @@ #include "ntlm.h" #include "crypt.h" +bool ntlm_crypt_init(ntlm_client *ntlm) +{ + const mbedtls_md_info_t *info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); + + mbedtls_md_init(&ntlm->crypt_ctx.hmac); + + if (mbedtls_md_setup(&ntlm->crypt_ctx.hmac, info, 1) != 0) { + ntlm_client_set_errmsg(ntlm, "could not setup mbedtls digest"); + return false; + } + + return true; +} + + bool ntlm_random_bytes( - ntlm_client *ntlm, unsigned char *out, + ntlm_client *ntlm, size_t len) { mbedtls_ctr_drbg_context ctr_drbg; @@ -51,6 +66,7 @@ bool ntlm_random_bytes( bool ntlm_des_encrypt( ntlm_des_block *out, + ntlm_client *ntlm, ntlm_des_block *plaintext, ntlm_des_block *key) { @@ -60,8 +76,10 @@ bool ntlm_des_encrypt( mbedtls_des_init(&ctx); if (mbedtls_des_setkey_enc(&ctx, *key) || - mbedtls_des_crypt_ecb(&ctx, *plaintext, *out)) + mbedtls_des_crypt_ecb(&ctx, *plaintext, *out)) { + ntlm_client_set_errmsg(ntlm, "DES encryption failed"); goto done; + } success = true; @@ -72,11 +90,14 @@ done: bool ntlm_md4_digest( unsigned char out[CRYPT_MD4_DIGESTSIZE], + ntlm_client *ntlm, const unsigned char *in, size_t in_len) { mbedtls_md4_context ctx; + NTLM_UNUSED(ntlm); + mbedtls_md4_init(&ctx); mbedtls_md4_starts(&ctx); mbedtls_md4_update(&ctx, in, in_len); @@ -86,60 +107,40 @@ bool ntlm_md4_digest( return true; } -ntlm_hmac_ctx *ntlm_hmac_ctx_init(void) -{ - ntlm_hmac_ctx *ctx; - const mbedtls_md_info_t *info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); - - if ((ctx = calloc(1, sizeof(ntlm_hmac_ctx))) == NULL) - return NULL; - - mbedtls_md_init(&ctx->mbed); - - if (mbedtls_md_setup(&ctx->mbed, info, 1) != 0) { - free(ctx); - return false; - } - - return ctx; -} - -bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx) -{ - return !mbedtls_md_hmac_reset(&ctx->mbed); -} - bool ntlm_hmac_md5_init( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *key, size_t key_len) { - return !mbedtls_md_hmac_starts(&ctx->mbed, key, key_len); + if (ntlm->crypt_ctx.hmac_initialized) { + if (mbedtls_md_hmac_reset(&ntlm->crypt_ctx.hmac)) + return false; + } + + ntlm->crypt_ctx.hmac_initialized = !mbedtls_md_hmac_starts(&ntlm->crypt_ctx.hmac, key, key_len); + return ntlm->crypt_ctx.hmac_initialized; } bool ntlm_hmac_md5_update( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *in, size_t in_len) { - return !mbedtls_md_hmac_update(&ctx->mbed, in, in_len); + return !mbedtls_md_hmac_update(&ntlm->crypt_ctx.hmac, in, in_len); } bool ntlm_hmac_md5_final( unsigned char *out, size_t *out_len, - ntlm_hmac_ctx *ctx) + ntlm_client *ntlm) { if (*out_len < CRYPT_MD5_DIGESTSIZE) return false; - return !mbedtls_md_hmac_finish(&ctx->mbed, out); + return !mbedtls_md_hmac_finish(&ntlm->crypt_ctx.hmac, out); } -void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx) +void ntlm_crypt_shutdown(ntlm_client *ntlm) { - if (ctx) { - mbedtls_md_free(&ctx->mbed); - free(ctx); - } + mbedtls_md_free(&ntlm->crypt_ctx.hmac); } diff --git a/deps/ntlmclient/crypt_mbedtls.h b/deps/ntlmclient/crypt_mbedtls.h index eb49a4596..2fc85035d 100644 --- a/deps/ntlmclient/crypt_mbedtls.h +++ b/deps/ntlmclient/crypt_mbedtls.h @@ -11,8 +11,9 @@ #include "mbedtls/md.h" -typedef struct { - mbedtls_md_context_t mbed; -} ntlm_hmac_ctx; +struct ntlm_crypt_ctx { + mbedtls_md_context_t hmac; + unsigned int hmac_initialized : 1; +}; #endif /* PRIVATE_CRYPT_MBEDTLS_H__ */ diff --git a/deps/ntlmclient/crypt_openssl.c b/deps/ntlmclient/crypt_openssl.c index c0d36d891..463eae4f8 100644 --- a/deps/ntlmclient/crypt_openssl.c +++ b/deps/ntlmclient/crypt_openssl.c @@ -9,26 +9,166 @@ #include <stdlib.h> #include <string.h> -#include <openssl/rand.h> -#include <openssl/des.h> -#include <openssl/md4.h> -#include <openssl/hmac.h> -#include <openssl/err.h> +#ifdef CRYPT_OPENSSL_DYNAMIC +# include <dlfcn.h> +#else +# include <openssl/rand.h> +# include <openssl/des.h> +# include <openssl/md4.h> +# include <openssl/hmac.h> +# include <openssl/err.h> +#endif #include "ntlm.h" #include "compat.h" #include "util.h" #include "crypt.h" +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(CRYPT_OPENSSL_DYNAMIC) + +static inline HMAC_CTX *HMAC_CTX_new(void) +{ + return calloc(1, sizeof(HMAC_CTX)); +} + +static inline int HMAC_CTX_reset(HMAC_CTX *ctx) +{ + ntlm_memzero(ctx, sizeof(HMAC_CTX)); + return 1; +} + +static inline void HMAC_CTX_free(HMAC_CTX *ctx) +{ + free(ctx); +} + +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(CRYPT_OPENSSL_DYNAMIC) + +static inline void HMAC_CTX_cleanup(HMAC_CTX *ctx) +{ + NTLM_UNUSED(ctx); +} + +#endif + + +#ifdef CRYPT_OPENSSL_DYNAMIC + +static bool ntlm_crypt_init_functions(ntlm_client *ntlm) +{ + void *handle; + + if ((handle = dlopen("libssl.so.1.1", RTLD_NOW)) == NULL && + (handle = dlopen("libssl.1.1.dylib", RTLD_NOW)) == NULL && + (handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL && + (handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL && + (handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL) { + ntlm_client_set_errmsg(ntlm, "could not open libssl"); + return false; + } + + ntlm->crypt_ctx.des_set_key_fn = dlsym(handle, "DES_set_key"); + ntlm->crypt_ctx.des_ecb_encrypt_fn = dlsym(handle, "DES_ecb_encrypt"); + ntlm->crypt_ctx.err_get_error_fn = dlsym(handle, "ERR_get_error"); + ntlm->crypt_ctx.err_lib_error_string_fn = dlsym(handle, "ERR_lib_error_string"); + ntlm->crypt_ctx.evp_md5_fn = dlsym(handle, "EVP_md5"); + ntlm->crypt_ctx.hmac_ctx_new_fn = dlsym(handle, "HMAC_CTX_new"); + ntlm->crypt_ctx.hmac_ctx_free_fn = dlsym(handle, "HMAC_CTX_free"); + ntlm->crypt_ctx.hmac_ctx_reset_fn = dlsym(handle, "HMAC_CTX_reset"); + ntlm->crypt_ctx.hmac_init_ex_fn = dlsym(handle, "HMAC_Init_ex"); + ntlm->crypt_ctx.hmac_update_fn = dlsym(handle, "HMAC_Update"); + ntlm->crypt_ctx.hmac_final_fn = dlsym(handle, "HMAC_Final"); + ntlm->crypt_ctx.md4_fn = dlsym(handle, "MD4"); + ntlm->crypt_ctx.rand_bytes_fn = dlsym(handle, "RAND_bytes"); + + if (!ntlm->crypt_ctx.des_set_key_fn || + !ntlm->crypt_ctx.des_ecb_encrypt_fn || + !ntlm->crypt_ctx.err_get_error_fn || + !ntlm->crypt_ctx.err_lib_error_string_fn || + !ntlm->crypt_ctx.evp_md5_fn || + !ntlm->crypt_ctx.hmac_init_ex_fn || + !ntlm->crypt_ctx.hmac_update_fn || + !ntlm->crypt_ctx.hmac_final_fn || + !ntlm->crypt_ctx.md4_fn || + !ntlm->crypt_ctx.rand_bytes_fn) { + ntlm_client_set_errmsg(ntlm, "could not load libssl functions"); + dlclose(handle); + return false; + } + + /* Toggle legacy HMAC context functions */ + if (ntlm->crypt_ctx.hmac_ctx_new_fn && + ntlm->crypt_ctx.hmac_ctx_free_fn && + ntlm->crypt_ctx.hmac_ctx_reset_fn) { + ntlm->crypt_ctx.hmac_ctx_cleanup_fn = HMAC_CTX_cleanup; + } else { + ntlm->crypt_ctx.hmac_ctx_cleanup_fn = dlsym(handle, "HMAC_CTX_cleanup"); + + if (!ntlm->crypt_ctx.hmac_ctx_cleanup_fn) { + ntlm_client_set_errmsg(ntlm, "could not load legacy libssl functions"); + dlclose(handle); + return false; + } + + ntlm->crypt_ctx.hmac_ctx_new_fn = HMAC_CTX_new; + ntlm->crypt_ctx.hmac_ctx_free_fn = HMAC_CTX_free; + ntlm->crypt_ctx.hmac_ctx_reset_fn = HMAC_CTX_reset; + } + + ntlm->crypt_ctx.openssl_handle = handle; + return true; +} + +#else /* CRYPT_OPENSSL_DYNAMIC */ + +static bool ntlm_crypt_init_functions(ntlm_client *ntlm) +{ + ntlm->crypt_ctx.des_set_key_fn = DES_set_key; + ntlm->crypt_ctx.des_ecb_encrypt_fn = DES_ecb_encrypt; + ntlm->crypt_ctx.err_get_error_fn = ERR_get_error; + ntlm->crypt_ctx.err_lib_error_string_fn = ERR_lib_error_string; + ntlm->crypt_ctx.evp_md5_fn = EVP_md5; + ntlm->crypt_ctx.hmac_ctx_new_fn = HMAC_CTX_new; + ntlm->crypt_ctx.hmac_ctx_free_fn = HMAC_CTX_free; + ntlm->crypt_ctx.hmac_ctx_reset_fn = HMAC_CTX_reset; + ntlm->crypt_ctx.hmac_ctx_cleanup_fn = HMAC_CTX_cleanup; + ntlm->crypt_ctx.hmac_init_ex_fn = HMAC_Init_ex; + ntlm->crypt_ctx.hmac_update_fn = HMAC_Update; + ntlm->crypt_ctx.hmac_final_fn = HMAC_Final; + ntlm->crypt_ctx.md4_fn = MD4; + ntlm->crypt_ctx.rand_bytes_fn = RAND_bytes; + + return true; +} + +#endif /* CRYPT_OPENSSL_DYNAMIC */ + +bool ntlm_crypt_init(ntlm_client *ntlm) +{ + if (!ntlm_crypt_init_functions(ntlm)) + return false; + + ntlm->crypt_ctx.hmac = ntlm->crypt_ctx.hmac_ctx_new_fn(); + + if (ntlm->crypt_ctx.hmac == NULL) { + ntlm_client_set_errmsg(ntlm, "out of memory"); + return false; + } + + return true; +} + bool ntlm_random_bytes( - ntlm_client *ntlm, unsigned char *out, + ntlm_client *ntlm, size_t len) { - int rc = RAND_bytes(out, len); + int rc = ntlm->crypt_ctx.rand_bytes_fn(out, len); if (rc != 1) { - ntlm_client_set_errmsg(ntlm, ERR_lib_error_string(ERR_get_error())); + ntlm_client_set_errmsg(ntlm, ntlm->crypt_ctx.err_lib_error_string_fn(ntlm->crypt_ctx.err_get_error_fn())); return false; } @@ -37,94 +177,81 @@ bool ntlm_random_bytes( bool ntlm_des_encrypt( ntlm_des_block *out, + ntlm_client *ntlm, ntlm_des_block *plaintext, ntlm_des_block *key) { DES_key_schedule keysched; + NTLM_UNUSED(ntlm); + memset(out, 0, sizeof(ntlm_des_block)); - DES_set_key(key, &keysched); - DES_ecb_encrypt(plaintext, out, &keysched, DES_ENCRYPT); + ntlm->crypt_ctx.des_set_key_fn(key, &keysched); + ntlm->crypt_ctx.des_ecb_encrypt_fn(plaintext, out, &keysched, DES_ENCRYPT); return true; } bool ntlm_md4_digest( unsigned char out[CRYPT_MD4_DIGESTSIZE], + ntlm_client *ntlm, const unsigned char *in, size_t in_len) { - MD4(in, in_len, out); + ntlm->crypt_ctx.md4_fn(in, in_len, out); return true; } -#if OPENSSL_VERSION_NUMBER < 0x10100000L -static inline void HMAC_CTX_free(HMAC_CTX *ctx) -{ - if (ctx) - HMAC_CTX_cleanup(ctx); - - free(ctx); -} - -static inline int HMAC_CTX_reset(HMAC_CTX *ctx) -{ - HMAC_CTX_cleanup(ctx); - ntlm_memzero(ctx, sizeof(HMAC_CTX)); - return 1; -} - -static inline HMAC_CTX *HMAC_CTX_new(void) -{ - return calloc(1, sizeof(HMAC_CTX)); -} -#endif - -ntlm_hmac_ctx *ntlm_hmac_ctx_init(void) -{ - return HMAC_CTX_new(); -} - -bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx) -{ - return HMAC_CTX_reset(ctx); -} - bool ntlm_hmac_md5_init( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *key, size_t key_len) { - return HMAC_Init_ex(ctx, key, key_len, EVP_md5(), NULL); + const EVP_MD *md5 = ntlm->crypt_ctx.evp_md5_fn(); + + ntlm->crypt_ctx.hmac_ctx_cleanup_fn(ntlm->crypt_ctx.hmac); + + return ntlm->crypt_ctx.hmac_ctx_reset_fn(ntlm->crypt_ctx.hmac) && + ntlm->crypt_ctx.hmac_init_ex_fn(ntlm->crypt_ctx.hmac, key, key_len, md5, NULL); } bool ntlm_hmac_md5_update( - ntlm_hmac_ctx *ctx, + ntlm_client *ntlm, const unsigned char *in, size_t in_len) { - return HMAC_Update(ctx, in, in_len); + return ntlm->crypt_ctx.hmac_update_fn(ntlm->crypt_ctx.hmac, in, in_len); } bool ntlm_hmac_md5_final( unsigned char *out, size_t *out_len, - ntlm_hmac_ctx *ctx) + ntlm_client *ntlm) { unsigned int len; if (*out_len < CRYPT_MD5_DIGESTSIZE) return false; - if (!HMAC_Final(ctx, out, &len)) + if (!ntlm->crypt_ctx.hmac_final_fn(ntlm->crypt_ctx.hmac, out, &len)) return false; *out_len = len; return true; } -void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx) +void ntlm_crypt_shutdown(ntlm_client *ntlm) { - HMAC_CTX_free(ctx); + if (ntlm->crypt_ctx.hmac) { + ntlm->crypt_ctx.hmac_ctx_cleanup_fn(ntlm->crypt_ctx.hmac); + ntlm->crypt_ctx.hmac_ctx_free_fn(ntlm->crypt_ctx.hmac); + } + +#ifdef CRYPT_OPENSSL_DYNAMIC + if (ntlm->crypt_ctx.openssl_handle) + dlclose(ntlm->crypt_ctx.openssl_handle); +#endif + + memset(&ntlm->crypt_ctx, 0, sizeof(ntlm_crypt_ctx)); } diff --git a/deps/ntlmclient/crypt_openssl.h b/deps/ntlmclient/crypt_openssl.h index 4195db9a5..8654027db 100644 --- a/deps/ntlmclient/crypt_openssl.h +++ b/deps/ntlmclient/crypt_openssl.h @@ -9,13 +9,82 @@ #ifndef PRIVATE_CRYPT_OPENSSL_H__ #define PRIVATE_CRYPT_OPENSSL_H__ -#include <openssl/hmac.h> +#ifndef CRYPT_OPENSSL_DYNAMIC +# include <openssl/des.h> +# include <openssl/hmac.h> +#endif /* OpenSSL 1.1.0 uses opaque structs, we'll reuse these. */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L -typedef struct hmac_ctx_st ntlm_hmac_ctx; -#else -# define ntlm_hmac_ctx HMAC_CTX +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L +# define HMAC_CTX struct hmac_ctx_st +#endif + +#ifdef CRYPT_OPENSSL_DYNAMIC +typedef unsigned char DES_cblock[8]; +typedef unsigned char const_DES_cblock[8]; + +typedef unsigned long DES_LONG; + +typedef struct DES_ks { + union { + DES_cblock cblock; + DES_LONG deslong[2]; + } ks[16]; +} DES_key_schedule; + +#define DES_ENCRYPT 1 + +typedef void EVP_MD; +typedef void ENGINE; +typedef void EVP_PKEY_CTX; + +#define HMAC_MAX_MD_CBLOCK 128 + +typedef struct env_md_ctx_st EVP_MD_CTX; +struct env_md_ctx_st { + const EVP_MD *digest; + ENGINE *engine; + unsigned long flags; + void *md_data; + EVP_PKEY_CTX *pctx; + int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); +}; + +typedef struct hmac_ctx_st { + const EVP_MD *md; + EVP_MD_CTX md_ctx; + EVP_MD_CTX i_ctx; + EVP_MD_CTX o_ctx; + unsigned int key_length; + unsigned char key[HMAC_MAX_MD_CBLOCK]; +} HMAC_CTX; #endif +struct ntlm_crypt_ctx { + HMAC_CTX *hmac; + + void *openssl_handle; + + void (*des_ecb_encrypt_fn)(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks, int enc); + int (*des_set_key_fn)(const_DES_cblock *key, DES_key_schedule *schedule); + + unsigned long (*err_get_error_fn)(void); + const char *(*err_lib_error_string_fn)(unsigned long e); + + const EVP_MD *(*evp_md5_fn)(void); + + HMAC_CTX *(*hmac_ctx_new_fn)(void); + int (*hmac_ctx_reset_fn)(HMAC_CTX *ctx); + void (*hmac_ctx_free_fn)(HMAC_CTX *ctx); + void (*hmac_ctx_cleanup_fn)(HMAC_CTX *ctx); + + int (*hmac_init_ex_fn)(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl); + int (*hmac_update_fn)(HMAC_CTX *ctx, const unsigned char *data, size_t len); + int (*hmac_final_fn)(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); + + unsigned char *(*md4_fn)(const unsigned char *d, size_t n, unsigned char *md); + + int (*rand_bytes_fn)(unsigned char *buf, int num); +}; + #endif /* PRIVATE_CRYPT_OPENSSL_H__ */ diff --git a/deps/ntlmclient/ntlm.c b/deps/ntlmclient/ntlm.c index 470a90143..3393be915 100644 --- a/deps/ntlmclient/ntlm.c +++ b/deps/ntlmclient/ntlm.c @@ -9,7 +9,6 @@ #include <stdlib.h> #include <stdint.h> #include <string.h> -#include <assert.h> #include <errno.h> #include <ctype.h> #include <unistd.h> @@ -24,6 +23,18 @@ #include "compat.h" #include "util.h" +#define NTLM_ASSERT_ARG(expr) do { \ + if (!(expr)) \ + return NTLM_CLIENT_ERROR_INVALID_INPUT; \ + } while(0) + +#define NTLM_ASSERT(ntlm, expr) do { \ + if (!(expr)) { \ + ntlm_client_set_errmsg(ntlm, "internal error: " #expr); \ + return -1; \ + } \ + } while(0) + unsigned char ntlm_client_signature[] = NTLM_SIGNATURE; static bool supports_unicode(ntlm_client *ntlm) @@ -52,17 +63,20 @@ ntlm_client *ntlm_client_init(ntlm_client_flags flags) ntlm->flags = flags; - if ((ntlm->hmac_ctx = ntlm_hmac_ctx_init()) == NULL || - (ntlm->unicode_ctx = ntlm_unicode_ctx_init(ntlm)) == NULL) { - ntlm_hmac_ctx_free(ntlm->hmac_ctx); - ntlm_unicode_ctx_free(ntlm->unicode_ctx); - free(ntlm); - return NULL; - } - return ntlm; } +#define ENSURE_INITIALIZED(ntlm) \ + do { \ + if (!(ntlm)->unicode_initialized) \ + (ntlm)->unicode_initialized = ntlm_unicode_init((ntlm)); \ + if (!(ntlm)->crypt_initialized) \ + (ntlm)->crypt_initialized = ntlm_crypt_init((ntlm)); \ + if (!(ntlm)->unicode_initialized || \ + !(ntlm)->crypt_initialized) \ + return -1; \ + } while(0) + void ntlm_client_set_errmsg(ntlm_client *ntlm, const char *errmsg) { ntlm->state = NTLM_STATE_ERROR; @@ -71,7 +85,9 @@ void ntlm_client_set_errmsg(ntlm_client *ntlm, const char *errmsg) const char *ntlm_client_errmsg(ntlm_client *ntlm) { - assert(ntlm); + if (!ntlm) + return "internal error"; + return ntlm->errmsg ? ntlm->errmsg : "no error"; } @@ -81,7 +97,7 @@ int ntlm_client_set_version( uint8_t minor, uint16_t build) { - assert(ntlm); + NTLM_ASSERT_ARG(ntlm); ntlm->host_version.major = major; ntlm->host_version.minor = minor; @@ -93,20 +109,25 @@ int ntlm_client_set_version( return 0; } +#define reset(ptr) do { free(ptr); ptr = NULL; } while(0) + +static void free_hostname(ntlm_client *ntlm) +{ + reset(ntlm->hostname); + reset(ntlm->hostdomain); + reset(ntlm->hostname_utf16); + ntlm->hostname_utf16_len = 0; +} + int ntlm_client_set_hostname( ntlm_client *ntlm, const char *hostname, const char *domain) { - assert(ntlm); + NTLM_ASSERT_ARG(ntlm); + ENSURE_INITIALIZED(ntlm); - free(ntlm->hostname); - free(ntlm->hostdomain); - free(ntlm->hostname_utf16); - - ntlm->hostname = NULL; - ntlm->hostdomain = NULL; - ntlm->hostname_utf16 = NULL; + free_hostname(ntlm); if (hostname && (ntlm->hostname = strdup(hostname)) == NULL) { ntlm_client_set_errmsg(ntlm, "out of memory"); @@ -121,7 +142,7 @@ int ntlm_client_set_hostname( if (hostname && supports_unicode(ntlm) && !ntlm_unicode_utf8_to_16( &ntlm->hostname_utf16, &ntlm->hostname_utf16_len, - ntlm->unicode_ctx, + ntlm, hostname, strlen(hostname))) return -1; @@ -137,25 +158,20 @@ static void free_credentials(ntlm_client *ntlm) if (ntlm->password_utf16) ntlm_memzero(ntlm->password_utf16, ntlm->password_utf16_len); - free(ntlm->username); - free(ntlm->username_upper); - free(ntlm->userdomain); - free(ntlm->password); - - free(ntlm->username_utf16); - free(ntlm->username_upper_utf16); - free(ntlm->userdomain_utf16); - free(ntlm->password_utf16); - - ntlm->username = NULL; - ntlm->username_upper = NULL; - ntlm->userdomain = NULL; - ntlm->password = NULL; - - ntlm->username_utf16 = NULL; - ntlm->username_upper_utf16 = NULL; - ntlm->userdomain_utf16 = NULL; - ntlm->password_utf16 = NULL; + reset(ntlm->username); + reset(ntlm->username_upper); + reset(ntlm->userdomain); + reset(ntlm->password); + + reset(ntlm->username_utf16); + reset(ntlm->username_upper_utf16); + reset(ntlm->userdomain_utf16); + reset(ntlm->password_utf16); + + ntlm->username_utf16_len = 0; + ntlm->username_upper_utf16_len = 0; + ntlm->userdomain_utf16_len = 0; + ntlm->password_utf16_len = 0; } int ntlm_client_set_credentials( @@ -164,7 +180,8 @@ int ntlm_client_set_credentials( const char *domain, const char *password) { - assert(ntlm); + NTLM_ASSERT_ARG(ntlm); + ENSURE_INITIALIZED(ntlm); free_credentials(ntlm); @@ -185,7 +202,7 @@ int ntlm_client_set_credentials( if (!ntlm_unicode_utf8_to_16( &ntlm->username_utf16, &ntlm->username_utf16_len, - ntlm->unicode_ctx, + ntlm, ntlm->username, strlen(ntlm->username))) return -1; @@ -193,7 +210,7 @@ int ntlm_client_set_credentials( if (!ntlm_unicode_utf8_to_16( &ntlm->username_upper_utf16, &ntlm->username_upper_utf16_len, - ntlm->unicode_ctx, + ntlm, ntlm->username_upper, strlen(ntlm->username_upper))) return -1; @@ -202,7 +219,7 @@ int ntlm_client_set_credentials( if (domain && supports_unicode(ntlm) && !ntlm_unicode_utf8_to_16( &ntlm->userdomain_utf16, &ntlm->userdomain_utf16_len, - ntlm->unicode_ctx, + ntlm, ntlm->userdomain, strlen(ntlm->userdomain))) return -1; @@ -212,7 +229,8 @@ int ntlm_client_set_credentials( int ntlm_client_set_target(ntlm_client *ntlm, const char *target) { - assert(ntlm); + NTLM_ASSERT_ARG(ntlm); + ENSURE_INITIALIZED(ntlm); free(ntlm->target); free(ntlm->target_utf16); @@ -229,7 +247,7 @@ int ntlm_client_set_target(ntlm_client *ntlm, const char *target) if (supports_unicode(ntlm) && !ntlm_unicode_utf8_to_16( &ntlm->target_utf16, &ntlm->target_utf16_len, - ntlm->unicode_ctx, + ntlm, ntlm->target, strlen(ntlm->target))) return -1; @@ -240,14 +258,16 @@ int ntlm_client_set_target(ntlm_client *ntlm, const char *target) int ntlm_client_set_nonce(ntlm_client *ntlm, uint64_t nonce) { - assert(ntlm); + NTLM_ASSERT_ARG(ntlm); + ntlm->nonce = nonce; return 0; } int ntlm_client_set_timestamp(ntlm_client *ntlm, uint64_t timestamp) { - assert(ntlm); + NTLM_ASSERT_ARG(ntlm); + ntlm->timestamp = timestamp; return 0; } @@ -475,7 +495,7 @@ static inline bool read_string_unicode( size_t out_len; int ret = ntlm_unicode_utf16_to_8(out, &out_len, - ntlm->unicode_ctx, + ntlm, (char *)&message->buf[message->pos], string_len); @@ -593,7 +613,9 @@ int ntlm_client_negotiate( size_t hostname_offset = 0; uint32_t flags = 0; - assert(out && out_len && ntlm); + NTLM_ASSERT_ARG(out); + NTLM_ASSERT_ARG(out_len); + NTLM_ASSERT_ARG(ntlm); *out = NULL; *out_len = 0; @@ -676,20 +698,22 @@ int ntlm_client_negotiate( return -1; if (hostname_len > 0) { - assert(hostname_offset == ntlm->negotiate.pos); + NTLM_ASSERT(ntlm, hostname_offset == ntlm->negotiate.pos); + if (!write_buf(ntlm, &ntlm->negotiate, (const unsigned char *)ntlm->hostname, hostname_len)) return -1; } if (domain_len > 0) { - assert(domain_offset == ntlm->negotiate.pos); + NTLM_ASSERT(ntlm, domain_offset == ntlm->negotiate.pos); + if (!write_buf(ntlm, &ntlm->negotiate, (const unsigned char *)ntlm->hostdomain, domain_len)) return -1; } - assert(ntlm->negotiate.pos == ntlm->negotiate.len); + NTLM_ASSERT(ntlm, ntlm->negotiate.pos == ntlm->negotiate.len); ntlm->state = NTLM_STATE_CHALLENGE; @@ -711,7 +735,10 @@ int ntlm_client_set_challenge( uint32_t name_offset, info_offset = 0; bool unicode, has_target_info = false; - assert(ntlm && (challenge_msg || !challenge_msg_len)); + NTLM_ASSERT_ARG(ntlm); + NTLM_ASSERT_ARG(challenge_msg || !challenge_msg_len); + + ENSURE_INITIALIZED(ntlm); if (ntlm->state != NTLM_STATE_NEGOTIATE && ntlm->state != NTLM_STATE_CHALLENGE) { @@ -940,6 +967,7 @@ static void des_key_from_password( static inline bool generate_lm_hash( ntlm_des_block out[2], + ntlm_client *ntlm, const char *password) { /* LM encrypts this known plaintext using the password as a key */ @@ -968,8 +996,8 @@ static inline bool generate_lm_hash( des_key_from_password(&key1, keystr1, keystr1_len); des_key_from_password(&key2, keystr2, keystr2_len); - return ntlm_des_encrypt(&out[0], &plaintext, &key1) && - ntlm_des_encrypt(&out[1], &plaintext, &key2); + return ntlm_des_encrypt(&out[0], ntlm, &plaintext, &key1) && + ntlm_des_encrypt(&out[1], ntlm, &plaintext, &key2); } static void des_keys_from_lm_hash(ntlm_des_block out[3], ntlm_des_block lm_hash[2]) @@ -994,16 +1022,16 @@ static bool generate_lm_response(ntlm_client *ntlm) ntlm_des_block *challenge = (ntlm_des_block *)&ntlm->challenge.nonce; /* Generate the LM hash from the password */ - if (!generate_lm_hash(lm_hash, ntlm->password)) + if (!generate_lm_hash(lm_hash, ntlm, ntlm->password)) return false; /* Convert that LM hash to three DES keys */ des_keys_from_lm_hash(key, lm_hash); /* Finally, encrypt the challenge with each of these keys */ - if (!ntlm_des_encrypt(&lm_response[0], challenge, &key[0]) || - !ntlm_des_encrypt(&lm_response[1], challenge, &key[1]) || - !ntlm_des_encrypt(&lm_response[2], challenge, &key[2])) + if (!ntlm_des_encrypt(&lm_response[0], ntlm, challenge, &key[0]) || + !ntlm_des_encrypt(&lm_response[1], ntlm, challenge, &key[1]) || + !ntlm_des_encrypt(&lm_response[2], ntlm, challenge, &key[2])) return false; memcpy(&ntlm->lm_response[0], lm_response[0], 8); @@ -1022,12 +1050,13 @@ static bool generate_ntlm_hash( if (ntlm->password && !ntlm_unicode_utf8_to_16( &ntlm->password_utf16, &ntlm->password_utf16_len, - ntlm->unicode_ctx, + ntlm, ntlm->password, strlen(ntlm->password))) return false; return ntlm_md4_digest(out, + ntlm, (const unsigned char *)ntlm->password_utf16, ntlm->password_utf16_len); } @@ -1048,9 +1077,9 @@ static bool generate_ntlm_response(ntlm_client *ntlm) des_key_from_password(&key[2], &ntlm_hash[14], 2); /* Finally, encrypt the challenge with each of these keys */ - if (!ntlm_des_encrypt(&ntlm_response[0], challenge, &key[0]) || - !ntlm_des_encrypt(&ntlm_response[1], challenge, &key[1]) || - !ntlm_des_encrypt(&ntlm_response[2], challenge, &key[2])) + if (!ntlm_des_encrypt(&ntlm_response[0], ntlm, challenge, &key[0]) || + !ntlm_des_encrypt(&ntlm_response[1], ntlm, challenge, &key[1]) || + !ntlm_des_encrypt(&ntlm_response[2], ntlm, challenge, &key[2])) return false; memcpy(&ntlm->ntlm_response[0], ntlm_response[0], 8); @@ -1081,16 +1110,15 @@ static bool generate_ntlm2_hash( target_len = ntlm->target_utf16_len; } - if (!ntlm_hmac_ctx_reset(ntlm->hmac_ctx) || - !ntlm_hmac_md5_init(ntlm->hmac_ctx, ntlm_hash, sizeof(ntlm_hash)) || - !ntlm_hmac_md5_update(ntlm->hmac_ctx, username, username_len) || - !ntlm_hmac_md5_update(ntlm->hmac_ctx, target, target_len) || - !ntlm_hmac_md5_final(out, &out_len, ntlm->hmac_ctx)) { + if (!ntlm_hmac_md5_init(ntlm, ntlm_hash, sizeof(ntlm_hash)) || + !ntlm_hmac_md5_update(ntlm, username, username_len) || + !ntlm_hmac_md5_update(ntlm, target, target_len) || + !ntlm_hmac_md5_final(out, &out_len, ntlm)) { ntlm_client_set_errmsg(ntlm, "failed to create HMAC-MD5"); return false; } - assert(out_len == NTLM_NTLM2_HASH_LEN); + NTLM_ASSERT(ntlm, out_len == NTLM_NTLM2_HASH_LEN); return true; } @@ -1103,18 +1131,15 @@ static bool generate_ntlm2_challengehash( { size_t out_len = 16; - if (!ntlm_hmac_ctx_reset(ntlm->hmac_ctx) || - !ntlm_hmac_md5_init(ntlm->hmac_ctx, - ntlm2_hash, NTLM_NTLM2_HASH_LEN) || - !ntlm_hmac_md5_update(ntlm->hmac_ctx, - (const unsigned char *)&ntlm->challenge.nonce, 8) || - !ntlm_hmac_md5_update(ntlm->hmac_ctx, blob, blob_len) || - !ntlm_hmac_md5_final(out, &out_len, ntlm->hmac_ctx)) { + if (!ntlm_hmac_md5_init(ntlm, ntlm2_hash, NTLM_NTLM2_HASH_LEN) || + !ntlm_hmac_md5_update(ntlm, (const unsigned char *)&ntlm->challenge.nonce, 8) || + !ntlm_hmac_md5_update(ntlm, blob, blob_len) || + !ntlm_hmac_md5_final(out, &out_len, ntlm)) { ntlm_client_set_errmsg(ntlm, "failed to create HMAC-MD5"); return false; } - assert(out_len == 16); + NTLM_ASSERT(ntlm, out_len == 16); return true; } @@ -1127,19 +1152,15 @@ static bool generate_lm2_response(ntlm_client *ntlm, local_nonce = ntlm_htonll(ntlm->nonce); - if (!ntlm_hmac_ctx_reset(ntlm->hmac_ctx) || - !ntlm_hmac_md5_init(ntlm->hmac_ctx, - ntlm2_hash, NTLM_NTLM2_HASH_LEN) || - !ntlm_hmac_md5_update(ntlm->hmac_ctx, - (const unsigned char *)&ntlm->challenge.nonce, 8) || - !ntlm_hmac_md5_update(ntlm->hmac_ctx, - (const unsigned char *)&local_nonce, 8) || - !ntlm_hmac_md5_final(lm2_challengehash, &lm2_len, ntlm->hmac_ctx)) { + if (!ntlm_hmac_md5_init(ntlm, ntlm2_hash, NTLM_NTLM2_HASH_LEN) || + !ntlm_hmac_md5_update(ntlm, (const unsigned char *)&ntlm->challenge.nonce, 8) || + !ntlm_hmac_md5_update(ntlm, (const unsigned char *)&local_nonce, 8) || + !ntlm_hmac_md5_final(lm2_challengehash, &lm2_len, ntlm)) { ntlm_client_set_errmsg(ntlm, "failed to create HMAC-MD5"); return false; } - assert(lm2_len == 16); + NTLM_ASSERT(ntlm, lm2_len == 16); memcpy(&ntlm->lm_response[0], lm2_challengehash, 16); memcpy(&ntlm->lm_response[16], &local_nonce, 8); @@ -1163,7 +1184,7 @@ static bool generate_nonce(ntlm_client *ntlm) if (ntlm->nonce) return true; - if (!ntlm_random_bytes(ntlm, buf, 8)) + if (!ntlm_random_bytes(buf, ntlm, 8)) return false; memcpy(&ntlm->nonce, buf, sizeof(uint64_t)); @@ -1233,7 +1254,11 @@ int ntlm_client_response( uint32_t flags = 0; bool unicode; - assert(out && out_len && ntlm); + NTLM_ASSERT_ARG(out); + NTLM_ASSERT_ARG(out_len); + NTLM_ASSERT_ARG(ntlm); + + ENSURE_INITIALIZED(ntlm); *out = NULL; *out_len = 0; @@ -1356,7 +1381,7 @@ int ntlm_client_response( !write_buf(ntlm, &ntlm->response, session, session_len)) return -1; - assert(ntlm->response.pos == ntlm->response.len); + NTLM_ASSERT(ntlm, ntlm->response.pos == ntlm->response.len); ntlm->state = NTLM_STATE_COMPLETE; @@ -1368,41 +1393,48 @@ int ntlm_client_response( void ntlm_client_reset(ntlm_client *ntlm) { - ntlm_client_flags flags; - ntlm_hmac_ctx *hmac_ctx; - ntlm_unicode_ctx *unicode_ctx; - - assert(ntlm); + if (!ntlm) + return; - free(ntlm->negotiate.buf); - free(ntlm->challenge.target_info); - free(ntlm->challenge.target); - free(ntlm->challenge.target_domain); - free(ntlm->challenge.target_domain_dns); - free(ntlm->challenge.target_server); - free(ntlm->challenge.target_server_dns); - free(ntlm->response.buf); + ntlm->state = NTLM_STATE_NEGOTIATE; - free(ntlm->hostname); - free(ntlm->hostname_utf16); - free(ntlm->hostdomain); + free_hostname(ntlm); - free(ntlm->target); - free(ntlm->target_utf16); + memset(&ntlm->host_version, 0, sizeof(ntlm_version)); - free(ntlm->ntlm2_response); + reset(ntlm->target); + reset(ntlm->target_utf16); + ntlm->target_utf16_len = 0; free_credentials(ntlm); - flags = ntlm->flags; - hmac_ctx = ntlm->hmac_ctx; - unicode_ctx = ntlm->unicode_ctx; + ntlm->nonce = 0; + ntlm->timestamp = 0; - memset(ntlm, 0, sizeof(struct ntlm_client)); + memset(ntlm->lm_response, 0, NTLM_LM_RESPONSE_LEN); + ntlm->lm_response_len = 0; - ntlm->flags = flags; - ntlm->hmac_ctx = hmac_ctx; - ntlm->unicode_ctx = unicode_ctx; + memset(ntlm->ntlm_response, 0, NTLM_NTLM_RESPONSE_LEN); + ntlm->ntlm_response_len = 0; + + reset(ntlm->ntlm2_response); + ntlm->ntlm2_response_len = 0; + + reset(ntlm->negotiate.buf); + ntlm->negotiate.pos = 0; + ntlm->negotiate.len = 0; + + reset(ntlm->response.buf); + ntlm->response.pos = 0; + ntlm->response.len = 0; + + free(ntlm->challenge.target_info); + free(ntlm->challenge.target); + free(ntlm->challenge.target_domain); + free(ntlm->challenge.target_domain_dns); + free(ntlm->challenge.target_server); + free(ntlm->challenge.target_server_dns); + memset(&ntlm->challenge, 0, sizeof(ntlm_challenge)); } void ntlm_client_free(ntlm_client *ntlm) @@ -1410,10 +1442,10 @@ void ntlm_client_free(ntlm_client *ntlm) if (!ntlm) return; - ntlm_client_reset(ntlm); + ntlm_crypt_shutdown(ntlm); + ntlm_unicode_shutdown(ntlm); - ntlm_hmac_ctx_free(ntlm->hmac_ctx); - ntlm_unicode_ctx_free(ntlm->unicode_ctx); + ntlm_client_reset(ntlm); free(ntlm); } diff --git a/deps/ntlmclient/ntlm.h b/deps/ntlmclient/ntlm.h index 0dad91ec0..227f5bcba 100644 --- a/deps/ntlmclient/ntlm.h +++ b/deps/ntlmclient/ntlm.h @@ -14,6 +14,8 @@ #include "crypt.h" #include "compat.h" +#define NTLM_UNUSED(x) ((void)(x)) + #define NTLM_LM_RESPONSE_LEN 24 #define NTLM_NTLM_RESPONSE_LEN 24 #define NTLM_NTLM_HASH_LEN 16 @@ -66,9 +68,11 @@ struct ntlm_client { ntlm_state state; - /* crypto contexts */ - ntlm_hmac_ctx *hmac_ctx; - ntlm_unicode_ctx *unicode_ctx; + /* subsystem contexts */ + ntlm_crypt_ctx crypt_ctx; + ntlm_unicode_ctx unicode_ctx; + int crypt_initialized : 1, + unicode_initialized : 1; /* error message as set by the library */ const char *errmsg; @@ -85,24 +89,24 @@ struct ntlm_client { char *password; /* strings as converted to utf16 */ + char *hostname_utf16; char *target_utf16; char *username_utf16; char *username_upper_utf16; char *userdomain_utf16; - char *hostname_utf16; char *password_utf16; - /* timestamp and nonce; only for debugging */ - uint64_t nonce; - uint64_t timestamp; - + size_t hostname_utf16_len; size_t username_utf16_len; size_t username_upper_utf16_len; size_t userdomain_utf16_len; - size_t hostname_utf16_len; size_t password_utf16_len; size_t target_utf16_len; + /* timestamp and nonce; only for debugging */ + uint64_t nonce; + uint64_t timestamp; + unsigned char lm_response[NTLM_LM_RESPONSE_LEN]; size_t lm_response_len; diff --git a/deps/ntlmclient/ntlmclient.h b/deps/ntlmclient/ntlmclient.h index d109a5c89..bf57b17c6 100644 --- a/deps/ntlmclient/ntlmclient.h +++ b/deps/ntlmclient/ntlmclient.h @@ -15,13 +15,26 @@ extern "C" { #endif -#define NTLM_CLIENT_VERSION "0.0.1" +#define NTLM_CLIENT_VERSION "0.9.0" #define NTLM_CLIENT_VERSION_MAJOR 0 -#define NTLM_CLIENT_VERSION_MINOR 0 -#define NTLM_CLIENT_VERSION_TEENY 1 +#define NTLM_CLIENT_VERSION_MINOR 9 +#define NTLM_CLIENT_VERSION_TEENY 0 typedef struct ntlm_client ntlm_client; +typedef enum { + /** + * An error occurred; more details are available by querying + * `ntlm_client_errmsg`. + */ + NTLM_CLIENT_ERROR = -1, + + /** + * The input provided to the function is missing or invalid. + */ + NTLM_CLIENT_ERROR_INVALID_INPUT = -2, +} ntlm_error_code; + /* * Flags for initializing the `ntlm_client` context. A combination of * these flags can be provided to `ntlm_client_init`. diff --git a/deps/ntlmclient/unicode.h b/deps/ntlmclient/unicode.h index e3b17bcf7..b7c63f2ed 100644 --- a/deps/ntlmclient/unicode.h +++ b/deps/ntlmclient/unicode.h @@ -11,26 +11,32 @@ #include "compat.h" +#ifdef UNICODE_ICONV +# include "unicode_iconv.h" +#elif UNICODE_BUILTIN +# include "unicode_builtin.h" +#endif + #define NTLM_UNICODE_MAX_LEN 2048 typedef struct ntlm_unicode_ctx ntlm_unicode_ctx; -extern ntlm_unicode_ctx *ntlm_unicode_ctx_init(ntlm_client *ntlm); +extern bool ntlm_unicode_init(ntlm_client *ntlm); bool ntlm_unicode_utf8_to_16( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *ntlm, const char *string, size_t string_len); bool ntlm_unicode_utf16_to_8( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *ntlm, const char *string, size_t string_len); -extern void ntlm_unicode_ctx_free(ntlm_unicode_ctx *ctx); +extern void ntlm_unicode_shutdown(ntlm_client *ntlm); #endif /* PRIVATE_UNICODE_H__ */ diff --git a/deps/ntlmclient/unicode_builtin.c b/deps/ntlmclient/unicode_builtin.c index e1856cca9..e2ee0abf7 100644 --- a/deps/ntlmclient/unicode_builtin.c +++ b/deps/ntlmclient/unicode_builtin.c @@ -13,10 +13,6 @@ #include "unicode.h" #include "compat.h" -struct ntlm_unicode_ctx { - ntlm_client *ntlm; -}; - typedef unsigned int UTF32; /* at least 32 bits */ typedef unsigned short UTF16; /* at least 16 bits */ typedef unsigned char UTF8; /* typically 8 bits */ @@ -281,15 +277,10 @@ static ConversionResult ConvertUTF8toUTF16 ( } -ntlm_unicode_ctx *ntlm_unicode_ctx_init(ntlm_client *ntlm) +bool ntlm_unicode_init(ntlm_client *ntlm) { - ntlm_unicode_ctx *ctx; - - if ((ctx = malloc(sizeof(ntlm_unicode_ctx))) == NULL) - return NULL; - - ctx->ntlm = ntlm; - return ctx; + NTLM_UNUSED(ntlm); + return true; } typedef enum { @@ -300,7 +291,7 @@ typedef enum { static inline bool unicode_builtin_encoding_convert( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *ntlm, const char *string, size_t string_len, unicode_builtin_encoding_direction direction) @@ -332,7 +323,7 @@ static inline bool unicode_builtin_encoding_convert( out_size = (out_size + 7) & ~7; if ((out = malloc(out_size)) == NULL) { - ntlm_client_set_errmsg(ctx->ntlm, "out of memory"); + ntlm_client_set_errmsg(ntlm, "out of memory"); return false; } @@ -358,17 +349,17 @@ static inline bool unicode_builtin_encoding_convert( success = true; goto done; case sourceExhausted: - ntlm_client_set_errmsg(ctx->ntlm, + ntlm_client_set_errmsg(ntlm, "invalid unicode string; trailing data remains"); goto done; case targetExhausted: break; case sourceIllegal: - ntlm_client_set_errmsg(ctx->ntlm, + ntlm_client_set_errmsg(ntlm, "invalid unicode string; trailing data remains"); goto done; default: - ntlm_client_set_errmsg(ctx->ntlm, + ntlm_client_set_errmsg(ntlm, "unknown unicode conversion failure"); goto done; } @@ -377,13 +368,12 @@ static inline bool unicode_builtin_encoding_convert( out_size = ((((out_size << 1) - (out_size >> 1)) + 7) & ~7); if (out_size > NTLM_UNICODE_MAX_LEN) { - ntlm_client_set_errmsg(ctx->ntlm, - "unicode conversion too large"); + ntlm_client_set_errmsg(ntlm, "unicode conversion too large"); goto done; } if ((new_out = realloc(out, out_size)) == NULL) { - ntlm_client_set_errmsg(ctx->ntlm, "out of memory"); + ntlm_client_set_errmsg(ntlm, "out of memory"); goto done; } @@ -419,27 +409,26 @@ done: bool ntlm_unicode_utf8_to_16( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *client, const char *string, size_t string_len) { return unicode_builtin_encoding_convert(converted, converted_len, - ctx, string, string_len, unicode_builtin_utf8_to_16); + client, string, string_len, unicode_builtin_utf8_to_16); } bool ntlm_unicode_utf16_to_8( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *client, const char *string, size_t string_len) { return unicode_builtin_encoding_convert(converted, converted_len, - ctx, string, string_len, unicode_builtin_utf16_to_8); + client, string, string_len, unicode_builtin_utf16_to_8); } -void ntlm_unicode_ctx_free(ntlm_unicode_ctx *ctx) +void ntlm_unicode_shutdown(ntlm_client *ntlm) { - if (ctx) - free(ctx); + NTLM_UNUSED(ntlm); } diff --git a/deps/ntlmclient/unicode_builtin.h b/deps/ntlmclient/unicode_builtin.h new file mode 100644 index 000000000..eabec40bf --- /dev/null +++ b/deps/ntlmclient/unicode_builtin.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) Edward Thomson. All rights reserved. + * + * This file is part of ntlmclient, distributed under the MIT license. + * For full terms and copyright information, and for third-party + * copyright information, see the included LICENSE.txt file. + */ + +#ifndef PRIVATE_UNICODE_BUILTIN_H__ +#define PRIVATE_UNICODE_BUILTIN_H__ + +#include <locale.h> +#include <iconv.h> + +#include "ntlmclient.h" + +struct ntlm_unicode_ctx { +}; + +#endif /* PRIVATE_UNICODE_BUILTIN_H__ */ diff --git a/deps/ntlmclient/unicode_iconv.c b/deps/ntlmclient/unicode_iconv.c index d1fe07e26..e14da21f5 100644 --- a/deps/ntlmclient/unicode_iconv.c +++ b/deps/ntlmclient/unicode_iconv.c @@ -16,43 +16,23 @@ #include "ntlm.h" #include "compat.h" -struct ntlm_unicode_ctx { - ntlm_client *ntlm; - iconv_t utf8_to_16; - iconv_t utf16_to_8; -}; - -ntlm_unicode_ctx *ntlm_unicode_ctx_init(ntlm_client *ntlm) -{ - ntlm_unicode_ctx *ctx; - - if ((ctx = calloc(1, sizeof(ntlm_unicode_ctx))) == NULL) - return NULL; - - ctx->ntlm = ntlm; - ctx->utf8_to_16 = (iconv_t)-1; - ctx->utf16_to_8 = (iconv_t)-1; - - return ctx; -} - typedef enum { unicode_iconv_utf8_to_16, unicode_iconv_utf16_to_8 } unicode_iconv_encoding_direction; -static inline bool unicode_iconv_init(ntlm_unicode_ctx *ctx) +bool ntlm_unicode_init(ntlm_client *ntlm) { - if (ctx->utf8_to_16 != (iconv_t)-1 || ctx->utf16_to_8 != (iconv_t)-1) - return true; + ntlm->unicode_ctx.utf8_to_16 = iconv_open("UTF-16LE", "UTF-8"); + ntlm->unicode_ctx.utf16_to_8 = iconv_open("UTF-8", "UTF-16LE"); - if ((ctx->utf8_to_16 = iconv_open("UTF-16LE", "UTF-8")) == (iconv_t)-1 || - (ctx->utf16_to_8 = iconv_open("UTF-8", "UTF-16LE")) == (iconv_t)-1) { + if (ntlm->unicode_ctx.utf8_to_16 == (iconv_t)-1 || + ntlm->unicode_ctx.utf16_to_8 == (iconv_t)-1) { if (errno == EINVAL) - ntlm_client_set_errmsg(ctx->ntlm, + ntlm_client_set_errmsg(ntlm, "iconv does not support UTF8 <-> UTF16 conversion"); else - ntlm_client_set_errmsg(ctx->ntlm, strerror(errno)); + ntlm_client_set_errmsg(ntlm, strerror(errno)); return false; } @@ -63,7 +43,7 @@ static inline bool unicode_iconv_init(ntlm_unicode_ctx *ctx) static inline bool unicode_iconv_encoding_convert( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *ntlm, const char *string, size_t string_len, unicode_iconv_encoding_direction direction) @@ -75,9 +55,6 @@ static inline bool unicode_iconv_encoding_convert( *converted = NULL; *converted_len = 0; - if (!unicode_iconv_init(ctx)) - return false; - /* * When translating UTF8 to UTF16, these strings are only used * internally, and we obey the given length, so we can simply @@ -86,11 +63,11 @@ static inline bool unicode_iconv_encoding_convert( * terminate and expect an extra byte for UTF8, two for UTF16. */ if (direction == unicode_iconv_utf8_to_16) { - converter = ctx->utf8_to_16; + converter = ntlm->unicode_ctx.utf8_to_16; out_size = (string_len * 2) + 2; nul_size = 2; } else { - converter = ctx->utf16_to_8; + converter = ntlm->unicode_ctx.utf16_to_8; out_size = (string_len / 2) + 1; nul_size = 1; } @@ -99,7 +76,7 @@ static inline bool unicode_iconv_encoding_convert( out_size = (out_size + 7) & ~7; if ((out = malloc(out_size)) == NULL) { - ntlm_client_set_errmsg(ctx->ntlm, "out of memory"); + ntlm_client_set_errmsg(ntlm, "out of memory"); return false; } @@ -117,7 +94,7 @@ static inline bool unicode_iconv_encoding_convert( break; if (ret == (size_t)-1 && errno != E2BIG) { - ntlm_client_set_errmsg(ctx->ntlm, strerror(errno)); + ntlm_client_set_errmsg(ntlm, strerror(errno)); goto on_error; } @@ -125,13 +102,12 @@ static inline bool unicode_iconv_encoding_convert( out_size = ((((out_size << 1) - (out_size >> 1)) + 7) & ~7); if (out_size > NTLM_UNICODE_MAX_LEN) { - ntlm_client_set_errmsg(ctx->ntlm, - "unicode conversion too large"); + ntlm_client_set_errmsg(ntlm, "unicode conversion too large"); goto on_error; } if ((new_out = realloc(out, out_size)) == NULL) { - ntlm_client_set_errmsg(ctx->ntlm, "out of memory"); + ntlm_client_set_errmsg(ntlm, "out of memory"); goto on_error; } @@ -139,7 +115,7 @@ static inline bool unicode_iconv_encoding_convert( } if (in_start_len != 0) { - ntlm_client_set_errmsg(ctx->ntlm, + ntlm_client_set_errmsg(ntlm, "invalid unicode string; trailing data remains"); goto on_error; } @@ -165,37 +141,37 @@ on_error: bool ntlm_unicode_utf8_to_16( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *ntlm, const char *string, size_t string_len) { return unicode_iconv_encoding_convert( - converted, converted_len, ctx, string, string_len, + converted, converted_len, ntlm, string, string_len, unicode_iconv_utf8_to_16); } bool ntlm_unicode_utf16_to_8( char **converted, size_t *converted_len, - ntlm_unicode_ctx *ctx, + ntlm_client *ntlm, const char *string, size_t string_len) { return unicode_iconv_encoding_convert( - converted, converted_len, ctx, string, string_len, + converted, converted_len, ntlm, string, string_len, unicode_iconv_utf16_to_8); } -void ntlm_unicode_ctx_free(ntlm_unicode_ctx *ctx) +void ntlm_unicode_shutdown(ntlm_client *ntlm) { - if (!ctx) - return; - - if (ctx->utf16_to_8 != (iconv_t)-1) - iconv_close(ctx->utf16_to_8); + if (ntlm->unicode_ctx.utf16_to_8 != (iconv_t)0 && + ntlm->unicode_ctx.utf16_to_8 != (iconv_t)-1) + iconv_close(ntlm->unicode_ctx.utf16_to_8); - if (ctx->utf8_to_16 != (iconv_t)-1) - iconv_close(ctx->utf8_to_16); + if (ntlm->unicode_ctx.utf8_to_16 != (iconv_t)0 && + ntlm->unicode_ctx.utf8_to_16 != (iconv_t)-1) + iconv_close(ntlm->unicode_ctx.utf8_to_16); - free(ctx); + ntlm->unicode_ctx.utf8_to_16 = (iconv_t)-1; + ntlm->unicode_ctx.utf16_to_8 = (iconv_t)-1; } diff --git a/deps/ntlmclient/unicode_iconv.h b/deps/ntlmclient/unicode_iconv.h new file mode 100644 index 000000000..87a96a67d --- /dev/null +++ b/deps/ntlmclient/unicode_iconv.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Edward Thomson. All rights reserved. + * + * This file is part of ntlmclient, distributed under the MIT license. + * For full terms and copyright information, and for third-party + * copyright information, see the included LICENSE.txt file. + */ + +#ifndef PRIVATE_UNICODE_ICONV_H__ +#define PRIVATE_UNICODE_ICONV_H__ + +#include <locale.h> +#include <iconv.h> + +#include "ntlmclient.h" + +struct ntlm_unicode_ctx { + iconv_t utf8_to_16; + iconv_t utf16_to_8; +}; + +#endif /* PRIVATE_UNICODE_ICONV_H__ */ diff --git a/script/valgrind.supp b/script/valgrind.supp index d938aa9c9..8c4549f62 100644 --- a/script/valgrind.supp +++ b/script/valgrind.supp @@ -42,6 +42,38 @@ } { + ignore-openssl-init-leak + Memcheck:Leak + ... + fun:git_openssl_stream_global_init + ... +} + +{ + ignore-openssl-legacy-init-leak + Memcheck:Leak + ... + fun:OPENSSL_init_ssl__legacy + ... +} + +{ + ignore-openssl-malloc-leak + Memcheck:Leak + ... + fun:git_openssl_malloc + ... +} + +{ + ignore-openssl-realloc-leak + Memcheck:Leak + ... + fun:git_openssl_realloc + ... +} + +{ ignore-glibc-getaddrinfo-cache Memcheck:Leak ... @@ -65,6 +97,22 @@ } { + ignore-libssh2-session-create + Memcheck:Leak + ... + fun:_git_ssh_session_create + ... +} + +{ + ignore-libssh2-setup-conn + Memcheck:Leak + ... + fun:_git_ssh_setup_conn + ... +} + +{ ignore-libssh2-gcrypt-control-leak Memcheck:Leak ... @@ -178,3 +226,19 @@ obj:*libcrypto.so* ... } + +{ + ignore-dlopen-leak + Memcheck:Leak + ... + fun:dlopen + ... +} + +{ + ignore-dlopen-leak + Memcheck:Leak + ... + fun:_dlerror_run + ... +} diff --git a/src/features.h.in b/src/features.h.in index ab523f90b..41f2734ac 100644 --- a/src/features.h.in +++ b/src/features.h.in @@ -34,6 +34,7 @@ #cmakedefine GIT_WINHTTP 1 #cmakedefine GIT_HTTPS 1 #cmakedefine GIT_OPENSSL 1 +#cmakedefine GIT_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SECURE_TRANSPORT 1 #cmakedefine GIT_MBEDTLS 1 diff --git a/src/libgit2.c b/src/libgit2.c index 089c83590..aee9cf2cd 100644 --- a/src/libgit2.c +++ b/src/libgit2.c @@ -36,14 +36,6 @@ # include "win32/w32_leakcheck.h" #endif -#ifdef GIT_OPENSSL -# include <openssl/err.h> -#endif - -#ifdef GIT_MBEDTLS -# include <mbedtls/error.h> -#endif - /* Declarations for tuneable settings */ extern size_t git_mwindow__window_size; extern size_t git_mwindow__mapped_limit; diff --git a/src/netops.h b/src/netops.h index 771c87b64..7140b39bc 100644 --- a/src/netops.h +++ b/src/netops.h @@ -14,7 +14,7 @@ #include "net.h" #ifdef GIT_OPENSSL -# include <openssl/ssl.h> +# include "streams/openssl.h" #endif typedef struct gitno_ssl { diff --git a/src/streams/openssl.c b/src/streams/openssl.c index 01ce9ce2a..89c96780c 100644 --- a/src/streams/openssl.c +++ b/src/streams/openssl.c @@ -6,11 +6,14 @@ */ #include "streams/openssl.h" +#include "streams/openssl_legacy.h" +#include "streams/openssl_dynamic.h" #ifdef GIT_OPENSSL #include <ctype.h> +#include "common.h" #include "runtime.h" #include "settings.h" #include "posix.h" @@ -26,156 +29,17 @@ # include <netinet/in.h> #endif -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <openssl/x509v3.h> -#include <openssl/bio.h> +#ifndef GIT_OPENSSL_DYNAMIC +# include <openssl/ssl.h> +# include <openssl/err.h> +# include <openssl/x509v3.h> +# include <openssl/bio.h> +#endif SSL_CTX *git__ssl_ctx; #define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" -#if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) -# define OPENSSL_LEGACY_API -#endif - -/* - * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it - * which do not exist in previous versions. We define these inline functions so - * we can program against the interface instead of littering the implementation - * with ifdefs. We do the same for OPENSSL_init_ssl. - */ -#if defined(OPENSSL_LEGACY_API) -static int OPENSSL_init_ssl(int opts, void *settings) -{ - GIT_UNUSED(opts); - GIT_UNUSED(settings); - SSL_load_error_strings(); - OpenSSL_add_ssl_algorithms(); - return 0; -} - -static BIO_METHOD* BIO_meth_new(int type, const char *name) -{ - BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD)); - if (!meth) { - return NULL; - } - - meth->type = type; - meth->name = name; - - return meth; -} - -static void BIO_meth_free(BIO_METHOD *biom) -{ - git__free(biom); -} - -static int BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int)) -{ - biom->bwrite = write; - return 1; -} - -static int BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int)) -{ - biom->bread = read; - return 1; -} - -static int BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *)) -{ - biom->bputs = puts; - return 1; -} - -static int BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int)) - -{ - biom->bgets = gets; - return 1; -} - -static int BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *)) -{ - biom->ctrl = ctrl; - return 1; -} - -static int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *)) -{ - biom->create = create; - return 1; -} - -static int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *)) -{ - biom->destroy = destroy; - return 1; -} - -static int BIO_get_new_index(void) -{ - /* This exists as of 1.1 so before we'd just have 0 */ - return 0; -} - -static void BIO_set_init(BIO *b, int init) -{ - b->init = init; -} - -static void BIO_set_data(BIO *a, void *ptr) -{ - a->ptr = ptr; -} - -static void *BIO_get_data(BIO *a) -{ - return a->ptr; -} - -static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x) -{ - return ASN1_STRING_data((ASN1_STRING *)x); -} - -# if defined(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) { - (void)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[i]); - git__free(openssl_locks); -} -# endif /* GIT_THREADS */ -#endif /* OPENSSL_LEGACY_API */ static BIO_METHOD *git_stream_bio_method; static int init_bio_method(void); @@ -198,46 +62,47 @@ static void shutdown_ssl(void) } #ifdef VALGRIND -#ifdef OPENSSL_LEGACY_API -static void *git_openssl_malloc(size_t bytes) -{ - return git__calloc(1, bytes); -} +# if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) -static void *git_openssl_realloc(void *mem, size_t size) -{ - return git__realloc(mem, size); -} - -static void git_openssl_free(void *mem) -{ - return git__free(mem); -} -#else static void *git_openssl_malloc(size_t bytes, const char *file, int line) { GIT_UNUSED(file); GIT_UNUSED(line); return git__calloc(1, bytes); } - + static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line) { GIT_UNUSED(file); GIT_UNUSED(line); return git__realloc(mem, size); } - + static void git_openssl_free(void *mem, const char *file, int line) { GIT_UNUSED(file); GIT_UNUSED(line); - return git__free(mem); + git__free(mem); +} +# else /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ +static void *git_openssl_malloc(size_t bytes) +{ + return git__calloc(1, bytes); } -#endif -#endif -int git_openssl_stream_global_init(void) +static void *git_openssl_realloc(void *mem, size_t size) +{ + return git__realloc(mem, size); +} + +static void git_openssl_free(void *mem) +{ + git__free(mem); +} +# endif /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ +#endif /* VALGRIND */ + +static int openssl_init(void) { long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; const char *ciphers = git_libgit2__ssl_ciphers(); @@ -301,42 +166,60 @@ error: return -1; } -#if defined(GIT_THREADS) && defined(OPENSSL_LEGACY_API) -static void threadid_cb(CRYPTO_THREADID *threadid) +/* + * When we use dynamic loading, we defer OpenSSL initialization until + * it's first used. `openssl_ensure_initialized` will do the work + * under a mutex. + */ +git_mutex openssl_mutex; +bool openssl_initialized; + +int git_openssl_stream_global_init(void) { - GIT_UNUSED(threadid); - CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid()); -} +#ifndef GIT_OPENSSL_DYNAMIC + return openssl_init(); +#else + if (git_mutex_init(&openssl_mutex) != 0) + return -1; + + return 0; #endif +} -int git_openssl_set_locking(void) +static int openssl_ensure_initialized(void) { -#if defined(GIT_THREADS) && defined(OPENSSL_LEGACY_API) - int num_locks, i; +#ifdef GIT_OPENSSL_DYNAMIC + int error = 0; - CRYPTO_THREADID_set_callback(threadid_cb); + if (git_mutex_lock(&openssl_mutex) != 0) + return -1; - num_locks = CRYPTO_num_locks(); - openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); - GIT_ERROR_CHECK_ALLOC(openssl_locks); + if (!openssl_initialized) { + if ((error = git_openssl_stream_dynamic_init()) == 0) + error = openssl_init(); - for (i = 0; i < num_locks; i++) { - if (git_mutex_init(&openssl_locks[i]) != 0) { - git_error_set(GIT_ERROR_SSL, "failed to initialize openssl locks"); - return -1; - } + openssl_initialized = true; } - CRYPTO_set_locking_callback(openssl_locking_function); - return git_runtime_shutdown_register(shutdown_ssl_locking); + error |= git_mutex_unlock(&openssl_mutex); + return error; -#elif !defined(OPENSSL_LEGACY_API) - return 0; #else + return 0; +#endif +} + +#if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) +int git_openssl_set_locking(void) +{ +# ifdef GIT_THREADS + return 0; +# else git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads"); return -1; -#endif +# endif } +#endif static int bio_create(BIO *b) @@ -799,6 +682,9 @@ static int openssl_stream_wrap( int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host) { + if (openssl_ensure_initialized() < 0) + return -1; + return openssl_stream_wrap(out, in, host, 0); } @@ -811,6 +697,9 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port) GIT_ASSERT_ARG(host); GIT_ASSERT_ARG(port); + if (openssl_ensure_initialized() < 0) + return -1; + if ((error = git_socket_stream_new(&stream, host, port)) < 0) return error; @@ -824,6 +713,9 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port) int git_openssl__set_cert_location(const char *file, const char *path) { + if (openssl_ensure_initialized() < 0) + return -1; + if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) { char errmsg[256]; diff --git a/src/streams/openssl.h b/src/streams/openssl.h index 826d1efbc..89fb60a82 100644 --- a/src/streams/openssl.h +++ b/src/streams/openssl.h @@ -8,14 +8,22 @@ #define INCLUDE_streams_openssl_h__ #include "common.h" +#include "streams/openssl_legacy.h" +#include "streams/openssl_dynamic.h" #include "git2/sys/stream.h" extern int git_openssl_stream_global_init(void); +#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC) +# include <openssl/ssl.h> +# include <openssl/err.h> +# include <openssl/x509v3.h> +# include <openssl/bio.h> +# endif + #ifdef GIT_OPENSSL extern int git_openssl__set_cert_location(const char *file, const char *path); - extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port); extern int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host); #endif diff --git a/src/streams/openssl_dynamic.c b/src/streams/openssl_dynamic.c new file mode 100644 index 000000000..da16b6ed7 --- /dev/null +++ b/src/streams/openssl_dynamic.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "streams/openssl.h" +#include "streams/openssl_dynamic.h" + +#if defined(GIT_OPENSSL) && defined(GIT_OPENSSL_DYNAMIC) + +#include "runtime.h" + +#include <dlfcn.h> + +unsigned char *(*ASN1_STRING_data)(ASN1_STRING *x); +const unsigned char *(*ASN1_STRING_get0_data)(const ASN1_STRING *x); +int (*ASN1_STRING_length)(const ASN1_STRING *x); +int (*ASN1_STRING_to_UTF8)(unsigned char **out, const ASN1_STRING *in); +int (*ASN1_STRING_type)(const ASN1_STRING *x); + +void *(*BIO_get_data)(BIO *a); +int (*BIO_get_new_index)(void); +int (*OPENSSL_init_ssl)(uint64_t opts, const void *settings); +void (*BIO_meth_free)(BIO_METHOD *biom); +int (*BIO_meth_set_create)(BIO_METHOD *biom, int (*create) (BIO *)); +int (*BIO_meth_set_ctrl)(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *)); +int (*BIO_meth_set_destroy)(BIO_METHOD *biom, int (*destroy) (BIO *)); +int (*BIO_meth_set_gets)(BIO_METHOD *biom, int (*gets) (BIO *, char *, int)); +int (*BIO_meth_set_puts)(BIO_METHOD *biom, int (*puts) (BIO *, const char *)); +int (*BIO_meth_set_read)(BIO_METHOD *biom, int (*read) (BIO *, char *, int)); +int (*BIO_meth_set_write)(BIO_METHOD *biom, int (*write) (BIO *, const char *, int)); +BIO_METHOD *(*BIO_meth_new)(int type, const char *name); +BIO *(*BIO_new)(const BIO_METHOD *type); +void (*BIO_set_data)(BIO *a, void *ptr); +void (*BIO_set_init)(BIO *a, int init); + +void (*CRYPTO_free)(void *ptr, const char *file, int line); +void *(*CRYPTO_malloc)(size_t num, const char *file, int line); +int (*CRYPTO_num_locks)(void); +void (*CRYPTO_set_locking_callback)(void (*func)(int mode, int type, const char *file, int line)); +int (*CRYPTO_set_mem_functions)(void *(*m)(size_t bytes), void *(*r)(void *mem, size_t size), void (*f)(void *mem)); +int (*CRYPTO_THREADID_set_callback)(void (*func)(CRYPTO_THREADID *id)); +void (*CRYPTO_THREADID_set_numeric)(CRYPTO_THREADID *id, unsigned long val); + +char *(*ERR_error_string)(unsigned long e, char *buf); +void (*ERR_error_string_n)(unsigned long e, char *buf, size_t len); +unsigned long (*ERR_get_error)(void); + +int (*SSL_connect)(SSL *ssl); +long (*SSL_ctrl)(SSL *ssl, int cmd, long arg, void *parg); +void (*SSL_free)(SSL *ssl); +int (*SSL_get_error)(SSL *ssl, int ret); +X509 *(*SSL_get_peer_certificate)(const SSL *ssl); +long (*SSL_get_verify_result)(const SSL *ssl); +int (*SSL_library_init)(void); +void (*SSL_load_error_strings)(void); +SSL *(*SSL_new)(SSL_CTX *ctx); +int (*SSL_read)(SSL *ssl, const void *buf, int num); +void (*SSL_set_bio)(SSL *ssl, BIO *rbio, BIO *wbio); +int (*SSL_shutdown)(SSL *ssl); +int (*SSL_write)(SSL *ssl, const void *buf, int num); + +long (*SSL_CTX_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg); +void (*SSL_CTX_free)(SSL_CTX *ctx); +SSL_CTX *(*SSL_CTX_new)(const SSL_METHOD *method); +int (*SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); +int (*SSL_CTX_set_default_verify_paths)(SSL_CTX *ctx); +long (*SSL_CTX_set_options)(SSL_CTX *ctx, long options); +void (*SSL_CTX_set_verify)(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); +int (*SSL_CTX_load_verify_locations)(SSL_CTX *ctx, const char *CAfile, const char *CApath); + +const SSL_METHOD *(*SSLv23_method)(void); +const SSL_METHOD *(*TLS_method)(void); + +ASN1_STRING *(*X509_NAME_ENTRY_get_data)(const X509_NAME_ENTRY *ne); +X509_NAME_ENTRY *(*X509_NAME_get_entry)(X509_NAME *name, int loc); +int (*X509_NAME_get_index_by_NID)(X509_NAME *name, int nid, int lastpos); +void (*X509_free)(X509 *a); +void *(*X509_get_ext_d2i)(const X509 *x, int nid, int *crit, int *idx); +X509_NAME *(*X509_get_subject_name)(const X509 *x); + +int (*i2d_X509)(X509 *a, unsigned char **ppout); + +int (*OPENSSL_sk_num)(const void *sk); +void *(*OPENSSL_sk_value)(const void *sk, int i); +void (*OPENSSL_sk_free)(void *sk); + +int (*sk_num)(const void *sk); +void *(*sk_value)(const void *sk, int i); +void (*sk_free)(void *sk); + +void *openssl_handle; + +GIT_INLINE(void *) openssl_sym(int *err, const char *name, bool required) +{ + void *symbol; + + /* if we've seen an err, noop to retain it */ + if (*err) + return NULL; + + + if ((symbol = dlsym(openssl_handle, name)) == NULL && required) { + const char *msg = dlerror(); + git_error_set(GIT_ERROR_SSL, "could not load ssl function '%s': %s", name, msg ? msg : "unknown error"); + *err = -1; + } + + return symbol; +} + +static void dynamic_shutdown(void) +{ + dlclose(openssl_handle); + openssl_handle = NULL; +} + +int git_openssl_stream_dynamic_init(void) +{ + int err = 0; + + if ((openssl_handle = dlopen("libssl.so.1.1", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.1.1.dylib", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL) { + git_error_set(GIT_ERROR_SSL, "could not load ssl libraries"); + return -1; + } + + ASN1_STRING_data = (unsigned char *(*)(ASN1_STRING *x))openssl_sym(&err, "ASN1_STRING_data", false); + ASN1_STRING_get0_data = (const unsigned char *(*)(const ASN1_STRING *x))openssl_sym(&err, "ASN1_STRING_get0_data", false); + ASN1_STRING_length = (int (*)(const ASN1_STRING *))openssl_sym(&err, "ASN1_STRING_length", true); + ASN1_STRING_to_UTF8 = (int (*)(unsigned char **, const ASN1_STRING *))openssl_sym(&err, "ASN1_STRING_to_UTF8", true); + ASN1_STRING_type = (int (*)(const ASN1_STRING *))openssl_sym(&err, "ASN1_STRING_type", true); + + BIO_get_data = (void *(*)(BIO *))openssl_sym(&err, "BIO_get_data", false); + BIO_get_new_index = (int (*)(void))openssl_sym(&err, "BIO_get_new_index", false); + BIO_meth_free = (void (*)(BIO_METHOD *))openssl_sym(&err, "BIO_meth_free", false); + BIO_meth_new = (BIO_METHOD *(*)(int, const char *))openssl_sym(&err, "BIO_meth_new", false); + BIO_meth_set_create = (int (*)(BIO_METHOD *, int (*)(BIO *)))openssl_sym(&err, "BIO_meth_set_create", false); + BIO_meth_set_ctrl = (int (*)(BIO_METHOD *, long (*)(BIO *, int, long, void *)))openssl_sym(&err, "BIO_meth_set_ctrl", false); + BIO_meth_set_destroy = (int (*)(BIO_METHOD *, int (*)(BIO *)))openssl_sym(&err, "BIO_meth_set_destroy", false); + BIO_meth_set_gets = (int (*)(BIO_METHOD *, int (*)(BIO *, char *, int)))openssl_sym(&err, "BIO_meth_set_gets", false); + BIO_meth_set_puts = (int (*)(BIO_METHOD *, int (*)(BIO *, const char *)))openssl_sym(&err, "BIO_meth_set_puts", false); + BIO_meth_set_read = (int (*)(BIO_METHOD *, int (*)(BIO *, char *, int)))openssl_sym(&err, "BIO_meth_set_read", false); + BIO_meth_set_write = (int (*)(BIO_METHOD *, int (*)(BIO *, const char *, int)))openssl_sym(&err, "BIO_meth_set_write", false); + BIO_new = (BIO *(*)(const BIO_METHOD *))openssl_sym(&err, "BIO_new", true); + BIO_set_data = (void (*)(BIO *a, void *))openssl_sym(&err, "BIO_set_data", false); + BIO_set_init = (void (*)(BIO *a, int))openssl_sym(&err, "BIO_set_init", false); + + CRYPTO_free = (void (*)(void *, const char *, int))openssl_sym(&err, "CRYPTO_free", true); + CRYPTO_malloc = (void *(*)(size_t, const char *, int))openssl_sym(&err, "CRYPTO_malloc", true); + CRYPTO_num_locks = (int (*)(void))openssl_sym(&err, "CRYPTO_num_locks", false); + CRYPTO_set_locking_callback = (void (*)(void (*)(int, int, const char *, int)))openssl_sym(&err, "CRYPTO_set_locking_callback", false); + CRYPTO_set_mem_functions = (int (*)(void *(*)(size_t), void *(*)(void *, size_t), void (*f)(void *)))openssl_sym(&err, "CRYPTO_set_mem_functions", true); + + CRYPTO_THREADID_set_callback = (int (*)(void (*)(CRYPTO_THREADID *)))openssl_sym(&err, "CRYPTO_THREADID_set_callback", false); + CRYPTO_THREADID_set_numeric = (void (*)(CRYPTO_THREADID *, unsigned long))openssl_sym(&err, "CRYPTO_THREADID_set_numeric", false); + + ERR_error_string = (char *(*)(unsigned long, char *))openssl_sym(&err, "ERR_error_string", true); + ERR_error_string_n = (void (*)(unsigned long, char *, size_t))openssl_sym(&err, "ERR_error_string_n", true); + ERR_get_error = (unsigned long (*)(void))openssl_sym(&err, "ERR_get_error", true); + + OPENSSL_init_ssl = (int (*)(uint64_t opts, const void *settings))openssl_sym(&err, "OPENSSL_init_ssl", false); + OPENSSL_sk_num = (int (*)(const void *))openssl_sym(&err, "OPENSSL_sk_num", false); + OPENSSL_sk_value = (void *(*)(const void *sk, int i))openssl_sym(&err, "OPENSSL_sk_value", false); + OPENSSL_sk_free = (void (*)(void *))openssl_sym(&err, "OPENSSL_sk_free", false); + + sk_num = (int (*)(const void *))openssl_sym(&err, "sk_num", false); + sk_value = (void *(*)(const void *sk, int i))openssl_sym(&err, "sk_value", false); + sk_free = (void (*)(void *))openssl_sym(&err, "sk_free", false); + + SSL_connect = (int (*)(SSL *))openssl_sym(&err, "SSL_connect", true); + SSL_ctrl = (long (*)(SSL *, int, long, void *))openssl_sym(&err, "SSL_ctrl", true); + SSL_get_peer_certificate = (X509 *(*)(const SSL *))openssl_sym(&err, "SSL_get_peer_certificate", true); + SSL_library_init = (int (*)(void))openssl_sym(&err, "SSL_library_init", false); + SSL_free = (void (*)(SSL *))openssl_sym(&err, "SSL_free", true); + SSL_get_error = (int (*)(SSL *, int))openssl_sym(&err, "SSL_get_error", true); + SSL_get_verify_result = (long (*)(const SSL *ssl))openssl_sym(&err, "SSL_get_verify_result", true); + SSL_load_error_strings = (void (*)(void))openssl_sym(&err, "SSL_load_error_strings", false); + SSL_new = (SSL *(*)(SSL_CTX *))openssl_sym(&err, "SSL_new", true); + SSL_read = (int (*)(SSL *, const void *, int))openssl_sym(&err, "SSL_read", true); + SSL_set_bio = (void (*)(SSL *, BIO *, BIO *))openssl_sym(&err, "SSL_set_bio", true); + SSL_shutdown = (int (*)(SSL *ssl))openssl_sym(&err, "SSL_shutdown", true); + SSL_write = (int (*)(SSL *, const void *, int))openssl_sym(&err, "SSL_write", true); + + SSL_CTX_ctrl = (long (*)(SSL_CTX *, int, long, void *))openssl_sym(&err, "SSL_CTX_ctrl", true); + SSL_CTX_free = (void (*)(SSL_CTX *))openssl_sym(&err, "SSL_CTX_free", true); + SSL_CTX_new = (SSL_CTX *(*)(const SSL_METHOD *))openssl_sym(&err, "SSL_CTX_new", true); + SSL_CTX_set_cipher_list = (int (*)(SSL_CTX *, const char *))openssl_sym(&err, "SSL_CTX_set_cipher_list", true); + SSL_CTX_set_default_verify_paths = (int (*)(SSL_CTX *ctx))openssl_sym(&err, "SSL_CTX_set_default_verify_paths", true); + SSL_CTX_set_options = (long (*)(SSL_CTX *, long))openssl_sym(&err, "SSL_CTX_set_options", false); + SSL_CTX_set_verify = (void (*)(SSL_CTX *, int, int (*)(int, X509_STORE_CTX *)))openssl_sym(&err, "SSL_CTX_set_verify", true); + SSL_CTX_load_verify_locations = (int (*)(SSL_CTX *, const char *, const char *))openssl_sym(&err, "SSL_CTX_load_verify_locations", true); + + SSLv23_method = (const SSL_METHOD *(*)(void))openssl_sym(&err, "SSLv23_method", false); + TLS_method = (const SSL_METHOD *(*)(void))openssl_sym(&err, "TLS_method", false); + + X509_NAME_ENTRY_get_data = (ASN1_STRING *(*)(const X509_NAME_ENTRY *))openssl_sym(&err, "X509_NAME_ENTRY_get_data", true); + X509_NAME_get_entry = (X509_NAME_ENTRY *(*)(X509_NAME *, int))openssl_sym(&err, "X509_NAME_get_entry", true); + X509_NAME_get_index_by_NID = (int (*)(X509_NAME *, int, int))openssl_sym(&err, "X509_NAME_get_index_by_NID", true); + X509_free = (void (*)(X509 *))openssl_sym(&err, "X509_free", true); + X509_get_ext_d2i = (void *(*)(const X509 *x, int nid, int *crit, int *idx))openssl_sym(&err, "X509_get_ext_d2i", true); + X509_get_subject_name = (X509_NAME *(*)(const X509 *))openssl_sym(&err, "X509_get_subject_name", true); + + i2d_X509 = (int (*)(X509 *a, unsigned char **ppout))openssl_sym(&err, "i2d_X509", true); + + if (err) + goto on_error; + + /* Add legacy functionality */ + if (!OPENSSL_init_ssl) { + OPENSSL_init_ssl = OPENSSL_init_ssl__legacy; + + if (!SSL_library_init || + !SSL_load_error_strings || + !CRYPTO_num_locks || + !CRYPTO_set_locking_callback || + !CRYPTO_THREADID_set_callback || + !CRYPTO_THREADID_set_numeric) { + git_error_set(GIT_ERROR_SSL, "could not load legacy openssl initialization functions"); + goto on_error; + } + } + + if (!SSL_CTX_set_options) + SSL_CTX_set_options = SSL_CTX_set_options__legacy; + + if (TLS_method) + SSLv23_method = TLS_method; + + if (!BIO_meth_new) { + BIO_meth_new = BIO_meth_new__legacy; + BIO_meth_new = BIO_meth_new__legacy; + BIO_meth_free = BIO_meth_free__legacy; + BIO_meth_set_write = BIO_meth_set_write__legacy; + BIO_meth_set_read = BIO_meth_set_read__legacy; + BIO_meth_set_puts = BIO_meth_set_puts__legacy; + BIO_meth_set_gets = BIO_meth_set_gets__legacy; + BIO_meth_set_ctrl = BIO_meth_set_ctrl__legacy; + BIO_meth_set_create = BIO_meth_set_create__legacy; + BIO_meth_set_destroy = BIO_meth_set_destroy__legacy; + BIO_get_new_index = BIO_get_new_index__legacy; + BIO_set_data = BIO_set_data__legacy; + BIO_set_init = BIO_set_init__legacy; + BIO_get_data = BIO_get_data__legacy; + } + + if (!ASN1_STRING_get0_data) { + if (!ASN1_STRING_data) { + git_error_set(GIT_ERROR_SSL, "could not load legacy openssl string function"); + goto on_error; + } + + ASN1_STRING_get0_data = ASN1_STRING_get0_data__legacy; + } + + if ((!OPENSSL_sk_num && !sk_num) || + (!OPENSSL_sk_value && !sk_value) || + (!OPENSSL_sk_free && !sk_free)) { + git_error_set(GIT_ERROR_SSL, "could not load legacy openssl stack functions"); + goto on_error; + } + + if (git_runtime_shutdown_register(dynamic_shutdown) != 0) + goto on_error; + + return 0; + +on_error: + dlclose(openssl_handle); + return -1; +} + + +int sk_GENERAL_NAME_num(const GENERAL_NAME *sk) +{ + if (OPENSSL_sk_num) + return OPENSSL_sk_num(sk); + else if (sk_num) + return sk_num(sk); + + GIT_ASSERT_WITH_RETVAL(false, 0); + return 0; +} + +GENERAL_NAME *sk_GENERAL_NAME_value(const GENERAL_NAME *sk, int i) +{ + if (OPENSSL_sk_value) + return OPENSSL_sk_value(sk, i); + else if (sk_value) + return sk_value(sk, i); + + GIT_ASSERT_WITH_RETVAL(false, NULL); + return NULL; +} + +void GENERAL_NAMES_free(GENERAL_NAME *sk) +{ + if (OPENSSL_sk_free) + OPENSSL_sk_free(sk); + else if (sk_free) + sk_free(sk); +} + +#endif /* GIT_OPENSSL && GIT_OPENSSL_DYNAMIC */ diff --git a/src/streams/openssl_dynamic.h b/src/streams/openssl_dynamic.h new file mode 100644 index 000000000..12d927a61 --- /dev/null +++ b/src/streams/openssl_dynamic.h @@ -0,0 +1,348 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef INCLUDE_streams_openssl_dynamic_h__ +#define INCLUDE_streams_openssl_dynamic_h__ + +#ifdef GIT_OPENSSL_DYNAMIC + +# define BIO_CTRL_FLUSH 11 + +# define BIO_TYPE_SOURCE_SINK 0x0400 + +# define CRYPTO_LOCK 1 + +# define GEN_DNS 2 +# define GEN_IPADD 7 + +# define NID_commonName 13 +# define NID_subject_alt_name 85 + +# define SSL_VERIFY_NONE 0x00 + +# define SSL_CTRL_OPTIONS 32 +# define SSL_CTRL_MODE 33 +# define SSL_CTRL_SET_TLSEXT_HOSTNAME 55 + +# define SSL_ERROR_NONE 0 +# define SSL_ERROR_SSL 1 +# define SSL_ERROR_WANT_READ 2 +# define SSL_ERROR_WANT_WRITE 3 +# define SSL_ERROR_WANT_X509_LOOKUP 4 +# define SSL_ERROR_SYSCALL 5 +# define SSL_ERROR_ZERO_RETURN 6 +# define SSL_ERROR_WANT_CONNECT 7 +# define SSL_ERROR_WANT_ACCEPT 8 + +# define SSL_OP_NO_COMPRESSION 0x00020000L +# define SSL_OP_NO_SSLv2 0x01000000L +# define SSL_OP_NO_SSLv3 0x02000000L + +# define SSL_MODE_AUTO_RETRY 0x00000004L + +# define TLSEXT_NAMETYPE_host_name 0 + +# define V_ASN1_UTF8STRING 12 + +# define X509_V_OK 0 + +/* Most of the OpenSSL types are mercifully opaque, so we can treat them like `void *` */ +typedef struct bio_st BIO; +typedef struct bio_method_st BIO_METHOD; +typedef void bio_info_cb; +typedef void * CRYPTO_EX_DATA; +typedef void CRYPTO_THREADID; +typedef void GENERAL_NAMES; +typedef void SSL; +typedef void SSL_CTX; +typedef void SSL_METHOD; +typedef void X509; +typedef void X509_NAME; +typedef void X509_NAME_ENTRY; +typedef void X509_STORE_CTX; + +typedef struct { + int length; + int type; + unsigned char *data; + long flags; +} ASN1_STRING; + +typedef struct { + int type; + union { + char *ptr; + ASN1_STRING *ia5; + } d; +} GENERAL_NAME; + +struct bio_st { + BIO_METHOD *method; + /* bio, mode, argp, argi, argl, ret */ + long (*callback) (struct bio_st *, int, const char *, int, long, long); + char *cb_arg; /* first argument for the callback */ + int init; + int shutdown; + int flags; /* extra storage */ + int retry_reason; + int num; + void *ptr; + struct bio_st *next_bio; /* used by filter BIOs */ + struct bio_st *prev_bio; /* used by filter BIOs */ + int references; + unsigned long num_read; + unsigned long num_write; + CRYPTO_EX_DATA ex_data; +}; + +struct bio_method_st { + int type; + const char *name; + int (*bwrite) (BIO *, const char *, int); + int (*bread) (BIO *, char *, int); + int (*bputs) (BIO *, const char *); + int (*bgets) (BIO *, char *, int); + long (*ctrl) (BIO *, int, long, void *); + int (*create) (BIO *); + int (*destroy) (BIO *); + long (*callback_ctrl) (BIO *, int, bio_info_cb *); +}; + +extern unsigned char *(*ASN1_STRING_data)(ASN1_STRING *x); +extern const unsigned char *(*ASN1_STRING_get0_data)(const ASN1_STRING *x); +extern int (*ASN1_STRING_length)(const ASN1_STRING *x); +extern int (*ASN1_STRING_to_UTF8)(unsigned char **out, const ASN1_STRING *in); +extern int (*ASN1_STRING_type)(const ASN1_STRING *x); + +extern void *(*BIO_get_data)(BIO *a); +extern int (*BIO_get_new_index)(void); +extern int (*OPENSSL_init_ssl)(uint64_t opts, const void *settings); +extern void (*BIO_meth_free)(BIO_METHOD *biom); +extern int (*BIO_meth_set_create)(BIO_METHOD *biom, int (*create) (BIO *)); +extern int (*BIO_meth_set_ctrl)(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *)); +extern int (*BIO_meth_set_destroy)(BIO_METHOD *biom, int (*destroy) (BIO *)); +extern int (*BIO_meth_set_gets)(BIO_METHOD *biom, int (*gets) (BIO *, char *, int)); +extern int (*BIO_meth_set_puts)(BIO_METHOD *biom, int (*puts) (BIO *, const char *)); +extern int (*BIO_meth_set_read)(BIO_METHOD *biom, int (*read) (BIO *, char *, int)); +extern int (*BIO_meth_set_write)(BIO_METHOD *biom, int (*write) (BIO *, const char *, int)); +extern BIO_METHOD *(*BIO_meth_new)(int type, const char *name); +extern BIO *(*BIO_new)(const BIO_METHOD *type); +extern void (*BIO_set_data)(BIO *a, void *ptr); +extern void (*BIO_set_init)(BIO *a, int init); + +extern void (*CRYPTO_free)(void *ptr, const char *file, int line); +extern void *(*CRYPTO_malloc)(size_t num, const char *file, int line); +extern int (*CRYPTO_num_locks)(void); +extern void (*CRYPTO_set_locking_callback)(void (*func)(int mode, int type, const char *file, int line)); +extern int (*CRYPTO_set_mem_functions)(void *(*m)(size_t bytes), void *(*r)(void *mem, size_t size), void (*f)(void *mem)); +extern int (*CRYPTO_THREADID_set_callback)(void (*func)(CRYPTO_THREADID *id)); +extern void (*CRYPTO_THREADID_set_numeric)(CRYPTO_THREADID *id, unsigned long val); + +extern char *(*ERR_error_string)(unsigned long e, char *buf); +extern void (*ERR_error_string_n)(unsigned long e, char *buf, size_t len); +extern unsigned long (*ERR_get_error)(void); + +# define OPENSSL_malloc(num) CRYPTO_malloc(num, __FILE__, __LINE__) +# define OPENSSL_free(addr) CRYPTO_free(addr, __FILE__, __LINE__) + +extern int (*SSL_connect)(SSL *ssl); +extern long (*SSL_ctrl)(SSL *ssl, int cmd, long arg, void *parg); +extern void (*SSL_free)(SSL *ssl); +extern int (*SSL_get_error)(SSL *ssl, int ret); +extern X509 *(*SSL_get_peer_certificate)(const SSL *ssl); +extern long (*SSL_get_verify_result)(const SSL *ssl); +extern int (*SSL_library_init)(void); +extern void (*SSL_load_error_strings)(void); +extern SSL *(*SSL_new)(SSL_CTX *ctx); +extern int (*SSL_read)(SSL *ssl, const void *buf, int num); +extern void (*SSL_set_bio)(SSL *ssl, BIO *rbio, BIO *wbio); +extern int (*SSL_shutdown)(SSL *ssl); +extern int (*SSL_write)(SSL *ssl, const void *buf, int num); + +# define SSL_set_tlsext_host_name(s, name) SSL_ctrl((s), SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, (char *)(name)); + +extern long (*SSL_CTX_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg); +extern void (*SSL_CTX_free)(SSL_CTX *ctx); +extern SSL_CTX *(*SSL_CTX_new)(const SSL_METHOD *method); +extern int (*SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); +extern int (*SSL_CTX_set_default_verify_paths)(SSL_CTX *ctx); +extern long (*SSL_CTX_set_options)(SSL_CTX *ctx, long options); +extern void (*SSL_CTX_set_verify)(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); +extern int (*SSL_CTX_load_verify_locations)(SSL_CTX *ctx, const char *CAfile, const char *CApath); + +# define SSL_CTX_set_mode(ctx, mode) SSL_CTX_ctrl((ctx), SSL_CTRL_MODE, (mode), NULL); + +extern const SSL_METHOD *(*SSLv23_method)(void); +extern const SSL_METHOD *(*TLS_method)(void); + +extern ASN1_STRING *(*X509_NAME_ENTRY_get_data)(const X509_NAME_ENTRY *ne); +extern X509_NAME_ENTRY *(*X509_NAME_get_entry)(X509_NAME *name, int loc); +extern int (*X509_NAME_get_index_by_NID)(X509_NAME *name, int nid, int lastpos); +extern void (*X509_free)(X509 *a); +extern void *(*X509_get_ext_d2i)(const X509 *x, int nid, int *crit, int *idx); +extern X509_NAME *(*X509_get_subject_name)(const X509 *x); + +extern int (*i2d_X509)(X509 *a, unsigned char **ppout); + +extern int (*OPENSSL_sk_num)(const void *sk); +extern void *(*OPENSSL_sk_value)(const void *sk, int i); +extern void (*OPENSSL_sk_free)(void *sk); + +extern int (*sk_num)(const void *sk); +extern void *(*sk_value)(const void *sk, int i); +extern void (*sk_free)(void *sk); + +extern int sk_GENERAL_NAME_num(const GENERAL_NAME *sk); +extern GENERAL_NAME *sk_GENERAL_NAME_value(const GENERAL_NAME *sk, int i); +extern void GENERAL_NAMES_free(GENERAL_NAME *sk); + +extern int git_openssl_stream_dynamic_init(void); + +#endif /* GIT_OPENSSL_DYNAMIC */ + +#endif diff --git a/src/streams/openssl_legacy.c b/src/streams/openssl_legacy.c new file mode 100644 index 000000000..1c1ff60c0 --- /dev/null +++ b/src/streams/openssl_legacy.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "streams/openssl.h" +#include "streams/openssl_legacy.h" + +#include "runtime.h" +#include "git2/sys/openssl.h" + +#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC) +# include <openssl/ssl.h> +# include <openssl/err.h> +# include <openssl/x509v3.h> +# include <openssl/bio.h> +#endif + +#if defined(GIT_OPENSSL_LEGACY) || defined(GIT_OPENSSL_DYNAMIC) + +/* + * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it + * which do not exist in previous versions. We define these inline functions so + * we can program against the interface instead of littering the implementation + * with ifdefs. We do the same for OPENSSL_init_ssl. + */ + +int OPENSSL_init_ssl__legacy(uint64_t opts, const void *settings) +{ + GIT_UNUSED(opts); + GIT_UNUSED(settings); + SSL_load_error_strings(); + SSL_library_init(); + return 0; +} + +BIO_METHOD* BIO_meth_new__legacy(int type, const char *name) +{ + BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD)); + if (!meth) { + return NULL; + } + + meth->type = type; + meth->name = name; + + return meth; +} + +void BIO_meth_free__legacy(BIO_METHOD *biom) +{ + git__free(biom); +} + +int BIO_meth_set_write__legacy(BIO_METHOD *biom, int (*write) (BIO *, const char *, int)) +{ + biom->bwrite = write; + return 1; +} + +int BIO_meth_set_read__legacy(BIO_METHOD *biom, int (*read) (BIO *, char *, int)) +{ + biom->bread = read; + return 1; +} + +int BIO_meth_set_puts__legacy(BIO_METHOD *biom, int (*puts) (BIO *, const char *)) +{ + biom->bputs = puts; + return 1; +} + +int BIO_meth_set_gets__legacy(BIO_METHOD *biom, int (*gets) (BIO *, char *, int)) + +{ + biom->bgets = gets; + return 1; +} + +int BIO_meth_set_ctrl__legacy(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *)) +{ + biom->ctrl = ctrl; + return 1; +} + +int BIO_meth_set_create__legacy(BIO_METHOD *biom, int (*create) (BIO *)) +{ + biom->create = create; + return 1; +} + +int BIO_meth_set_destroy__legacy(BIO_METHOD *biom, int (*destroy) (BIO *)) +{ + biom->destroy = destroy; + return 1; +} + +int BIO_get_new_index__legacy(void) +{ + /* This exists as of 1.1 so before we'd just have 0 */ + return 0; +} + +void BIO_set_init__legacy(BIO *b, int init) +{ + b->init = init; +} + +void BIO_set_data__legacy(BIO *a, void *ptr) +{ + a->ptr = ptr; +} + +void *BIO_get_data__legacy(BIO *a) +{ + return a->ptr; +} + +const unsigned char *ASN1_STRING_get0_data__legacy(const ASN1_STRING *x) +{ + return ASN1_STRING_data((ASN1_STRING *)x); +} + +long SSL_CTX_set_options__legacy(SSL_CTX *ctx, long op) +{ + return SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, NULL); +} + +# if defined(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) + (void)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[i]); + git__free(openssl_locks); +} + +static void threadid_cb(CRYPTO_THREADID *threadid) +{ + GIT_UNUSED(threadid); + CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid()); +} + +int git_openssl_set_locking(void) +{ + int num_locks, i; + +#ifndef GIT_THREADS + git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads"); + return -1; +#endif + +#ifdef GIT_OPENSSL_DYNAMIC + /* + * This function is required on legacy versions of OpenSSL; when building + * with dynamically-loaded OpenSSL, we detect whether we loaded it or not. + */ + if (!CRYPTO_set_locking_callback) + return 0; +#endif + + CRYPTO_THREADID_set_callback(threadid_cb); + + num_locks = CRYPTO_num_locks(); + openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); + GIT_ERROR_CHECK_ALLOC(openssl_locks); + + for (i = 0; i < num_locks; i++) { + if (git_mutex_init(&openssl_locks[i]) != 0) { + git_error_set(GIT_ERROR_SSL, "failed to initialize openssl locks"); + return -1; + } + } + + CRYPTO_set_locking_callback(openssl_locking_function); + return git_runtime_shutdown_register(shutdown_ssl_locking); +} +#endif /* GIT_THREADS */ + +#endif /* GIT_OPENSSL_LEGACY || GIT_OPENSSL_DYNAMIC */ diff --git a/src/streams/openssl_legacy.h b/src/streams/openssl_legacy.h new file mode 100644 index 000000000..1f74fd95a --- /dev/null +++ b/src/streams/openssl_legacy.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_streams_openssl_legacy_h__ +#define INCLUDE_streams_openssl_legacy_h__ + +#include "streams/openssl_dynamic.h" + +#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC) +# include <openssl/ssl.h> +# include <openssl/err.h> +# include <openssl/x509v3.h> +# include <openssl/bio.h> + +# if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) +# define GIT_OPENSSL_LEGACY +# endif +#endif + +#if defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) +# define OPENSSL_init_ssl OPENSSL_init_ssl__legacy +# define BIO_meth_new BIO_meth_new__legacy +# define BIO_meth_free BIO_meth_free__legacy +# define BIO_meth_set_write BIO_meth_set_write__legacy +# define BIO_meth_set_read BIO_meth_set_read__legacy +# define BIO_meth_set_puts BIO_meth_set_puts__legacy +# define BIO_meth_set_gets BIO_meth_set_gets__legacy +# define BIO_meth_set_ctrl BIO_meth_set_ctrl__legacy +# define BIO_meth_set_create BIO_meth_set_create__legacy +# define BIO_meth_set_destroy BIO_meth_set_destroy__legacy +# define BIO_get_new_index BIO_get_new_index__legacy +# define BIO_set_data BIO_set_data__legacy +# define BIO_set_init BIO_set_init__legacy +# define BIO_get_data BIO_get_data__legacy +# define ASN1_STRING_get0_data ASN1_STRING_get0_data__legacy +#endif + +#if defined(GIT_OPENSSL_LEGACY) || defined(GIT_OPENSSL_DYNAMIC) + +extern int OPENSSL_init_ssl__legacy(uint64_t opts, const void *settings); +extern BIO_METHOD* BIO_meth_new__legacy(int type, const char *name); +extern void BIO_meth_free__legacy(BIO_METHOD *biom); +extern int BIO_meth_set_write__legacy(BIO_METHOD *biom, int (*write) (BIO *, const char *, int)); +extern int BIO_meth_set_read__legacy(BIO_METHOD *biom, int (*read) (BIO *, char *, int)); +extern int BIO_meth_set_puts__legacy(BIO_METHOD *biom, int (*puts) (BIO *, const char *)); +extern int BIO_meth_set_gets__legacy(BIO_METHOD *biom, int (*gets) (BIO *, char *, int)); +extern int BIO_meth_set_ctrl__legacy(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *)); +extern int BIO_meth_set_create__legacy(BIO_METHOD *biom, int (*create) (BIO *)); +extern int BIO_meth_set_destroy__legacy(BIO_METHOD *biom, int (*destroy) (BIO *)); +extern int BIO_get_new_index__legacy(void); +extern void BIO_set_data__legacy(BIO *a, void *ptr); +extern void BIO_set_init__legacy(BIO *b, int init); +extern void *BIO_get_data__legacy(BIO *a); +extern const unsigned char *ASN1_STRING_get0_data__legacy(const ASN1_STRING *x); +extern long SSL_CTX_set_options__legacy(SSL_CTX *ctx, long op); + +#endif + +#endif diff --git a/src/transports/auth_ntlm.c b/src/transports/auth_ntlm.c index e0960bf9d..b5110616b 100644 --- a/src/transports/auth_ntlm.c +++ b/src/transports/auth_ntlm.c @@ -14,7 +14,7 @@ #ifdef GIT_NTLM -#include "ntlm.h" +#include "ntlmclient.h" typedef struct { git_http_auth_context parent; diff --git a/tests/main.c b/tests/main.c index 207a6a8be..56751c288 100644 --- a/tests/main.c +++ b/tests/main.c @@ -18,7 +18,9 @@ int main(int argc, char *argv[]) res = git_libgit2_init(); if (res < 0) { - fprintf(stderr, "failed to init libgit2"); + const git_error *err = git_error_last(); + const char *msg = err ? err->message : "unknown failure"; + fprintf(stderr, "failed to init libgit2: %s\n", msg); return res; } |