diff --git a/LICENSE.md b/LICENSE.md index ab11841e04e27..ad19da9f9a8c2 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -86,7 +86,6 @@ Julia bundles the following external programs and libraries on some platforms: - [BUSYBOX](https://github.com/rmyorston/busybox-w32/blob/master/LICENSE) - [ZLIB](http://zlib.net/zlib_license.html) - [LIBEXPAT](http://expat.cvs.sourceforge.net/viewvc/expat/expat/README) -- [OPENSSL](https://github.com/openssl/openssl/blob/master/LICENSE) On some platforms, distributions of Julia contain SSL certificate authority certificates, released under the [Mozilla Public License](https://en.wikipedia.org/wiki/Mozilla_Public_License). diff --git a/Makefile b/Makefile index 2716c9c1ec5a4..8b0cc23a36227 100644 --- a/Makefile +++ b/Makefile @@ -362,12 +362,6 @@ endif fi \ done \ done - - # Copy in libssl and libcrypto if they exist -ifeq ($(OS),Linux) - -$(INSTALL_M) $(build_libdir)/libssl*.so* $(DESTDIR)$(private_libdir) - -$(INSTALL_M) $(build_libdir)/libcrypto*.so* $(DESTDIR)$(private_libdir) -endif endif ifeq ($(USE_SYSTEM_LIBUV),0) diff --git a/README.md b/README.md index 094b3fba994a3..2982db4871d45 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,6 @@ Building Julia requires that the following software be installed: - **[m4]** — needed to build GMP. - **[patch]** — for modifying source code. - **[cmake]** — needed to build `libgit2`. -- **[openssl]** — needed for HTTPS support in `libgit2` on Linux, install via `apt-get install libssl-dev` or `yum install openssl-devel`. - **[pkg-config]** - needed to build `libgit2` correctly, especially for proxy support Julia uses the following external libraries, which are automatically downloaded (or in a few cases, included in the Julia source repository) and then compiled from source the first time you run `make`: @@ -337,7 +336,6 @@ For a longer overview of Julia's dependencies, see these [slides](https://github [utf8proc]: http://julialang.org/utf8proc/ [libosxunwind]: https://github.com/JuliaLang/libosxunwind [libunwind]: http://www.nongnu.org/libunwind -[openssl]: https://www.openssl.org [libssh2]: https://www.libssh2.org [mbedtls]: https://tls.mbed.org/ [pkg-config]: https://www.freedesktop.org/wiki/Software/pkg-config/ diff --git a/deps/libgit2.mk b/deps/libgit2.mk index b4d260424c438..d7abc6d88f8b0 100644 --- a/deps/libgit2.mk +++ b/deps/libgit2.mk @@ -8,6 +8,10 @@ ifeq ($(USE_SYSTEM_LIBSSH2), 0) $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/libssh2 endif +ifeq ($(USE_SYSTEM_MBEDTLS), 0) +$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/mbedtls +endif + ifneq ($(OS),WINNT) ifeq ($(USE_SYSTEM_CURL), 0) $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/curl @@ -33,18 +37,18 @@ LIBGIT2_OPTS += -DCURL_INCLUDE_DIRS=$(build_includedir) -DCURL_LIBRARIES="-L$(bu endif ifeq ($(OS),Linux) -LIBGIT2_OPTS += -DCMAKE_INSTALL_RPATH="\$$ORIGIN" +LIBGIT2_OPTS += -DUSE_OPENSSL=OFF -DUSE_MBEDTLS=ON -DCMAKE_INSTALL_RPATH="\$$ORIGIN" endif $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-ssh.patch-applied: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/source-extracted cd $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR) && patch -p0 -f < $(SRCDIR)/patches/libgit2-ssh.patch echo 1 > $@ -$(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-require-openssl.patch-applied: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/source-extracted | $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-ssh.patch-applied - cd $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR) && patch -p1 -f < $(SRCDIR)/patches/libgit2-require-openssl.patch +$(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-mbedtls.patch-applied: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/source-extracted | $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-ssh.patch-applied + cd $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR) && patch -p1 -f < $(SRCDIR)/patches/libgit2-mbedtls.patch echo 1 > $@ -$(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-agent-nonfatal.patch-applied: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/source-extracted | $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-require-openssl.patch-applied +$(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-agent-nonfatal.patch-applied: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/source-extracted | $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-mbedtls.patch-applied cd $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR) && patch -p1 -f < $(SRCDIR)/patches/libgit2-agent-nonfatal.patch echo 1 > $@ @@ -53,7 +57,7 @@ $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-openssl-hang.patch-applied: $(SRCD echo 1 > $@ $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: \ - $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-require-openssl.patch-applied \ + $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-mbedtls.patch-applied \ $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-openssl-hang.patch-applied \ $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-ssh.patch-applied \ $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-agent-nonfatal.patch-applied @@ -82,15 +86,6 @@ ifeq ($$(OS),WINNT) else $(call MAKE_INSTALL,$1,$2,$3) endif -ifeq ($$(OS),Linux) - @# If we're on linux, copy over libssl and libcrypto for libgit2 - -LIBGIT_LIBS=$$$$(ldd "$1/libgit2.$$(SHLIB_EXT)" | tail -n +2 | awk '{print $$$$(NF-1)}'); \ - for LIB in libssl libcrypto; do \ - LIB_PATH=$$$$(echo "$$$$LIBGIT_LIBS" | grep "$$$$LIB"); \ - echo "LIB_PATH for $$$$LIB: $$$$LIB_PATH"; \ - [ ! -z "$$$$LIB_PATH" ] && cp -v "$$$$LIB_PATH" $2/$$(build_shlibdir); \ - done -endif endef $(eval $(call staged-install, \ libgit2,$(LIBGIT2_SRC_DIR), \ diff --git a/deps/patches/libgit2-mbedtls.patch b/deps/patches/libgit2-mbedtls.patch new file mode 100644 index 0000000000000..12ea364942f4b --- /dev/null +++ b/deps/patches/libgit2-mbedtls.patch @@ -0,0 +1,900 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index c79b263..ee37d05 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -112,6 +112,10 @@ IF (HAVE_STRUCT_STAT_NSEC OR WIN32) + OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" OFF ) + ENDIF() + ++IF (NOT USE_OPENSSL) ++ OPTION( USE_MBEDTLS "Link with and use mbedtls library" OFF ) ++ENDIF() ++ + # This variable will contain the libraries we need to put into + # libgit2.pc's Requires.private. That is, what we're linking to or + # what someone who's statically linking us needs to link to. +@@ -277,6 +281,10 @@ ELSE () + FIND_PACKAGE(OpenSSL) + ENDIF () + ++ IF (NOT AMIGA AND USE_MBEDTLS) ++ FIND_PACKAGE(mbedTLS) ++ ENDIF () ++ + IF (CURL_FOUND) + ADD_DEFINITIONS(-DGIT_CURL) + INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS}) +@@ -309,6 +317,9 @@ ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin") + ELSE() + SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} openssl") + ENDIF () ++ELSEIF (MBEDTLS_FOUND AND NOT SHA1_TYPE STREQUAL "builtin") ++ ADD_DEFINITIONS(-DMBEDTLS_SHA1) ++ FILE(GLOB SRC_SHA1 src/hash/hash_mbedtls.c) + ELSE() + FILE(GLOB SRC_SHA1 src/hash/hash_generic.c) + ENDIF() +@@ -534,6 +545,11 @@ IF (OPENSSL_FOUND) + SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) + ENDIF() + ++IF (MBEDTLS_FOUND) ++ ADD_DEFINITIONS(-DGIT_MBEDTLS) ++ INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR}) ++ SET(SSL_LIBRARIES ${MBEDTLS_LIBRARIES}) ++ENDIF() + + + IF (THREADSAFE) +@@ -679,7 +695,7 @@ IF (BUILD_CLAR) + ENDIF () + + ENABLE_TESTING() +- IF (WINHTTP OR OPENSSL_FOUND OR SECURITY_FOUND) ++ IF (WINHTTP OR OPENSSL_FOUND OR SECURITY_FOUND OR MBEDTLS_FOUND) + ADD_TEST(libgit2_clar libgit2_clar -ionline) + ELSE () + ADD_TEST(libgit2_clar libgit2_clar -v) +diff --git a/cmake/Modules/FindmbedTLS.cmake b/cmake/Modules/FindmbedTLS.cmake +new file mode 100644 +index 0000000..2f4adbc +--- /dev/null ++++ b/cmake/Modules/FindmbedTLS.cmake +@@ -0,0 +1,64 @@ ++# - Try to find mbedTLS ++# Once done this will define ++# ++# Read-Only variables ++# MBEDTLS_FOUND - system has mbedTLS ++# MBEDTLS_INCLUDE_DIR - the mbedTLS include directory ++# MBEDTLS_LIBRARY_DIR - the mbedTLS library directory ++# MBEDTLS_LIBRARIES - Link these to use mbedTLS ++# MBEDTLS_LIBRARY - path to mbedTLS library ++# MBEDX509_LIBRARY - path to mbedTLS X.509 library ++# MBEDCRYPTO_LIBRARY - path to mbedTLS Crypto library ++ ++FIND_PATH(MBEDTLS_INCLUDE_DIR mbedtls/version.h) ++ ++IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARIES) ++ # Already in cache, be silent ++ SET(MBEDTLS_FIND_QUIETLY TRUE) ++ENDIF() ++ ++FIND_LIBRARY(MBEDTLS_LIBRARY NAMES mbedtls libmbedtls libmbedx509) ++FIND_LIBRARY(MBEDX509_LIBRARY NAMES mbedx509 libmbedx509) ++FIND_LIBRARY(MBEDCRYPTO_LIBRARY NAMES mbedcrypto libmbedcrypto) ++ ++IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY) ++ SET(MBEDTLS_FOUND TRUE) ++ENDIF() ++ ++IF(MBEDTLS_FOUND) ++ # split mbedTLS into -L and -l linker options, so we can set them for pkg-config ++ GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_DIR ${MBEDTLS_LIBRARY} PATH) ++ GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY} NAME_WE) ++ GET_FILENAME_COMPONENT(MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY} NAME_WE) ++ GET_FILENAME_COMPONENT(MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY} NAME_WE) ++ STRING(REGEX REPLACE "^lib" "" MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY_FILE}) ++ STRING(REGEX REPLACE "^lib" "" MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY_FILE}) ++ STRING(REGEX REPLACE "^lib" "" MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY_FILE}) ++ SET(MBEDTLS_LIBRARIES "-L${MBEDTLS_LIBRARY_DIR} -l${MBEDTLS_LIBRARY_FILE} -l${MBEDX509_LIBRARY_FILE} -l${MBEDCRYPTO_LIBRARY_FILE}") ++ ++ IF(NOT MBEDTLS_FIND_QUIETLY) ++ MESSAGE(STATUS "Found mbedTLS:") ++ FILE(READ ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h MBEDTLSCONTENT) ++ STRING(REGEX MATCH "MBEDTLS_VERSION_STRING +\"[0-9|.]+\"" MBEDTLSMATCH ${MBEDTLSCONTENT}) ++ IF (MBEDTLSMATCH) ++ STRING(REGEX REPLACE "MBEDTLS_VERSION_STRING +\"([0-9|.]+)\"" "\\1" MBEDTLS_VERSION ${MBEDTLSMATCH}) ++ MESSAGE(STATUS " version ${MBEDTLS_VERSION}") ++ ENDIF(MBEDTLSMATCH) ++ MESSAGE(STATUS " TLS: ${MBEDTLS_LIBRARY}") ++ MESSAGE(STATUS " X509: ${MBEDX509_LIBRARY}") ++ MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}") ++ ENDIF(NOT MBEDTLS_FIND_QUIETLY) ++ELSE(MBEDTLS_FOUND) ++ IF(MBEDTLS_FIND_REQUIRED) ++ MESSAGE(FATAL_ERROR "Could not find mbedTLS") ++ ENDIF(MBEDTLS_FIND_REQUIRED) ++ENDIF(MBEDTLS_FOUND) ++ ++MARK_AS_ADVANCED( ++ MBEDTLS_INCLUDE_DIR ++ MBEDTLS_LIBRARY_DIR ++ MBEDTLS_LIBRARIES ++ MBEDTLS_LIBRARY ++ MBEDX509_LIBRARY ++ MBEDCRYPTO_LIBRARY ++) +diff --git a/src/global.c b/src/global.c +index adf353d..bdad772 100644 +--- a/src/global.c ++++ b/src/global.c +@@ -9,7 +9,11 @@ + #include "hash.h" + #include "sysdir.h" + #include "filter.h" ++#ifdef GIT_OPENSSL + #include "openssl_stream.h" ++#elif GIT_MBEDTLS ++#include "mbedtls_stream.h" ++#endif + #include "thread-utils.h" + #include "git2/global.h" + #include "transports/ssh.h" +@@ -60,7 +64,11 @@ static int init_common(void) + (ret = git_sysdir_global_init()) == 0 && + (ret = git_filter_global_init()) == 0 && + (ret = git_transport_ssh_global_init()) == 0) ++#ifdef GIT_OPENSSL + ret = git_openssl_stream_global_init(); ++#elif GIT_MBEDTLS ++ ret = git_mbedtls_stream_global_init(); ++#endif + + GIT_MEMORY_BARRIER; + +diff --git a/src/global.h b/src/global.h +index 2199515..adadcd9 100644 +--- a/src/global.h ++++ b/src/global.h +@@ -23,6 +23,12 @@ typedef struct { + extern SSL_CTX *git__ssl_ctx; + #endif + ++#ifdef GIT_MBEDTLS ++# include "mbedtls/platform.h" ++# include "mbedtls/ssl.h" ++extern mbedtls_ssl_config *git__ssl_conf; ++#endif ++ + git_global_st *git__global_state(void); + + extern git_mutex git__mwindow_mutex; +diff --git a/src/hash.h b/src/hash.h +index 0bc02a8..958d23b 100644 +--- a/src/hash.h ++++ b/src/hash.h +@@ -20,6 +20,8 @@ void git_hash_ctx_cleanup(git_hash_ctx *ctx); + # include "hash/hash_common_crypto.h" + #elif defined(OPENSSL_SHA1) + # include "hash/hash_openssl.h" ++#elif defined(MBEDTLS_SHA1) ++# include "hash/hash_mbedtls.h" + #elif defined(WIN32_SHA1) + # include "hash/hash_win32.h" + #else +diff --git a/src/hash/hash_mbedtls.c b/src/hash/hash_mbedtls.c +new file mode 100644 +index 0000000..a19d763 +--- /dev/null ++++ b/src/hash/hash_mbedtls.c +@@ -0,0 +1,38 @@ ++/* ++ * 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 "common.h" ++#include "hash.h" ++#include "hash/hash_mbedtls.h" ++ ++void git_hash_ctx_cleanup(git_hash_ctx *ctx) ++{ ++ assert(ctx); ++ mbedtls_sha1_free(&ctx->c); ++} ++ ++int git_hash_init(git_hash_ctx *ctx) ++{ ++ assert(ctx); ++ mbedtls_sha1_init(&ctx->c); ++ mbedtls_sha1_starts(&ctx->c); ++ return 0; ++} ++ ++int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) ++{ ++ assert(ctx); ++ mbedtls_sha1_update(&ctx->c, data, len); ++ return 0; ++} ++ ++int git_hash_final(git_oid *out, git_hash_ctx *ctx) ++{ ++ assert(ctx); ++ mbedtls_sha1_finish(&ctx->c, out->id); ++ return 0; ++} +diff --git a/src/hash/hash_mbedtls.h b/src/hash/hash_mbedtls.h +new file mode 100644 +index 0000000..e50d295 +--- /dev/null ++++ b/src/hash/hash_mbedtls.h +@@ -0,0 +1,20 @@ ++/* ++ * 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_hash_mbedtld_h__ ++#define INCLUDE_hash_mbedtld_h__ ++ ++#include ++ ++struct git_hash_ctx { ++ mbedtls_sha1_context c; ++}; ++ ++#define git_hash_global_init() 0 ++#define git_hash_ctx_init(ctx) git_hash_init(ctx) ++ ++#endif /* INCLUDE_hash_mbedtld_h__ */ +\ No newline at end of file +diff --git a/src/mbedtls_stream.c b/src/mbedtls_stream.c +new file mode 100644 +index 0000000..98ff808 +--- /dev/null ++++ b/src/mbedtls_stream.c +@@ -0,0 +1,483 @@ ++/* ++ * 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. ++ */ ++ ++#ifdef GIT_MBEDTLS ++ ++#include ++ ++#include "global.h" ++#include "stream.h" ++#include "socket_stream.h" ++#include "git2/transport.h" ++ ++#ifdef GIT_CURL ++# include "curl_stream.h" ++#endif ++ ++#include "mbedtls/config.h" ++#include ++#include ++#include ++#include "mbedtls/net.h" ++#include "mbedtls/debug.h" ++#include "mbedtls/entropy.h" ++#include "mbedtls/ctr_drbg.h" ++#include "mbedtls/error.h" ++#include "mbedtls/certs.h" ++ ++#ifndef OPENSSLDIR ++# define OPENSSLDIR "/usr/lib/ssl" ++#endif ++#define X509_CERT_DIR OPENSSLDIR "/certs" ++#define X509_CERT_FILE OPENSSLDIR "/cert.pem" ++#define X509_CERT_DIR_EVP "SSL_CERT_DIR" ++#define X509_CERT_FILE_EVP "SSL_CERT_FILE" ++ ++mbedtls_ssl_config *git__ssl_conf; ++mbedtls_entropy_context *mbedtls_entropy; ++ ++#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" ++ ++/** ++ * This function aims to clean-up the SSL context which ++ * we allocated. ++ */ ++static void shutdown_ssl(void) ++{ ++ if (git__ssl_conf) { ++ mbedtls_x509_crt_free(git__ssl_conf->ca_chain); ++ git__free(git__ssl_conf->ca_chain); ++ mbedtls_ctr_drbg_free(git__ssl_conf->p_rng); ++ git__free(git__ssl_conf->p_rng); ++ mbedtls_ssl_config_free(git__ssl_conf); ++ git__free(git__ssl_conf); ++ git__ssl_conf = NULL; ++ } ++ if (mbedtls_entropy) { ++ mbedtls_entropy_free(mbedtls_entropy); ++ git__free(mbedtls_entropy); ++ mbedtls_entropy = NULL; ++ } ++} ++ ++int git_mbedtls_stream_global_init(void) ++{ ++ int ret, isdir; ++ char *crtpath; ++ struct stat statbuf; ++ // const int *cipherids; ++ // const char *ciphers = git_libgit2__ssl_ciphers(); ++ ++ mbedtls_ctr_drbg_context *ctr_drbg; ++ ++ mbedtls_entropy = git__malloc(sizeof(mbedtls_entropy_context)); ++ mbedtls_entropy_init(mbedtls_entropy); ++ ++ // Seeding the random number generator ++ ctr_drbg = git__malloc(sizeof(mbedtls_ctr_drbg_context)); ++ mbedtls_ctr_drbg_init(ctr_drbg); ++ if (mbedtls_ctr_drbg_seed(ctr_drbg, ++ mbedtls_entropy_func, ++ mbedtls_entropy, NULL, 0) != 0) { ++ mbedtls_ctr_drbg_free(ctr_drbg); ++ mbedtls_entropy_free(mbedtls_entropy); ++ git__free(ctr_drbg); ++ git__free(mbedtls_entropy); ++ return -1; ++ } ++ ++ // configure TLSv1 ++ git__ssl_conf = git__malloc(sizeof(mbedtls_ssl_config)); ++ mbedtls_ssl_config_init(git__ssl_conf); ++ if ( mbedtls_ssl_config_defaults(git__ssl_conf, ++ MBEDTLS_SSL_IS_CLIENT, ++ MBEDTLS_SSL_TRANSPORT_STREAM, ++ MBEDTLS_SSL_PRESET_DEFAULT ) != 0) { ++ mbedtls_ctr_drbg_free(ctr_drbg); ++ git__free(ctr_drbg); ++ mbedtls_ssl_config_free(git__ssl_conf); ++ git__free(git__ssl_conf); ++ git__ssl_conf = NULL; ++ return -1; ++ } ++ ++ mbedtls_ssl_conf_authmode(git__ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); ++ mbedtls_ssl_conf_rng(git__ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg); ++ ++ // find locations for which CA certificates ++ isdir = 0; ++ crtpath = getenv(X509_CERT_FILE_EVP); ++ ret = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode) ? 0 : 1; ++ if (ret) { ++ isdir = 1; ++ crtpath = getenv(X509_CERT_DIR_EVP); ++ ret = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode) ? 0 : 1; ++ } ++ if (ret) { ++ isdir = 0; ++ crtpath = X509_CERT_FILE; ++ ret = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode) ? 0 : 1; ++ } ++ if (ret) { ++ isdir = 1; ++ crtpath = X509_CERT_DIR; ++ ret = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode) ? 0 : 1; ++ } ++ ++ // cannot find CA certificates ++ if (ret) { ++ mbedtls_ctr_drbg_free(ctr_drbg); ++ git__free(ctr_drbg); ++ mbedtls_ssl_config_free(git__ssl_conf); ++ git__free(git__ssl_conf); ++ git__ssl_conf = NULL; ++ return -1; ++ } else { ++ // set root certificates ++ mbedtls_x509_crt *cacert = git__malloc(sizeof(mbedtls_x509_crt)); ++ mbedtls_x509_crt_init(cacert); ++ if (isdir) ++ ret = mbedtls_x509_crt_parse_path(cacert, crtpath); ++ else ++ ret = mbedtls_x509_crt_parse_file(cacert, crtpath); ++ ++ if (ret) { ++ giterr_set(GITERR_SSL, "failed to load CA certificates: %d", ret); ++ mbedtls_x509_crt_free(cacert); ++ git__free(cacert); ++ mbedtls_ctr_drbg_free(ctr_drbg); ++ git__free(ctr_drbg); ++ mbedtls_ssl_config_free(git__ssl_conf); ++ git__free(git__ssl_conf); ++ git__ssl_conf = NULL; ++ return -1; ++ } else { ++ mbedtls_ssl_conf_ca_chain(git__ssl_conf, cacert, NULL); ++ } ++ } ++ ++ // set the list of allowed ciphersuites ++ // if (!ciphers) { ++ // cipherids = mbedtls_ssl_list_ciphersuites(); ++ // } ++ // mbedtls_ssl_conf_ciphersuites(git__ssl_conf, cipherids); ++ ++ git__on_shutdown(shutdown_ssl); ++ ++ return 0; ++} ++ ++static int bio_read(void *b, unsigned char *buf, size_t len) ++{ ++ git_stream *io = (git_stream *) b; ++ return (int) git_stream_read(io, buf, len); ++} ++ ++static int bio_write(void *b, const unsigned char *buf, size_t len) ++{ ++ git_stream *io = (git_stream *) b; ++ return (int) git_stream_write(io, (const char *)buf, len, 0); ++} ++ ++static int ssl_set_error(mbedtls_ssl_context *ssl, int error) ++{ ++ char errbuf[512]; ++ int ret = -1; ++ ++ assert(error != MBEDTLS_ERR_SSL_WANT_READ); ++ assert(error != MBEDTLS_ERR_SSL_WANT_WRITE); ++ ++ if (error != 0) ++ mbedtls_strerror( error, errbuf, 512 ); ++ ++ switch(error){ ++ case 0: ++ giterr_set(GITERR_SSL, "SSL error: unknown error"); ++ break; ++ case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: ++ giterr_set(GITERR_SSL, "SSL error: %x[%x] - %s", error, ssl->session_negotiate->verify_result, errbuf); ++ ret = GIT_ECERTIFICATE; ++ break; ++ default: ++ giterr_set(GITERR_SSL, "SSL error: %x - %s", error, errbuf); ++ } ++ ++ return ret; ++} ++ ++static int ssl_teardown(mbedtls_ssl_context *ssl) ++{ ++ int ret = 0; ++ ++ ret = mbedtls_ssl_close_notify(ssl); ++ if (ret < 0) ++ ret = ssl_set_error(ssl, ret); ++ ++ mbedtls_ssl_free(ssl); ++ return ret; ++} ++ ++static int check_host_name(const char *name, const char *host) ++{ ++ if (!strcasecmp(name, host)) ++ return 0; ++ ++ if (gitno__match_host(name, host) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int verify_server_cert(mbedtls_ssl_context *ssl, const char *host) ++{ ++ const mbedtls_x509_crt *cert; ++ const mbedtls_x509_sequence *alts; ++ int ret, matched = -1; ++ size_t sn_size = 512; ++ char subject_name[sn_size], alt_name[sn_size]; ++ ++ ++ if (( ret = mbedtls_ssl_get_verify_result(ssl) ) != 0) { ++ char vrfy_buf[512]; ++ mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", ret ); ++ giterr_set(GITERR_SSL, "The SSL certificate is invalid: %s", vrfy_buf); ++ return GIT_ECERTIFICATE; ++ } ++ ++ cert = mbedtls_ssl_get_peer_cert(ssl); ++ if (!cert) { ++ giterr_set(GITERR_SSL, "the server did not provide a certificate"); ++ return -1; ++ } ++ ++ /* Check the alternative names */ ++ alts = &cert->subject_alt_names; ++ while (alts != NULL && matched != 1) { ++ // Buffer is too small ++ if( alts->buf.len >= sn_size ) ++ goto on_error; ++ ++ memcpy(alt_name, alts->buf.p, alts->buf.len); ++ alt_name[alts->buf.len] = '\0'; ++ ++ if (!memchr(alt_name, '\0', alts->buf.len)) { ++ if (check_host_name(alt_name, host) < 0) ++ matched = 0; ++ else ++ matched = 1; ++ } ++ ++ alts = alts->next; ++ } ++ if (matched == 0) ++ goto cert_fail_name; ++ ++ if (matched == 1) ++ return 0; ++ ++ /* If no alternative names are available, check the common name */ ++ ret = mbedtls_x509_dn_gets(subject_name, sn_size, &cert->subject); ++ if (ret == 0) ++ goto on_error; ++ if (memchr(subject_name, '\0', ret)) ++ goto cert_fail_name; ++ ++ if (check_host_name(subject_name, host) < 0) ++ goto cert_fail_name; ++ ++ return 0; ++ ++on_error: ++ return ssl_set_error(ssl, 0); ++ ++cert_fail_name: ++ giterr_set(GITERR_SSL, "hostname does not match certificate"); ++ return GIT_ECERTIFICATE; ++} ++ ++typedef struct { ++ git_stream parent; ++ git_stream *io; ++ bool connected; ++ char *host; ++ mbedtls_ssl_context *ssl; ++ git_cert_x509 cert_info; ++} mbedtls_stream; ++ ++ ++int mbedtls_connect(git_stream *stream) ++{ ++ int ret; ++ mbedtls_stream *st = (mbedtls_stream *) stream; ++ ++ if ((ret = git_stream_connect(st->io)) < 0) ++ return ret; ++ ++ st->connected = true; ++ ++ mbedtls_ssl_set_hostname(st->ssl, st->host); ++ ++ mbedtls_ssl_set_bio(st->ssl, st->io, bio_write, bio_read, NULL); ++ ++ if ((ret = mbedtls_ssl_handshake(st->ssl)) != 0) ++ return ssl_set_error(st->ssl, ret); ++ ++ return verify_server_cert(st->ssl, st->host); ++} ++ ++int mbedtls_certificate(git_cert **out, git_stream *stream) ++{ ++ unsigned char *encoded_cert; ++ mbedtls_stream *st = (mbedtls_stream *) stream; ++ ++ const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(st->ssl); ++ if (!cert) { ++ giterr_set(GITERR_SSL, "the server did not provide a certificate"); ++ return -1; ++ } ++ ++ /* Retrieve the length of the certificate first */ ++ if (cert->raw.len == 0) { ++ giterr_set(GITERR_NET, "failed to retrieve certificate information"); ++ return -1; ++ } ++ ++ encoded_cert = git__malloc(cert->raw.len); ++ GITERR_CHECK_ALLOC(encoded_cert); ++ memcpy(encoded_cert, cert->raw.p, cert->raw.len); ++ ++ st->cert_info.parent.cert_type = GIT_CERT_X509; ++ st->cert_info.data = encoded_cert; ++ st->cert_info.len = cert->raw.len; ++ ++ *out = &st->cert_info.parent; ++ ++ return 0; ++} ++ ++static int mbedtls_set_proxy(git_stream *stream, const char *proxy_url) ++{ ++ mbedtls_stream *st = (mbedtls_stream *) stream; ++ ++ return git_stream_set_proxy(st->io, proxy_url); ++} ++ ++ssize_t mbedtls_stream_write(git_stream *stream, const char *data, size_t len, int flags) ++{ ++ mbedtls_stream *st = (mbedtls_stream *) stream; ++ int ret; ++ ++ GIT_UNUSED(flags); ++ ++ if ((ret = mbedtls_ssl_write(st->ssl, (const unsigned char *)data, len)) <= 0) { ++ return ssl_set_error(st->ssl, ret); ++ } ++ ++ return ret; ++} ++ ++ssize_t mbedtls_stream_read(git_stream *stream, void *data, size_t len) ++{ ++ mbedtls_stream *st = (mbedtls_stream *) stream; ++ int ret; ++ ++ if ((ret = mbedtls_ssl_read(st->ssl, (unsigned char *)data, len)) <= 0) ++ ssl_set_error(st->ssl, ret); ++ ++ return ret; ++} ++ ++int mbedtls_stream_close(git_stream *stream) ++{ ++ mbedtls_stream *st = (mbedtls_stream *) stream; ++ int ret = 0; ++ ++ if (st->connected && (ret = ssl_teardown(st->ssl)) != 0) ++ return -1; ++ ++ st->connected = false; ++ ++ return git_stream_close(st->io); ++} ++ ++void mbedtls_stream_free(git_stream *stream) ++{ ++ mbedtls_stream *st = (mbedtls_stream *) stream; ++ ++ git__free(st->host); ++ git__free(st->cert_info.data); ++ git_stream_free(st->io); ++ git__free(st->ssl); ++ git__free(st); ++} ++ ++int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port) ++{ ++ int error; ++ mbedtls_stream *st; ++ ++ st = git__calloc(1, sizeof(mbedtls_stream)); ++ GITERR_CHECK_ALLOC(st); ++ ++#ifdef GIT_CURL ++ error = git_curl_stream_new(&st->io, host, port); ++#else ++ error = git_socket_stream_new(&st->io, host, port); ++#endif ++ ++ if (error < 0) ++ return error; ++ ++ st->ssl = git__malloc(sizeof(mbedtls_ssl_context)); ++ GITERR_CHECK_ALLOC(st->ssl); ++ mbedtls_ssl_init(st->ssl); ++ if( (error = mbedtls_ssl_setup(st->ssl, git__ssl_conf)) != 0 ) { ++ mbedtls_ssl_free(st->ssl); ++ giterr_set(GITERR_SSL, "failed to create ssl object"); ++ return -1; ++ } ++ ++ st->host = git__strdup(host); ++ GITERR_CHECK_ALLOC(st->host); ++ ++ st->parent.version = GIT_STREAM_VERSION; ++ st->parent.encrypted = 1; ++ st->parent.proxy_support = git_stream_supports_proxy(st->io); ++ st->parent.connect = mbedtls_connect; ++ st->parent.certificate = mbedtls_certificate; ++ st->parent.set_proxy = mbedtls_set_proxy; ++ st->parent.read = mbedtls_stream_read; ++ st->parent.write = mbedtls_stream_write; ++ st->parent.close = mbedtls_stream_close; ++ st->parent.free = mbedtls_stream_free; ++ ++ *out = (git_stream *) st; ++ return 0; ++} ++ ++#else ++ ++#include "stream.h" ++#include "git2/sys/openssl.h" ++ ++int git_mbedtls_stream_global_init(void) ++{ ++ return 0; ++} ++ ++int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port) ++{ ++ GIT_UNUSED(out); ++ GIT_UNUSED(host); ++ GIT_UNUSED(port); ++ ++ giterr_set(GITERR_SSL, "mbedTLS is not supported in this version"); ++ return -1; ++} ++ ++#endif ++ +diff --git a/src/mbedtls_stream.h b/src/mbedtls_stream.h +new file mode 100644 +index 0000000..5cb1071 +--- /dev/null ++++ b/src/mbedtls_stream.h +@@ -0,0 +1,16 @@ ++/* ++ * 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_mbedtls_stream_h__ ++#define INCLUDE_mbedtls_stream_h__ ++ ++#include "git2/sys/stream.h" ++ ++extern int git_mbedtls_stream_global_init(void); ++ ++extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port); ++ ++#endif +diff --git a/src/settings.c b/src/settings.c +index 0da19ea..65bbb41 100644 +--- a/src/settings.c ++++ b/src/settings.c +@@ -9,6 +9,10 @@ + # include + #endif + ++#ifdef GIT_MBEDTLS ++# include ++#endif ++ + #include + #include "common.h" + #include "sysdir.h" +@@ -29,7 +33,7 @@ int git_libgit2_features() + #ifdef GIT_THREADS + | GIT_FEATURE_THREADS + #endif +-#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) ++#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) || defined(GIT_MBEDTLS) + | GIT_FEATURE_HTTPS + #endif + #if defined(GIT_SSH) +@@ -174,8 +178,34 @@ int git_libgit2_opts(int key, ...) + error = -1; + } + } ++#elif GIT_MBEDTLS ++ { ++ const char *file = va_arg(ap, const char *); ++ const char *path = va_arg(ap, const char *); ++ int ret = 0; ++ char errbuf[512]; ++ mbedtls_x509_crt *cacert; ++ cacert = git__malloc(sizeof(mbedtls_x509_crt)); ++ mbedtls_x509_crt_init(cacert); ++ if (file) { ++ ret = mbedtls_x509_crt_parse_file(cacert, file); ++ } else if (path) { ++ ret = mbedtls_x509_crt_parse_path(cacert, path); ++ } ++ if (!ret) { ++ mbedtls_x509_crt_free(cacert); ++ git__free(cacert); ++ mbedtls_strerror( ret, errbuf, 512 ); ++ giterr_set(GITERR_SSL, "SSL error: failed to load CA certificates : %s (%d)", ret, errbuf); ++ error = -1; ++ } else { ++ mbedtls_x509_crt_free(git__ssl_conf->ca_chain); ++ git__free(git__ssl_conf->ca_chain); ++ mbedtls_ssl_conf_ca_chain(git__ssl_conf, cacert, NULL); ++ } ++ } + #else +- giterr_set(GITERR_NET, "cannot set certificate locations: OpenSSL is not enabled"); ++ giterr_set(GITERR_NET, "Cannot set certificate locations: OpenSSL or mbedTLS is not enabled"); + error = -1; + #endif + break; +diff --git a/src/tls_stream.c b/src/tls_stream.c +index 83e2d06..6fb538f 100644 +--- a/src/tls_stream.c ++++ b/src/tls_stream.c +@@ -9,6 +9,7 @@ + #include "common.h" + + #include "openssl_stream.h" ++#include "mbedtls_stream.h" + #include "stransport_stream.h" + + static git_stream_cb tls_ctor; +@@ -30,6 +31,8 @@ int git_tls_stream_new(git_stream **out, const char *host, const char *port) + return git_stransport_stream_new(out, host, port); + #elif defined(GIT_OPENSSL) + return git_openssl_stream_new(out, host, port); ++#elif defined(GIT_MBEDTLS) ++ return git_mbedtls_stream_new(out, host, port); + #else + GIT_UNUSED(out); + GIT_UNUSED(host); +diff --git a/src/transport.c b/src/transport.c +index 327052f..a438459 100644 +--- a/src/transport.c ++++ b/src/transport.c +@@ -29,7 +29,7 @@ static transport_definition local_transport_definition = { "file://", git_transp + static transport_definition transports[] = { + { "git://", git_transport_smart, &git_subtransport_definition }, + { "http://", git_transport_smart, &http_subtransport_definition }, +-#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) ++#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) || defined(GIT_MBEDTLS) + { "https://", git_transport_smart, &http_subtransport_definition }, + #endif + { "file://", git_transport_local, NULL }, +diff --git a/src/transports/http.c b/src/transports/http.c +index 88b124b..f4474ef 100644 +--- a/src/transports/http.c ++++ b/src/transports/http.c +@@ -597,7 +597,7 @@ static int http_connect(http_subtransport *t) + + error = git_stream_connect(t->io); + +-#if defined(GIT_OPENSSL) || defined(GIT_SECURE_TRANSPORT) || defined(GIT_CURL) ++#if defined(GIT_OPENSSL) || defined(GIT_SECURE_TRANSPORT) || defined(GIT_CURL) || defined(GIT_MBEDTLS) + if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL && + git_stream_is_encrypted(t->io)) { + git_cert *cert; +diff --git a/tests/core/stream.c b/tests/core/stream.c +index 0cbf442..a4fa2b4 100644 +--- a/tests/core/stream.c ++++ b/tests/core/stream.c +@@ -38,7 +38,7 @@ void test_core_stream__register_tls(void) + * with Security framework). + */ + #if defined(GIT_WIN32) || \ +- (!defined(GIT_SECURE_TRANSPORT) && !defined(GIT_OPENSSL)) ++ (!defined(GIT_SECURE_TRANSPORT) && !(defined(GIT_OPENSSL) || defined(GIT_MBEDTLS))) + cl_git_fail_with(-1, error); + #else + cl_git_pass(error); +diff --git a/tests/online/badssl.c b/tests/online/badssl.c +index 66b090d..bba31cc 100644 +--- a/tests/online/badssl.c ++++ b/tests/online/badssl.c +@@ -4,7 +4,7 @@ + + static git_repository *g_repo; + +-#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) ++#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) || defined(GIT_MBEDTLS) + static bool g_has_ssl = true; + #else + static bool g_has_ssl = false; diff --git a/deps/patches/libgit2-require-openssl.patch b/deps/patches/libgit2-require-openssl.patch deleted file mode 100644 index fce6e10635397..0000000000000 --- a/deps/patches/libgit2-require-openssl.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 73c9630..3dedd0a 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -217,7 +217,7 @@ ELSE () - ENDIF () - - IF (NOT AMIGA AND USE_OPENSSL) -- FIND_PACKAGE(OpenSSL) -+ FIND_PACKAGE(OpenSSL REQUIRED) - ENDIF () - - IF (CURL_FOUND)