---
This is necessary to get the libgit2 patch I submitted through. I noted
this as [WIP] because I'm able to compile this, but it fails in the
check() - however, I get the same errors when building the latest
version of Julia as well. CC'd the current maintainer of this package,
can you take a look?
community/julia/APKBUILD | 12 +-
community/julia/update-libgit2-0.26.0.patch | 5642 +++++++++++++++++++++++++++
2 files changed, 5649 insertions(+), 5 deletions(-)
create mode 100644 community/julia/update-libgit2-0.26.0.patch
diff --git a/community/julia/APKBUILD b/community/julia/APKBUILD
index 973a811f27..1e2a74c03b 100644
--- a/community/julia/APKBUILD
+++ b/community/julia/APKBUILD
@@ -2,9 +2,9 @@
# Contributor: Shiz <hi@shiz.me>
# Maintainer: Shiz <hi@shiz.me>
pkgname=julia
-pkgver=0.6.0
+pkgver=0.6.2
# Keep in sync with deps/libuv.version.
-_libuv_ver=52d72a52cc7ccd570929990f010ed16e2ec604c8
+_libuv_ver=d8ab1c6a33e77bf155facb54215dd8798e13825d
_llvm_ver=3.9
pkgrel=0
pkgdesc="A high-level, high-performance dynamic language for technical computing"
@@ -63,6 +63,7 @@ source="https://github.com/JuliaLang/julia/releases/download/v$pkgver/$pkgname-$
test-disable-tests-using-fake_pty.patch
test-libgit2-skip-SSL_CERT_FILE.patch
test-repl-disable-22176-20482.patch
+ update-libgit2-0.26.0.patch
"
builddir="$srcdir/$pkgname-$pkgver"
ldpath="/usr/lib/julia"
@@ -171,8 +172,8 @@ dbg() {
mv "$pkgdir"/usr/lib/julia/*-debug.* "$subpkgdir"/usr/lib/julia/
}
-sha512sums="da21b35eb2c682c0fb8720974a76759c51fe993f10e6af5ca4864fc7f0bb6c90d880b706eb798476c7228bae2db19ff0825add6a2abde2961f16a93a3050cb69 julia-0.6.0.tar.gz
-4bf9c8b16617691b70ea43c667ecc575d2a06b3d0c347b949d10360c012138585a13ecea5e18de81b1585a96cf7734b7cc3d6072490898f1d5531c702cf5afab libuv-52d72a52cc7ccd570929990f010ed16e2ec604c8.tar.gz
+sha512sums="679050463ed5825d34c477bd44cd91cfecc7d1735a2f52cc70b509afd9883cb60902861643266ecac5ba6cbb03f8fcdd12fc2e87dc41b9ed0eef813fa40610f1 julia-0.6.2.tar.gz
+272e3cc7b1290ef19cc941c3b3e6dd39dba7dcb26f0aea8e667c48c56288aa9266020504e0cc90074f02881521b3352079416f564c7eb24ab444326a8f04ca64 libuv-d8ab1c6a33e77bf155facb54215dd8798e13825d.tar.gz
43eaf66d9cb3748012b2dfd77da1b41f667c5c7602a56bea8186b796b215bde82d555d79ab053378c2222521396354dcce5cf23a78fa3b1456062c47771c8433 UnicodeData.txt
0283c7b0ff7dd99ae79f6ddac63513ce7d58ba31de506a3fee07af9b8882ddc275d0f9cb002381ba1e304bcacf252612fa16b21b85667422477e6b945b725899 find-syslibs
f812b05b7712975eaef0bf071dd2c1cd0b21c68b18d6a513878bb8fe877bfcadf9f4b9dd8cd27b6809378de5b250a010301e7a90169677d155ad2ba377e8b428 0001-hardened.patch
@@ -183,4 +184,5 @@ a66526aee8745875b254f0d27db78b10e76cd8489f4601c77b82674a31ee7a0cf417af8b24a520e0
3f2a6cf439aaada90872b869972f17b506d2f39758f3e2407c3e5f6b28082e7797ed6f2d7e4bace56e02809fe94f879c2a34e22216aa19b08a452371b81e7462 fix-or-disable-broken-tests.patch
be3eea9d7506796a48171d244e61e8ee3f69ee659aa65ee738a7ec08499566a014bd6ee21ba39ec97e74d734a8b45b7ec1f5a630a96a31a6d4e17b274107b640 test-disable-tests-using-fake_pty.patch
a97a16e3b36c7c192c1133139c87b7b3a719cef645dd2435828b5b5468f4f9beb3bba0e02bb68935319dc150d0c4ccd4728c9eaedc9e2ddee2d823e881f36e2c test-libgit2-skip-SSL_CERT_FILE.patch
-fc5eef406d84b60fdf1c837aa1f5bd0e7a205c311853d0ae8b2b237e2eb750d7da2152632d866d372174918a3953746620f2bf130596ab2b027ca389a6816edd test-repl-disable-22176-20482.patch"
+fc5eef406d84b60fdf1c837aa1f5bd0e7a205c311853d0ae8b2b237e2eb750d7da2152632d866d372174918a3953746620f2bf130596ab2b027ca389a6816edd test-repl-disable-22176-20482.patch
+fb9b4ea938284a31f6f062ecafc977f6c85a3550125857f6b2b138b84222b3cdeb4ed4739ac77e7c254644921e3ce203b83dc9bb62fbb96755ca2740ada68f77 update-libgit2-0.26.0.patch"
diff --git a/community/julia/update-libgit2-0.26.0.patch b/community/julia/update-libgit2-0.26.0.patch
new file mode 100644
index 0000000000..940d5314e4
--- /dev/null
+++ b/community/julia/update-libgit2-0.26.0.patch
@@ -0,0 +1,5642 @@
+From 158d65581dda29e6b9d85c6bc9ba612a09e73210 Mon Sep 17 00:00:00 2001
+From: Curtis Vogt <curtis.vogt@gmail.com>
+Date: Fri, 23 Jun 2017 17:23:41 -0500
+Subject: [PATCH 1/2] Update to LibGit2 v0.26.0
+
+---
+ .../md5 | 1 +
+ .../sha512 | 1 +
+ .../md5 | 1 -
+ .../sha512 | 1 -
+ deps/libgit2.mk | 28 +-
+ deps/libgit2.version | 4 +-
+ deps/patches/libgit2-gitconfig-symlink.patch | 27 -
+ deps/patches/libgit2-mbedtls-fixup.patch | 70 +
+ deps/patches/libgit2-mbedtls-verify.patch | 147 +-
+ deps/patches/libgit2-mbedtls-writer-fix.patch | 30 -
+ deps/patches/libgit2-mbedtls.patch | 4827 ++++++++++++++++++--
+ deps/patches/libgit2-remote-push-NULL.patch | 26 -
+ 14 files changed, 4521 insertions(+), 711 deletions(-)
+ create mode 100644 deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/md5
+ create mode 100644 deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/sha512
+ delete mode 100644 deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/md5
+ delete mode 100644 deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/sha512
+ delete mode 100644 deps/patches/libgit2-gitconfig-symlink.patch
+ create mode 100644 deps/patches/libgit2-mbedtls-fixup.patch
+ delete mode 100644 deps/patches/libgit2-mbedtls-writer-fix.patch
+ delete mode 100644 deps/patches/libgit2-remote-push-NULL.patch
+
+diff --git a/deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/md5 b/deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/md5
+new file mode 100644
+index 000000000000..f148bce28a5c
+--- /dev/null
++++ b/deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/md5
+@@ -0,0 +1 @@
++0d6fd3ed9265c6804349149b23ae6362
+diff --git a/deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/sha512 b/deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/sha512
+new file mode 100644
+index 000000000000..1e129704580c
+--- /dev/null
++++ b/deps/checksums/libgit2-15e119375018fba121cf58e02a9f17fe22df0df8.tar.gz/sha512
+@@ -0,0 +1 @@
++88a8a42bb8d18a5a722938404e048266d0899362ac89fdfedfa9f71aeb90408d8d98b4d9b9ea2ff46755d0a2cd8686ff04d31e85827566e1290a9536b8b36ac8
+diff --git a/deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/md5 b/deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/md5
+deleted file mode 100644
+index ccc33a35bb05..000000000000
+--- a/deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/md5
++++ /dev/null
+@@ -1 +0,0 @@
+-fb1f1140f9b55fc8499caa960382fc03
+diff --git a/deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/sha512 b/deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/sha512
+deleted file mode 100644
+index cc5156e0c027..000000000000
+--- a/deps/checksums/libgit2-2fcb8705e584ca61f6c4657525c9d2713f6a39d2.tar.gz/sha512
++++ /dev/null
+@@ -1 +0,0 @@
+-2086269728e14c0ec38f322b01f89d4d98a31a395cab3937591826a232193f00ec07bafe938ad99d70c74cb695af26c7228513019bfe6fc06427229bd2e098cf
+diff --git a/deps/libgit2.mk b/deps/libgit2.mk
+index c98528e52ae8..d83d0864c344 100644
+--- a/deps/libgit2.mk
++++ b/deps/libgit2.mk
+@@ -37,7 +37,7 @@ LIBGIT2_OPTS += -DCURL_INCLUDE_DIRS=$(build_includedir) -DCURL_LIBRARIES="-L$(bu
+ endif
+
+ ifeq ($(OS),Linux)
+-LIBGIT2_OPTS += -DUSE_OPENSSL=OFF -DUSE_MBEDTLS=ON -DCMAKE_INSTALL_RPATH="\$$ORIGIN"
++LIBGIT2_OPTS += -DUSE_HTTPS=ON -DTLS_BACKEND="mbedTLS" -DCMAKE_INSTALL_RPATH="\$$ORIGIN"
+ endif
+ ifeq ($(OS),FreeBSD)
+ LIBGIT2_OPTS += -DCMAKE_INSTALL_RPATH="\$$ORIGIN"
+@@ -78,29 +78,14 @@ $(LIBGIT2_SRC_PATH)/libgit2-agent-nonfatal.patch-applied: $(LIBGIT2_SRC_PATH)/so
+ patch -p1 -f < $(SRCDIR)/patches/libgit2-agent-nonfatal.patch
+ echo 1 > $@
+
+-$(LIBGIT2_SRC_PATH)/libgit2-mbedtls-writer-fix.patch-applied: $(LIBGIT2_SRC_PATH)/source-extracted | $(LIBGIT2_SRC_PATH)/libgit2-mbedtls.patch-applied
+- cd $(LIBGIT2_SRC_PATH) && \
+- patch -p1 -f < $(SRCDIR)/patches/libgit2-mbedtls-writer-fix.patch
+- echo 1 > $@
+-
+-$(LIBGIT2_SRC_PATH)/libgit2-mbedtls-verify.patch-applied: $(LIBGIT2_SRC_PATH)/source-extracted | $(LIBGIT2_SRC_PATH)/libgit2-mbedtls-writer-fix.patch-applied
++$(LIBGIT2_SRC_PATH)/libgit2-mbedtls-verify.patch-applied: $(LIBGIT2_SRC_PATH)/source-extracted | $(LIBGIT2_SRC_PATH)/libgit2-agent-nonfatal.patch-applied
+ cd $(LIBGIT2_SRC_PATH) && \
+ patch -p1 -f < $(SRCDIR)/patches/libgit2-mbedtls-verify.patch
+ echo 1 > $@
+
+-$(LIBGIT2_SRC_PATH)/libgit2-gitconfig-symlink.patch-applied: $(LIBGIT2_SRC_PATH)/source-extracted | $(LIBGIT2_SRC_PATH)/libgit2-mbedtls-verify.patch-applied
+- cd $(LIBGIT2_SRC_PATH) && \
+- patch -p1 -f < $(SRCDIR)/patches/libgit2-gitconfig-symlink.patch
+- echo 1 > $@
+-
+-$(LIBGIT2_SRC_PATH)/libgit2-free-config.patch-applied: $(LIBGIT2_SRC_PATH)/source-extracted | $(LIBGIT2_SRC_PATH)/libgit2-gitconfig-symlink.patch-applied
+- cd $(LIBGIT2_SRC_PATH) && \
+- patch -p1 -f < $(SRCDIR)/patches/libgit2-free-config.patch
+- echo 1 > $@
+-
+-$(LIBGIT2_SRC_PATH)/libgit2-remote-push-NULL.patch-applied: $(LIBGIT2_SRC_PATH)/source-extracted | $(LIBGIT2_SRC_PATH)/libgit2-free-config.patch-applied
++$(LIBGIT2_SRC_PATH)/libgit2-mbedtls-fixup.patch-applied: $(LIBGIT2_SRC_PATH)/source-extracted | $(LIBGIT2_SRC_PATH)/libgit2-mbedtls-verify.patch-applied
+ cd $(LIBGIT2_SRC_PATH) && \
+- patch -p1 -f < $(SRCDIR)/patches/libgit2-remote-push-NULL.patch
++ patch -p1 -f < $(SRCDIR)/patches/libgit2-mbedtls-fixup.patch
+ echo 1 > $@
+
+ $(build_datarootdir)/julia/cert.pem: $(CERTFILE)
+@@ -111,11 +96,8 @@ $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: \
+ $(LIBGIT2_SRC_PATH)/libgit2-mbedtls.patch-applied \
+ $(LIBGIT2_SRC_PATH)/libgit2-ssh.patch-applied \
+ $(LIBGIT2_SRC_PATH)/libgit2-agent-nonfatal.patch-applied \
+- $(LIBGIT2_SRC_PATH)/libgit2-mbedtls-writer-fix.patch-applied \
+ $(LIBGIT2_SRC_PATH)/libgit2-mbedtls-verify.patch-applied \
+- $(LIBGIT2_SRC_PATH)/libgit2-gitconfig-symlink.patch-applied \
+- $(LIBGIT2_SRC_PATH)/libgit2-free-config.patch-applied \
+- $(LIBGIT2_SRC_PATH)/libgit2-remote-push-NULL.patch-applied
++ $(LIBGIT2_SRC_PATH)/libgit2-mbedtls-fixup.patch-applied
+
+ ifneq ($(CERTFILE),)
+ $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: $(build_datarootdir)/julia/cert.pem
+diff --git a/deps/libgit2.version b/deps/libgit2.version
+index f5596b2fce3b..306384f5cd76 100644
+--- a/deps/libgit2.version
++++ b/deps/libgit2.version
+@@ -1,2 +1,2 @@
+-LIBGIT2_BRANCH=v0.25.1
+-LIBGIT2_SHA1=2fcb8705e584ca61f6c4657525c9d2713f6a39d2
++LIBGIT2_BRANCH=v0.26.0
++LIBGIT2_SHA1=15e119375018fba121cf58e02a9f17fe22df0df8
+diff --git a/deps/patches/libgit2-gitconfig-symlink.patch b/deps/patches/libgit2-gitconfig-symlink.patch
+deleted file mode 100644
+index bd4e983045be..000000000000
+--- a/deps/patches/libgit2-gitconfig-symlink.patch
++++ /dev/null
+@@ -1,27 +0,0 @@
+-From 86a8cd9f6a039889801b5bec865a4bc3deb30f47 Mon Sep 17 00:00:00 2001
+-From: Sven Strickroth2 <email@cs-ware.de>
+-Date: Mon, 20 Mar 2017 11:21:00 +0100
+-Subject: [PATCH] filebuf: fix resolving absolute symlinks
+-
+-The symlink destination is always concatenated to the original path. Fix
+-this by using `git_buf_sets` instead of `git_buf_puts`.
+----
+- src/filebuf.c | 2 +-
+- 1 file changed, 1 insertion(+), 1 deletion(-)
+-
+-diff --git a/src/filebuf.c b/src/filebuf.c
+-index ef68b16f4..825b9c04c 100644
+---- a/src/filebuf.c
+-+++ b/src/filebuf.c
+-@@ -246,7 +246,7 @@ static int resolve_symlink(git_buf *out, const char *path)
+-
+- root = git_path_root(target.ptr);
+- if (root >= 0) {
+-- if ((error = git_buf_puts(&curpath, target.ptr)) < 0)
+-+ if ((error = git_buf_sets(&curpath, target.ptr)) < 0)
+- goto cleanup;
+- } else {
+- git_buf dir = GIT_BUF_INIT;
+---
+-2.12.2
+-
+diff --git a/deps/patches/libgit2-mbedtls-fixup.patch b/deps/patches/libgit2-mbedtls-fixup.patch
+new file mode 100644
+index 000000000000..2ec6fbd7167a
+--- /dev/null
++++ b/deps/patches/libgit2-mbedtls-fixup.patch
+@@ -0,0 +1,70 @@
++commit de8721ae70dfae529fdb50224a47eadf6d29c574
++Author: Curtis Vogt <curtis.vogt@gmail.com>
++Date: Thu Jun 29 16:31:08 2017 -0500
++
++ Corrections to mbedtls support with LibGit2 0.26.0
++
++diff --git a/src/settings.c b/src/settings.c
++index 3a46f0d..4d976a0 100644
++--- a/src/settings.c
+++++ b/src/settings.c
++@@ -179,14 +179,18 @@ int git_libgit2_opts(int key, ...)
++ const char *path = va_arg(ap, const char *);
++ error = git_openssl_set_cert_file(file, path);
++ }
++-#elif GIT_MBEDTLS
+++#elif defined(GIT_MBEDTLS)
++ {
++ const char *file = va_arg(ap, const char *);
++ const char *path = va_arg(ap, const char *);
++- if (file)
+++ if (file) {
++ error = git_mbedtls_set_cert_file(file, 0);
++- if (error && path)
++- error = git_mbedtls_set_cert_file(path, 0);
+++ } else if (path) {
+++ error = git_mbedtls_set_cert_file(path, 1);
+++ } else {
+++ giterr_set(GITERR_NET, "cannot set certificate locations: no file or path given");
+++ error = -1;
+++ }
++ }
++ #else
++ giterr_set(GITERR_NET, "cannot set certificate locations: OpenSSL or mbedTLS is not enabled");
++diff --git a/src/streams/mbedtls.c b/src/streams/mbedtls.c
++index e456ea8..b4eb991 100644
++--- a/src/streams/mbedtls.c
+++++ b/src/streams/mbedtls.c
++@@ -205,12 +205,12 @@ static int ssl_set_error(mbedtls_ssl_context *ssl, int 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);
+++ giterr_set(GITERR_SSL, "SSL error: 0x%04x [%x] - %s", error, ssl->session_negotiate->verify_result, errbuf);
++ ret = GIT_ECERTIFICATE;
++ break;
++
++ default:
++- giterr_set(GITERR_SSL, "SSL error: %x - %s", error, errbuf);
+++ giterr_set(GITERR_SSL, "SSL error: 0x%04x - %s", error, errbuf);
++ }
++
++ return ret;
++@@ -236,7 +236,7 @@ static int verify_server_cert(mbedtls_ssl_context *ssl, const char *host)
++ 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: %x - %s", ret, vrfy_buf);
+++ giterr_set(GITERR_SSL, "The SSL certificate is invalid: 0x%04x - %s", ret, vrfy_buf);
++ return GIT_ECERTIFICATE;
++ }
++
++@@ -430,7 +430,7 @@ int git_mbedtls_set_cert_file(const char *path, int is_dir)
++ ret = mbedtls_x509_crt_parse_file(cacert, path);
++ }
++ // mbedtls_x509_crt_parse_path returns the number of invalid certs on success
++- if (ret <= 0) {
+++ if (ret < 0) {
++ mbedtls_x509_crt_free(cacert);
++ git__free(cacert);
++ mbedtls_strerror( ret, errbuf, 512 );
+diff --git a/deps/patches/libgit2-mbedtls-verify.patch b/deps/patches/libgit2-mbedtls-verify.patch
+index 4c454c3adc4b..eb0b3854cbb0 100644
+--- a/deps/patches/libgit2-mbedtls-verify.patch
++++ b/deps/patches/libgit2-mbedtls-verify.patch
+@@ -1,99 +1,100 @@
+-diff --git a/src/mbedtls_stream.c b/src/mbedtls_stream.c
+-index bcc2e8b..4706102 100644
+---- a/src/mbedtls_stream.c
+-+++ b/src/mbedtls_stream.c
+-@@ -221,82 +221,34 @@ static int ssl_teardown(mbedtls_ssl_context *ssl)
+- return ret;
++commit eefe88eaf8c5c5b7c9a596da79e68dca3a3234d4
++Author: Curtis Vogt <curtis.vogt@gmail.com>
++Date: Thu Jun 29 16:30:53 2017 -0500
++
++ Use mbedtls certificate verification
++
++ Letting mbedtls handle all certficate verification and removed the
++ custom alternative names and common name checking.
++
++diff --git a/src/streams/mbedtls.c b/src/streams/mbedtls.c
++index 0376ee4..e456ea8 100644
++--- a/src/streams/mbedtls.c
+++++ b/src/streams/mbedtls.c
++@@ -228,82 +228,19 @@ static int ssl_teardown(mbedtls_ssl_context *ssl)
++ return ret;
+ }
+
+ -static int check_host_name(const char *name, const char *host)
+ -{
+-- if (!strcasecmp(name, host))
+-- return 0;
++- if (!strcasecmp(name, host))
++- return 0;
+ -
+-- if (gitno__match_host(name, host) < 0)
+-- return -1;
++- if (gitno__match_host(name, host) < 0)
++- return -1;
+ -
+-- return 0;
++- 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;
+-+ mbedtls_x509_crt *cert;
+-+ uint32_t flags;
+-+ int ret = -1;
+- size_t sn_size = 512;
+-- char subject_name[sn_size], alt_name[sn_size];
++- 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];
+ -
+-+ char buf[sn_size];
+++ int ret = -1;
+++ (void)(host); // Suppress unused parameter warning
+
+- 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);
+-+ mbedtls_x509_crt_verify_info(buf, sn_size, " ! ", ret);
+-+ giterr_set(GITERR_SSL, "The SSL certificate is invalid: %s", buf);
+- return GIT_ECERTIFICATE;
+- }
++ 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);
+++ mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "", ret);
+++ giterr_set(GITERR_SSL, "The SSL certificate is invalid: %x - %s", ret, vrfy_buf);
++ return GIT_ECERTIFICATE;
++ }
+
+-- cert = mbedtls_ssl_get_peer_cert(ssl);
+-+ cert = (mbedtls_x509_crt*) 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;
++- cert = mbedtls_ssl_get_peer_cert(ssl);
++- if (!cert) {
++- giterr_set(GITERR_SSL, "the server did not provide a certificate");
++- return -1;
++- }
+ -
+-- memcpy(alt_name, alts->buf.p, alts->buf.len);
+-- alt_name[alts->buf.len] = '\0';
++- /* 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;
+ -
+-- if (!memchr(alt_name, '\0', alts->buf.len)) {
+-- if (check_host_name(alt_name, host) < 0)
+-- matched = 0;
+-- else
+-- matched = 1;
+-- }
++- memcpy(alt_name, alts->buf.p, alts->buf.len);
++- alt_name[alts->buf.len] = '\0';
+ -
+-- alts = alts->next;
+-+ if (mbedtls_x509_crt_verify(cert, git__ssl_conf->ca_chain, NULL, host, &flags, NULL, NULL) != 0) {
+-+ mbedtls_x509_crt_verify_info(buf, sn_size, "", flags);
+-+ buf[strlen(buf) - 1] = '\0'; // Remove trailing newline
+-+ giterr_set(GITERR_SSL, buf);
+-+ return GIT_ECERTIFICATE;
+- }
+-- if (matched == 0)
+-- goto cert_fail_name;
++- if (!memchr(alt_name, '\0', alts->buf.len)) {
++- if (check_host_name(alt_name, host) < 0)
++- matched = 0;
++- else
++- matched = 1;
++- }
+ -
+-- if (matched == 1)
+-- return 0;
++- alts = alts->next;
++- }
++- if (matched == 0)
++- goto cert_fail_name;
+ -
+-- /* 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 (matched == 1)
++- return 0;
+ -
+-- if (check_host_name(subject_name, host) < 0)
+-- goto cert_fail_name;
+-
+- 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);
++- return ssl_set_error(ssl, 0);
+ -
+ -cert_fail_name:
+-- giterr_set(GITERR_SSL, "hostname does not match certificate");
+-- return GIT_ECERTIFICATE;
++- giterr_set(GITERR_SSL, "hostname does not match certificate");
++- return GIT_ECERTIFICATE;
+ }
+
+ typedef struct {
+diff --git a/deps/patches/libgit2-mbedtls-writer-fix.patch b/deps/patches/libgit2-mbedtls-writer-fix.patch
+deleted file mode 100644
+index d80a637a3996..000000000000
+--- a/deps/patches/libgit2-mbedtls-writer-fix.patch
++++ /dev/null
+@@ -1,30 +0,0 @@
+-diff -rup libgit2-211e117a0590583a720c53172406f34186c543bd/src/mbedtls_stream.c libgit2-211e117a0590583a720c53172406f34186c543bd-fix-write/src/mbedtls_stream.c
+---- libgit2-211e117a0590583a720c53172406f34186c543bd/src/mbedtls_stream.c 2016-10-24 17:10:21.000000000 -0400
+-+++ libgit2-211e117a0590583a720c53172406f34186c543bd-fix-write/src/mbedtls_stream.c 2016-10-24 17:04:26.000000000 -0400
+-@@ -368,16 +368,20 @@ static int mbedtls_set_proxy(git_stream
+-
+- ssize_t mbedtls_stream_write(git_stream *stream, const char *data, size_t len, int flags)
+- {
+-+ size_t read = 0;
+- 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);
+-- }
+-+ do {
+-+ int error = mbedtls_ssl_write(st->ssl, (const unsigned char *)data + read, len - read);
+-+ if (error <= 0) {
+-+ return ssl_set_error(st->ssl, error);
+-+ }
+-+ read += error;
+-+ } while (read < len);
+-
+-- return ret;
+-+ return read;
+- }
+-
+- ssize_t mbedtls_stream_read(git_stream *stream, void *data, size_t len)
+-
+diff --git a/deps/patches/libgit2-mbedtls.patch b/deps/patches/libgit2-mbedtls.patch
+index 955f165eab75..af12728cf855 100644
+--- a/deps/patches/libgit2-mbedtls.patch
++++ b/deps/patches/libgit2-mbedtls.patch
+@@ -1,66 +1,282 @@
++commit 4d69ea1172fec234e0f3c8cee8574e9e13bf825e
++Author: Etienne Samson <samson.etienne@gmail.com>
++Date: Fri Jun 23 22:40:56 2017 +0000
++
++ mbedtls support for libgit2 v0.26.0
++
++ See https://github.com/libgit2/libgit2/pull/4173
++
++ cmake: simplify https support selection & tests
++
++ Gather streams to src/streams
++
++ Don't include OpenSSL from global.h so it doesn't namespace-leak
++
++ Have clar exit immediately on initialization failure
++
++ Generalize Travis' dependency installation
++
++ Add USE_HTTPS as a CMake option
++
++ It defaults to ON, e.g. "pick whatever default is appropriate for the platform".
++ It accepts one of SecureTransport, OpenSSL, WinHTTP, or OFF.
++ It errors if the backend library couldn't be found.
++
++ mbedtls: initial support
++
++ mbedtls: proper certificate verification
++
++ mbedtls: use libmbedcrypto for hashing
++
++ mbedtls: add global initialization
++
++ mbedtls: default cipher list support
++
++ mbedtls: load default CA certificates
++
++ mbedtls: fix libgit2 hanging due to incomplete writes
++
++ mbedtls: enable Travis CI tests
++
++ mbedtls: use our own certificate validation
++
++ Otherwise REQUIRED means that `git_stream_certificate` will always error.
++ We're doing the mbedtls check in verify_server_cert though.
++
++ mbedtls: try all CA locations, stopping after any loaded
++
++ WIP: distribution paths
++
++diff --git a/.travis.yml b/.travis.yml
++index af38252..e1be760 100644
++--- a/.travis.yml
+++++ b/.travis.yml
++@@ -45,11 +45,21 @@ matrix:
++ - VALGRIND=1
++ OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=OFF -DDEBUG_POOL=ON -DCMAKE_BUILD_TYPE=Debug"
++ os: linux
+++ - compiler: gcc
+++ env:
+++ MBEDTLS=1
+++ OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release -DUSE_TLS=mbedTLS -DMBEDTLS_ROOT_DIR=../mbedtls"
+++ os: linux
+++ - compiler: gcc
+++ env:
+++ MBEDTLS=1
+++ OPTIONS="-DTHREADSAFE=OFF -DBUILD_EXAMPLES=ON -DUSE_TLS=mbedTLS -DMBEDTLS_ROOT_DIR=../mbedtls"
+++ os: linux
++ allow_failures:
++ - env: COVERITY=1
++
++ install:
++- - if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./script/install-deps-${TRAVIS_OS_NAME}.sh; fi
+++ - if [ -x "./script/install-deps-${TRAVIS_OS_NAME}.sh" ]; then ./script/install-deps-${TRAVIS_OS_NAME}.sh; fi
++
++ # Run the Build script and tests
++ script:
+ diff --git a/CMakeLists.txt b/CMakeLists.txt
+-index 4e1104f..8110489 100644
++index 4783e3e..5d7dbe3 100644
+ --- a/CMakeLists.txt
+ +++ b/CMakeLists.txt
+-@@ -113,6 +113,10 @@ IF (HAVE_STRUCT_STAT_NSEC OR WIN32)
+- OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" ON )
++@@ -40,6 +40,7 @@ OPTION( LIBGIT2_FILENAME "Name of the produced binary" OFF )
++ OPTION( USE_SHA1DC "Use SHA-1 with collision detection" OFF )
++ OPTION( USE_ICONV "Link with and use iconv library" OFF )
++ OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
+++OPTION( USE_HTTPS "Enable HTTPS support" ON )
++ OPTION( USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF )
++ OPTION( VALGRIND "Configure build for valgrind" OFF )
++ OPTION( CURL "Use curl for HTTP if available" ON)
++@@ -89,10 +90,6 @@ IF(MSVC)
++ OPTION(MSVC_CRTDBG "Enable CRTDBG memory leak reporting" 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.
+-@@ -283,6 +287,10 @@ ELSE ()
++-IF (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
++- OPTION( USE_OPENSSL "Link with and use openssl library" ON )
++-ENDIF()
++-
++ CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtim "sys/types.h;sys/stat.h"
++ HAVE_STRUCT_STAT_ST_MTIM LANGUAGE C)
++ CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtimespec "sys/types.h;sys/stat.h"
++@@ -208,21 +205,6 @@ STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION ([0-9]+)$" "\\1" LIBGIT2_SOVERSION "$
++ # Find required dependencies
++ INCLUDE_DIRECTORIES(src include)
++
++-IF (SECURITY_FOUND)
++- # OS X 10.7 and older do not have some functions we use, fall back to OpenSSL there
++- CHECK_LIBRARY_EXISTS("${SECURITY_DIRS}" SSLCreateContext "Security/SecureTransport.h" HAVE_NEWER_SECURITY)
++- IF (HAVE_NEWER_SECURITY)
++- MESSAGE("-- Found Security ${SECURITY_DIRS}")
++- LIST(APPEND LIBGIT2_PC_LIBS "-framework Security")
++- ELSE()
++- MESSAGE("-- Security framework is too old, falling back to OpenSSL")
++- SET(SECURITY_FOUND "NO")
++- SET(SECURITY_DIRS "")
++- SET(SECURITY_DIR "")
++- SET(USE_OPENSSL "ON")
++- ENDIF()
++-ENDIF()
++-
++ IF (COREFOUNDATION_FOUND)
++ MESSAGE("-- Found CoreFoundation ${COREFOUNDATION_DIRS}")
++ LIST(APPEND LIBGIT2_PC_LIBS "-framework CoreFoundation")
++@@ -280,10 +262,14 @@ ELSE ()
++ PKG_CHECK_MODULES(CURL libcurl)
++ ENDIF ()
++
++- IF (NOT AMIGA AND USE_OPENSSL)
+++ IF (NOT AMIGA AND (USE_HTTPS STREQUAL "OpenSSL" OR USE_HTTPS STREQUAL "ON"))
+ FIND_PACKAGE(OpenSSL)
+ ENDIF ()
+
+-+ IF (NOT AMIGA AND USE_MBEDTLS)
+++ IF (NOT AMIGA AND (USE_HTTPS STREQUAL "mbedTLS" OR USE_HTTPS STREQUAL "ON"))
+ + FIND_PACKAGE(mbedTLS)
+ + ENDIF ()
+ +
+ IF (CURL_FOUND)
+ ADD_DEFINITIONS(-DGIT_CURL)
+ INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS})
+-@@ -316,6 +324,9 @@ ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin")
++@@ -293,6 +279,69 @@ ELSE ()
++ ENDIF()
++ ENDIF()
++
+++IF (USE_HTTPS STREQUAL "ON")
+++ IF (SECURITY_FOUND)
+++ # OS X 10.7 and older do not have some functions we use, fall back to OpenSSL there
+++ CHECK_LIBRARY_EXISTS("${SECURITY_DIRS}" SSLCreateContext "Security/SecureTransport.h" HAVE_NEWER_SECURITY)
+++ IF (HAVE_NEWER_SECURITY)
+++ MESSAGE("-- Found Security ${SECURITY_DIRS}")
+++ LIST(APPEND LIBGIT2_PC_LIBS "-framework Security")
+++ SET(HTTPS_BACKEND "SecureTransport")
+++ ELSE()
+++ MESSAGE("-- Security framework is too old, falling back to OpenSSL")
+++ SET(SECURITY_FOUND "NO")
+++ SET(SECURITY_DIRS "")
+++ SET(SECURITY_DIR "")
+++ SET(HTTPS_BACKEND "OpenSSL")
+++ ENDIF()
+++ ELSEIF(WINHTTP)
+++ SET(HTTPS_BACKEND "WinHTTP")
+++ ELSEIF(MBEDTLS_FOUND)
+++ SET(HTTPS_BACKEND "mbedTLS")
+++ ELSE()
+++ SET(HTTPS_BACKEND "OpenSSL")
+++ ENDIF()
+++ELSE()
+++ SET(HTTPS_BACKEND ${USE_HTTPS})
+++ENDIF()
+++
+++MESSAGE(STATUS "Using HTTPS backend ${HTTPS_BACKEND}")
+++
+++IF (HTTPS_BACKEND STREQUAL "SecureTransport")
+++ IF (NOT SECURITY_FOUND)
+++ MESSAGE(FATAL_ERROR "Asked for SecureTransport HTTPS backend, but it wasn't found")
+++ ENDIF()
+++
+++ ADD_DEFINITIONS(-DGIT_SECURE_TRANSPORT)
+++ INCLUDE_DIRECTORIES(${SECURITY_INCLUDE_DIR})
+++ELSEIF (HTTPS_BACKEND STREQUAL "OpenSSL")
+++ IF (NOT OPENSSL_FOUND)
+++ MESSAGE(FATAL_ERROR "Asked for OpenSSL HTTPS backend, but it wasn't found")
+++ ENDIF()
+++
+++ ADD_DEFINITIONS(-DGIT_OPENSSL)
+++ INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
+++ SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES})
+++ELSEIF (TLS_BACKEND STREQUAL "mbedTLS")
+++ IF (NOT MBEDTLS_FOUND)
+++ MESSAGE(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found")
+++ ENDIF()
+++
+++ ADD_DEFINITIONS(-DGIT_MBEDTLS)
+++ INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR})
+++ LINK_DIRECTORIES(${MBEDTLS_LIBRARY_DIR})
+++ SET(SSL_LIBRARIES ${MBEDTLS_LIBRARIES})
+++ELSEIF(HTTPS_BACKEND STREQUAL "WinHTTP")
+++ENDIF()
+++
+++IF (USE_HTTPS AND NOT HTTPS_BACKEND)
+++ MESSAGE(FATAL_ERROR "Asked for backend " ${HTTPS_BACKEND} " but it wasn't found")
+++ENDIF()
+++
+++IF (HTTPS_BACKEND)
+++ ADD_DEFINITIONS(-DGIT_HTTPS)
+++ENDIF()
+++
++ # Specify sha1 implementation
++ IF (USE_SHA1DC)
++ ADD_DEFINITIONS(-DGIT_SHA1_COLLISIONDETECT)
++@@ -303,15 +352,18 @@ IF (USE_SHA1DC)
++ ELSEIF (WIN32 AND NOT MINGW)
++ ADD_DEFINITIONS(-DGIT_SHA1_WIN32)
++ FILE(GLOB SRC_SHA1 src/hash/hash_win32.c)
++-ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+++ELSEIF (TLS_BACKEND MATCHES "SecureTransport")
++ ADD_DEFINITIONS(-DGIT_SHA1_COMMON_CRYPTO)
++-ELSEIF (OPENSSL_FOUND)
+++ELSEIF (TLS_BACKEND MATCHES "OpenSSL")
++ ADD_DEFINITIONS(-DGIT_SHA1_OPENSSL)
++ IF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
++ LIST(APPEND LIBGIT2_PC_LIBS "-lssl")
+ ELSE()
+ SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} openssl")
+ ENDIF ()
+-+ELSEIF (MBEDTLS_FOUND AND NOT SHA1_TYPE STREQUAL "builtin")
+++ELSEIF (TLS_BACKEND STREQUAL "mbedTLS")
+ + ADD_DEFINITIONS(-DMBEDTLS_SHA1)
+ + FILE(GLOB SRC_SHA1 src/hash/hash_mbedtls.c)
+ ELSE()
+ FILE(GLOB SRC_SHA1 src/hash/hash_generic.c)
+ ENDIF()
+-@@ -543,6 +554,11 @@ IF (OPENSSL_FOUND)
+- SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES})
++@@ -543,21 +595,6 @@ ELSE()
++ # that uses CMAKE_CONFIGURATION_TYPES and not CMAKE_BUILD_TYPE
+ ENDIF()
+
+-+IF (MBEDTLS_FOUND)
+-+ ADD_DEFINITIONS(-DGIT_MBEDTLS)
+-+ INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR})
+-+ SET(SSL_LIBRARIES ${MBEDTLS_LIBRARIES})
+-+ENDIF()
+-
+-
++-IF (SECURITY_FOUND)
++- ADD_DEFINITIONS(-DGIT_SECURE_TRANSPORT)
++- ADD_DEFINITIONS(-DGIT_HTTPS)
++- INCLUDE_DIRECTORIES(${SECURITY_INCLUDE_DIR})
++-ENDIF ()
++-
++-IF (OPENSSL_FOUND)
++- ADD_DEFINITIONS(-DGIT_OPENSSL)
++- ADD_DEFINITIONS(-DGIT_HTTPS)
++- INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
++- SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES})
++-ENDIF()
++-
++-
++-
+ IF (THREADSAFE)
+-@@ -688,7 +704,7 @@ IF (BUILD_CLAR)
++ IF (NOT WIN32)
++ FIND_PACKAGE(Threads REQUIRED)
++@@ -595,7 +632,12 @@ ELSE()
++ ENDIF()
++ FILE(GLOB SRC_OS src/unix/*.c src/unix/*.h)
++ ENDIF()
++-FILE(GLOB SRC_GIT2 src/*.c src/*.h src/transports/*.c src/transports/*.h src/xdiff/*.c src/xdiff/*.h)
+++FILE(GLOB SRC_GIT2
+++ src/*.c src/*.h
+++ src/streams/*.c src/streams/*.h
+++ src/transports/*.c src/transports/*.h
+++ src/xdiff/*.c src/xdiff/*.h
+++)
++
++ # Determine architecture of the machine
++ IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
++@@ -703,7 +745,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)
+++ IF (HAS_HTTPS_SUPPORT)
++ ADD_TEST(libgit2_clar libgit2_clar -ionline -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style)
+ ELSE ()
+- ADD_TEST(libgit2_clar libgit2_clar -v)
++ ADD_TEST(libgit2_clar libgit2_clar -v -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style)
+ diff --git a/cmake/Modules/FindmbedTLS.cmake b/cmake/Modules/FindmbedTLS.cmake
+ new file mode 100644
+-index 0000000..2f4adbc
++index 0000000..9329755
+ --- /dev/null
+ +++ b/cmake/Modules/FindmbedTLS.cmake
+-@@ -0,0 +1,64 @@
++@@ -0,0 +1,93 @@
+ +# - Try to find mbedTLS
+ +# Once done this will define
+ +#
+@@ -72,17 +288,46 @@ index 0000000..2f4adbc
+ +# MBEDTLS_LIBRARY - path to mbedTLS library
+ +# MBEDX509_LIBRARY - path to mbedTLS X.509 library
+ +# MBEDCRYPTO_LIBRARY - path to mbedTLS Crypto library
+++#
+++# Hint
+++# MBEDTLS_ROOT_DIR can be pointed to a local mbedTLS installation.
+++
+++SET(_MBEDTLS_ROOT_HINTS
+++ ${MBEDTLS_ROOT_DIR}
+++ ENV MBEDTLS_ROOT_DIR
+++)
+++
+++SET(_MBEDTLS_ROOT_HINTS_AND_PATHS
+++ HINTS ${_MBEDTLS_ROOT_HINTS}
+++ PATHS ${_MBEDTLS_ROOT_PATHS}
+++)
+ +
+-+FIND_PATH(MBEDTLS_INCLUDE_DIR mbedtls/version.h)
+++FIND_PATH(MBEDTLS_INCLUDE_DIR
+++ NAMES mbedtls/version.h
+++ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+++ PATH_SUFFIXES include
+++)
+ +
+ +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)
+++FIND_LIBRARY(MBEDTLS_LIBRARY
+++ NAMES mbedtls libmbedtls
+++ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+++ PATH_SUFFIXES library
+++)
+++FIND_LIBRARY(MBEDX509_LIBRARY
+++ NAMES mbedx509 libmbedx509
+++ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+++ PATH_SUFFIXES library
+++)
+++FIND_LIBRARY(MBEDCRYPTO_LIBRARY
+++ NAMES mbedcrypto libmbedcrypto
+++ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+++ PATH_SUFFIXES library
+++)
+ +
+ +IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY)
+ + SET(MBEDTLS_FOUND TRUE)
+@@ -125,68 +370,465 @@ index 0000000..2f4adbc
+ + MBEDX509_LIBRARY
+ + MBEDCRYPTO_LIBRARY
+ +)
++diff --git a/script/install-deps-linux.sh b/script/install-deps-linux.sh
++new file mode 100755
++index 0000000..94309b0
++--- /dev/null
+++++ b/script/install-deps-linux.sh
++@@ -0,0 +1,12 @@
+++#!/bin/sh
+++
+++echo "Installing dependencies"
+++if [ "$MBEDTLS" ]; then
+++ git clone https://github.com/ARMmbed/mbedtls.git ../mbedtls
+++ cd ../mbedtls
+++ git checkout mbedtls-2.4.2
+++ cmake -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF .
+++ cmake --build .
+++
+++ echo "mbedTLS built in `pwd`"
+++fi
++diff --git a/src/curl_stream.c b/src/curl_stream.c
++deleted file mode 100644
++index 4e0455c..0000000
++--- a/src/curl_stream.c
+++++ /dev/null
++@@ -1,362 +0,0 @@
++-/*
++- * 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_CURL
++-
++-#include <curl/curl.h>
++-
++-#include "stream.h"
++-#include "git2/transport.h"
++-#include "buffer.h"
++-#include "vector.h"
++-#include "proxy.h"
++-
++-/* This is for backwards compatibility with curl<7.45.0. */
++-#ifndef CURLINFO_ACTIVESOCKET
++-# define CURLINFO_ACTIVESOCKET CURLINFO_LASTSOCKET
++-# define GIT_CURL_BADSOCKET -1
++-# define git_activesocket_t long
++-#else
++-# define GIT_CURL_BADSOCKET CURL_SOCKET_BAD
++-# define git_activesocket_t curl_socket_t
++-#endif
++-
++-typedef struct {
++- git_stream parent;
++- CURL *handle;
++- curl_socket_t socket;
++- char curl_error[CURL_ERROR_SIZE + 1];
++- git_cert_x509 cert_info;
++- git_strarray cert_info_strings;
++- git_proxy_options proxy;
++- git_cred *proxy_cred;
++-} curl_stream;
++-
++-static int seterr_curl(curl_stream *s)
++-{
++- giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
++- return -1;
++-}
++-
++-GIT_INLINE(int) error_no_credentials(void)
++-{
++- giterr_set(GITERR_NET, "proxy authentication required, but no callback provided");
++- return GIT_EAUTH;
++-}
++-
++-static int apply_proxy_creds(curl_stream *s)
++-{
++- CURLcode res;
++- git_cred_userpass_plaintext *userpass;
++-
++- if (!s->proxy_cred)
++- return GIT_ENOTFOUND;
++-
++- userpass = (git_cred_userpass_plaintext *) s->proxy_cred;
++- if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYUSERNAME, userpass->username)) != CURLE_OK)
++- return seterr_curl(s);
++- if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYPASSWORD, userpass->password)) != CURLE_OK)
++- return seterr_curl(s);
++-
++- return 0;
++-}
++-
++-static int ask_and_apply_proxy_creds(curl_stream *s)
++-{
++- int error;
++- git_proxy_options *opts = &s->proxy;
++-
++- if (!opts->credentials)
++- return error_no_credentials();
++-
++- /* TODO: see if PROXYAUTH_AVAIL helps us here */
++- git_cred_free(s->proxy_cred);
++- s->proxy_cred = NULL;
++- giterr_clear();
++- error = opts->credentials(&s->proxy_cred, opts->url, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, opts->payload);
++- if (error == GIT_PASSTHROUGH)
++- return error_no_credentials();
++- if (error < 0) {
++- if (!giterr_last())
++- giterr_set(GITERR_NET, "proxy authentication was aborted by the user");
++- return error;
++- }
++-
++- if (s->proxy_cred->credtype != GIT_CREDTYPE_USERPASS_PLAINTEXT) {
++- giterr_set(GITERR_NET, "credentials callback returned invalid credential type");
++- return -1;
++- }
++-
++- return apply_proxy_creds(s);
++-}
++-
++-static int curls_connect(git_stream *stream)
++-{
++- curl_stream *s = (curl_stream *) stream;
++- git_activesocket_t sockextr;
++- long connect_last = 0;
++- int failed_cert = 0, error;
++- bool retry_connect;
++- CURLcode res;
++-
++- /* Apply any credentials we've already established */
++- error = apply_proxy_creds(s);
++- if (error < 0 && error != GIT_ENOTFOUND)
++- return seterr_curl(s);
++-
++- do {
++- retry_connect = 0;
++- res = curl_easy_perform(s->handle);
++-
++- curl_easy_getinfo(s->handle, CURLINFO_HTTP_CONNECTCODE, &connect_last);
++-
++- /* HTTP 407 Proxy Authentication Required */
++- if (connect_last == 407) {
++- if ((error = ask_and_apply_proxy_creds(s)) < 0)
++- return error;
++-
++- retry_connect = true;
++- }
++- } while (retry_connect);
++-
++- if (res != CURLE_OK && res != CURLE_PEER_FAILED_VERIFICATION)
++- return seterr_curl(s);
++- if (res == CURLE_PEER_FAILED_VERIFICATION)
++- failed_cert = 1;
++-
++- if ((res = curl_easy_getinfo(s->handle, CURLINFO_ACTIVESOCKET, &sockextr)) != CURLE_OK) {
++- return seterr_curl(s);
++- }
++-
++- if (sockextr == GIT_CURL_BADSOCKET) {
++- giterr_set(GITERR_NET, "curl socket is no longer valid");
++- return -1;
++- }
++-
++- s->socket = sockextr;
++-
++- if (s->parent.encrypted && failed_cert)
++- return GIT_ECERTIFICATE;
++-
++- return 0;
++-}
++-
++-static int curls_certificate(git_cert **out, git_stream *stream)
++-{
++- int error;
++- CURLcode res;
++- struct curl_slist *slist;
++- struct curl_certinfo *certinfo;
++- git_vector strings = GIT_VECTOR_INIT;
++- curl_stream *s = (curl_stream *) stream;
++-
++- if ((res = curl_easy_getinfo(s->handle, CURLINFO_CERTINFO, &certinfo)) != CURLE_OK)
++- return seterr_curl(s);
++-
++- /* No information is available, can happen with SecureTransport */
++- if (certinfo->num_of_certs == 0) {
++- s->cert_info.parent.cert_type = GIT_CERT_NONE;
++- s->cert_info.data = NULL;
++- s->cert_info.len = 0;
++- return 0;
++- }
++-
++- if ((error = git_vector_init(&strings, 8, NULL)) < 0)
++- return error;
++-
++- for (slist = certinfo->certinfo[0]; slist; slist = slist->next) {
++- char *str = git__strdup(slist->data);
++- GITERR_CHECK_ALLOC(str);
++- git_vector_insert(&strings, str);
++- }
++-
++- /* Copy the contents of the vector into a strarray so we can expose them */
++- s->cert_info_strings.strings = (char **) strings.contents;
++- s->cert_info_strings.count = strings.length;
++-
++- s->cert_info.parent.cert_type = GIT_CERT_STRARRAY;
++- s->cert_info.data = &s->cert_info_strings;
++- s->cert_info.len = strings.length;
++-
++- *out = &s->cert_info.parent;
++-
++- return 0;
++-}
++-
++-static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
++-{
++- int error;
++- CURLcode res;
++- curl_stream *s = (curl_stream *) stream;
++-
++- if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0)
++- return error;
++-
++- if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, s->proxy.url)) != CURLE_OK)
++- return seterr_curl(s);
++-
++- if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY)) != CURLE_OK)
++- return seterr_curl(s);
++-
++- return 0;
++-}
++-
++-static int wait_for(curl_socket_t fd, bool reading)
++-{
++- int ret;
++- fd_set infd, outfd, errfd;
++-
++- FD_ZERO(&infd);
++- FD_ZERO(&outfd);
++- FD_ZERO(&errfd);
++-
++- assert(fd >= 0);
++- FD_SET(fd, &errfd);
++- if (reading)
++- FD_SET(fd, &infd);
++- else
++- FD_SET(fd, &outfd);
++-
++- if ((ret = select(fd + 1, &infd, &outfd, &errfd, NULL)) < 0) {
++- giterr_set(GITERR_OS, "error in select");
++- return -1;
++- }
++-
++- return 0;
++-}
++-
++-static ssize_t curls_write(git_stream *stream, const char *data, size_t len, int flags)
++-{
++- int error;
++- size_t off = 0, sent;
++- CURLcode res;
++- curl_stream *s = (curl_stream *) stream;
++-
++- GIT_UNUSED(flags);
++-
++- do {
++- if ((error = wait_for(s->socket, false)) < 0)
++- return error;
++-
++- res = curl_easy_send(s->handle, data + off, len - off, &sent);
++- if (res == CURLE_OK)
++- off += sent;
++- } while ((res == CURLE_OK || res == CURLE_AGAIN) && off < len);
++-
++- if (res != CURLE_OK)
++- return seterr_curl(s);
++-
++- return len;
++-}
++-
++-static ssize_t curls_read(git_stream *stream, void *data, size_t len)
++-{
++- int error;
++- size_t read;
++- CURLcode res;
++- curl_stream *s = (curl_stream *) stream;
++-
++- do {
++- if ((error = wait_for(s->socket, true)) < 0)
++- return error;
++-
++- res = curl_easy_recv(s->handle, data, len, &read);
++- } while (res == CURLE_AGAIN);
++-
++- if (res != CURLE_OK)
++- return seterr_curl(s);
++-
++- return read;
++-}
++-
++-static int curls_close(git_stream *stream)
++-{
++- curl_stream *s = (curl_stream *) stream;
++-
++- if (!s->handle)
++- return 0;
++-
++- curl_easy_cleanup(s->handle);
++- s->handle = NULL;
++- s->socket = 0;
++-
++- return 0;
++-}
++-
++-static void curls_free(git_stream *stream)
++-{
++- curl_stream *s = (curl_stream *) stream;
++-
++- curls_close(stream);
++- git_strarray_free(&s->cert_info_strings);
++- git__free(s);
++-}
++-
++-int git_curl_stream_new(git_stream **out, const char *host, const char *port)
++-{
++- curl_stream *st;
++- CURL *handle;
++- int iport = 0, error;
++-
++- st = git__calloc(1, sizeof(curl_stream));
++- GITERR_CHECK_ALLOC(st);
++-
++- handle = curl_easy_init();
++- if (handle == NULL) {
++- giterr_set(GITERR_NET, "failed to create curl handle");
++- git__free(st);
++- return -1;
++- }
++-
++- if ((error = git__strtol32(&iport, port, NULL, 10)) < 0) {
++- git__free(st);
++- return error;
++- }
++-
++- curl_easy_setopt(handle, CURLOPT_URL, host);
++- curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, st->curl_error);
++- curl_easy_setopt(handle, CURLOPT_PORT, iport);
++- curl_easy_setopt(handle, CURLOPT_CONNECT_ONLY, 1);
++- curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1);
++- curl_easy_setopt(handle, CURLOPT_CERTINFO, 1);
++- curl_easy_setopt(handle, CURLOPT_HTTPPROXYTUNNEL, 1);
++- curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
++-
++- /* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); */
++-
++- st->parent.version = GIT_STREAM_VERSION;
++- st->parent.encrypted = 0; /* we don't encrypt ourselves */
++- st->parent.proxy_support = 1;
++- st->parent.connect = curls_connect;
++- st->parent.certificate = curls_certificate;
++- st->parent.set_proxy = curls_set_proxy;
++- st->parent.read = curls_read;
++- st->parent.write = curls_write;
++- st->parent.close = curls_close;
++- st->parent.free = curls_free;
++- st->handle = handle;
++-
++- *out = (git_stream *) st;
++- return 0;
++-}
++-
++-#else
++-
++-#include "stream.h"
++-
++-int git_curl_stream_new(git_stream **out, const char *host, const char *port)
++-{
++- GIT_UNUSED(out);
++- GIT_UNUSED(host);
++- GIT_UNUSED(port);
++-
++- giterr_set(GITERR_NET, "curl is not supported in this version");
++- return -1;
++-}
++-
++-
++-#endif
++diff --git a/src/curl_stream.h b/src/curl_stream.h
++deleted file mode 100644
++index 283f0fe..0000000
++--- a/src/curl_stream.h
+++++ /dev/null
++@@ -1,14 +0,0 @@
++-/*
++- * 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_curl_stream_h__
++-#define INCLUDE_curl_stream_h__
++-
++-#include "git2/sys/stream.h"
++-
++-extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
++-
++-#endif
+ diff --git a/src/global.c b/src/global.c
+-index e2ad8fe..c5b4269 100644
++index afa57e1..66f1d44 100644
+ --- a/src/global.c
+ +++ b/src/global.c
+-@@ -10,7 +10,11 @@
++@@ -10,7 +10,8 @@
+ #include "sysdir.h"
+ #include "filter.h"
+ #include "merge_driver.h"
+-+#ifdef GIT_OPENSSL
+- #include "openssl_stream.h"
+-+#elif GIT_MBEDTLS
+-+#include "mbedtls_stream.h"
+-+#endif
++-#include "openssl_stream.h"
+++#include "streams/mbedtls.h"
+++#include "streams/openssl.h"
+ #include "thread-utils.h"
+ #include "git2/global.h"
+ #include "transports/ssh.h"
+-@@ -61,8 +65,13 @@ static int init_common(void)
+- (ret = git_sysdir_global_init()) == 0 &&
++@@ -62,7 +63,8 @@ static int init_common(void)
+ (ret = git_filter_global_init()) == 0 &&
+ (ret = git_merge_driver_global_init()) == 0 &&
+-- (ret = git_transport_ssh_global_init()) == 0 &&
++ (ret = git_transport_ssh_global_init()) == 0 &&
+ - (ret = git_openssl_stream_global_init()) == 0)
+-+ (ret = git_transport_ssh_global_init()) == 0
+-+#ifdef GIT_OPENSSL
+-+ && (ret = git_openssl_stream_global_init()) == 0
+-+#elif GIT_MBEDTLS
+-+ && (ret = git_mbedtls_stream_global_init()) == 0
+-+#endif
+-+ )
+++ (ret = git_openssl_stream_global_init()) == 0 &&
+++ (ret = git_mbedtls_stream_global_init()) == 0)
+ ret = git_mwindow_global_init();
+
+ GIT_MEMORY_BARRIER;
+ diff --git a/src/global.h b/src/global.h
+-index 2199515..adadcd9 100644
++index 88f40aa..e4bbabf 100644
+ --- a/src/global.h
+ +++ b/src/global.h
+-@@ -23,6 +23,12 @@ typedef struct {
+- extern SSL_CTX *git__ssl_ctx;
+- #endif
++@@ -24,11 +24,6 @@ typedef struct {
++ git_thread *current_thread;
++ } git_global_st;
+
+-+#ifdef GIT_MBEDTLS
+-+# include "mbedtls/platform.h"
+-+# include "mbedtls/ssl.h"
+-+extern mbedtls_ssl_config *git__ssl_conf;
+-+#endif
+-+
++-#ifdef GIT_OPENSSL
++-# include <openssl/ssl.h>
++-extern SSL_CTX *git__ssl_ctx;
++-#endif
++-
+ git_global_st *git__global_state(void);
+
+ extern git_mutex git__mwindow_mutex;
+ diff --git a/src/hash.h b/src/hash.h
+-index 0bc02a8..958d23b 100644
++index 0db0339..cba4462 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)
++@@ -24,6 +24,8 @@ void git_hash_ctx_cleanup(git_hash_ctx *ctx);
+ # include "hash/hash_openssl.h"
++ #elif defined(GIT_SHA1_WIN32)
++ # include "hash/hash_win32.h"
+ +#elif defined(MBEDTLS_SHA1)
+ +# include "hash/hash_mbedtls.h"
+- #elif defined(WIN32_SHA1)
+- # include "hash/hash_win32.h"
+ #else
++ # include "hash/hash_generic.h"
++ #endif
+ diff --git a/src/hash/hash_mbedtls.c b/src/hash/hash_mbedtls.c
+ new file mode 100644
+ index 0000000..a19d763
+@@ -233,7 +875,7 @@ index 0000000..a19d763
+ +}
+ diff --git a/src/hash/hash_mbedtls.h b/src/hash/hash_mbedtls.h
+ new file mode 100644
+-index 0000000..e50d295
++index 0000000..24196c5
+ --- /dev/null
+ +++ b/src/hash/hash_mbedtls.h
+ @@ -0,0 +1,20 @@
+@@ -257,13 +899,1803 @@ index 0000000..e50d295
+ +#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
++diff --git a/src/openssl_stream.c b/src/openssl_stream.c
++deleted file mode 100644
++index 759c501..0000000
++--- a/src/openssl_stream.c
+++++ /dev/null
++@@ -1,656 +0,0 @@
++-/*
++- * 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_OPENSSL
++-
++-#include <ctype.h>
++-
++-#include "global.h"
++-#include "posix.h"
++-#include "stream.h"
++-#include "socket_stream.h"
++-#include "openssl_stream.h"
++-#include "netops.h"
++-#include "git2/transport.h"
++-#include "git2/sys/openssl.h"
++-
++-#ifdef GIT_CURL
++-# include "curl_stream.h"
++-#endif
++-
++-#ifndef GIT_WIN32
++-# include <sys/types.h>
++-# include <sys/socket.h>
++-# include <netinet/in.h>
++-#endif
++-
++-#include <openssl/ssl.h>
++-#include <openssl/err.h>
++-#include <openssl/x509v3.h>
++-#include <openssl/bio.h>
++-
++-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(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
++-
++-static git_mutex *openssl_locks;
++-
++-static void openssl_locking_function(
++- int mode, int n, const char *file, int line)
++-{
++- int lock;
++-
++- GIT_UNUSED(file);
++- GIT_UNUSED(line);
++-
++- lock = mode & CRYPTO_LOCK;
++-
++- if (lock) {
++- git_mutex_lock(&openssl_locks[n]);
++- } else {
++- git_mutex_unlock(&openssl_locks[n]);
++- }
++-}
++-
++-static void shutdown_ssl_locking(void)
++-{
++- int num_locks, i;
++-
++- num_locks = CRYPTO_num_locks();
++- CRYPTO_set_locking_callback(NULL);
++-
++- for (i = 0; i < num_locks; ++i)
++- git_mutex_free(&openssl_locks[i]);
++- git__free(openssl_locks);
++-}
++-
++-#endif /* GIT_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L */
++-
++-static BIO_METHOD *git_stream_bio_method;
++-static int init_bio_method(void);
++-
++-/**
++- * This function aims to clean-up the SSL context which
++- * we allocated.
++- */
++-static void shutdown_ssl(void)
++-{
++- if (git_stream_bio_method) {
++- BIO_meth_free(git_stream_bio_method);
++- git_stream_bio_method = NULL;
++- }
++-
++- if (git__ssl_ctx) {
++- SSL_CTX_free(git__ssl_ctx);
++- git__ssl_ctx = NULL;
++- }
++-}
++-
++-int git_openssl_stream_global_init(void)
++-{
++-#ifdef GIT_OPENSSL
++- long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
++- const char *ciphers = git_libgit2__ssl_ciphers();
++-
++- /* Older OpenSSL and MacOS OpenSSL doesn't have this */
++-#ifdef SSL_OP_NO_COMPRESSION
++- ssl_opts |= SSL_OP_NO_COMPRESSION;
++-#endif
++-
++-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++- SSL_load_error_strings();
++- OpenSSL_add_ssl_algorithms();
++-#else
++- OPENSSL_init_ssl(0, NULL);
++-#endif
++-
++- /*
++- * Load SSLv{2,3} and TLSv1 so that we can talk with servers
++- * which use the SSL hellos, which are often used for
++- * compatibility. We then disable SSL so we only allow OpenSSL
++- * to speak TLSv1 to perform the encryption itself.
++- */
++- git__ssl_ctx = SSL_CTX_new(SSLv23_method());
++- SSL_CTX_set_options(git__ssl_ctx, ssl_opts);
++- SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY);
++- SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL);
++- if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) {
++- SSL_CTX_free(git__ssl_ctx);
++- git__ssl_ctx = NULL;
++- return -1;
++- }
++-
++- if (!ciphers) {
++- ciphers = GIT_SSL_DEFAULT_CIPHERS;
++- }
++-
++- if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers)) {
++- SSL_CTX_free(git__ssl_ctx);
++- git__ssl_ctx = NULL;
++- return -1;
++- }
++-
++- if (init_bio_method() < 0) {
++- SSL_CTX_free(git__ssl_ctx);
++- git__ssl_ctx = NULL;
++- return -1;
++- }
++-
++-#endif
++-
++- git__on_shutdown(shutdown_ssl);
++-
++- return 0;
++-}
++-
++-int git_openssl_set_locking(void)
++-{
++-#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
++- int num_locks, i;
++-
++- num_locks = CRYPTO_num_locks();
++- openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
++- GITERR_CHECK_ALLOC(openssl_locks);
++-
++- for (i = 0; i < num_locks; i++) {
++- if (git_mutex_init(&openssl_locks[i]) != 0) {
++- giterr_set(GITERR_SSL, "failed to initialize openssl locks");
++- return -1;
++- }
++- }
++-
++- CRYPTO_set_locking_callback(openssl_locking_function);
++- git__on_shutdown(shutdown_ssl_locking);
++- return 0;
++-#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
++- return 0;
++-#else
++- giterr_set(GITERR_THREAD, "libgit2 was not built with threads");
++- return -1;
++-#endif
++-}
++-
++-
++-static int bio_create(BIO *b)
++-{
++- BIO_set_init(b, 1);
++- BIO_set_data(b, NULL);
++-
++- return 1;
++-}
++-
++-static int bio_destroy(BIO *b)
++-{
++- if (!b)
++- return 0;
++-
++- BIO_set_data(b, NULL);
++-
++- return 1;
++-}
++-
++-static int bio_read(BIO *b, char *buf, int len)
++-{
++- git_stream *io = (git_stream *) BIO_get_data(b);
++-
++- return (int) git_stream_read(io, buf, len);
++-}
++-
++-static int bio_write(BIO *b, const char *buf, int len)
++-{
++- git_stream *io = (git_stream *) BIO_get_data(b);
++-
++- return (int) git_stream_write(io, buf, len, 0);
++-}
++-
++-static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
++-{
++- GIT_UNUSED(b);
++- GIT_UNUSED(num);
++- GIT_UNUSED(ptr);
++-
++- if (cmd == BIO_CTRL_FLUSH)
++- return 1;
++-
++- return 0;
++-}
++-
++-static int bio_gets(BIO *b, char *buf, int len)
++-{
++- GIT_UNUSED(b);
++- GIT_UNUSED(buf);
++- GIT_UNUSED(len);
++- return -1;
++-}
++-
++-static int bio_puts(BIO *b, const char *str)
++-{
++- return bio_write(b, str, strlen(str));
++-}
++-
++-static int init_bio_method(void)
++-{
++- /* Set up the BIO_METHOD we use for wrapping our own stream implementations */
++- git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream");
++- GITERR_CHECK_ALLOC(git_stream_bio_method);
++-
++- BIO_meth_set_write(git_stream_bio_method, bio_write);
++- BIO_meth_set_read(git_stream_bio_method, bio_read);
++- BIO_meth_set_puts(git_stream_bio_method, bio_puts);
++- BIO_meth_set_gets(git_stream_bio_method, bio_gets);
++- BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl);
++- BIO_meth_set_create(git_stream_bio_method, bio_create);
++- BIO_meth_set_destroy(git_stream_bio_method, bio_destroy);
++-
++- return 0;
++-}
++-
++-static int ssl_set_error(SSL *ssl, int error)
++-{
++- int err;
++- unsigned long e;
++-
++- err = SSL_get_error(ssl, error);
++-
++- assert(err != SSL_ERROR_WANT_READ);
++- assert(err != SSL_ERROR_WANT_WRITE);
++-
++- switch (err) {
++- case SSL_ERROR_WANT_CONNECT:
++- case SSL_ERROR_WANT_ACCEPT:
++- giterr_set(GITERR_NET, "SSL error: connection failure");
++- break;
++- case SSL_ERROR_WANT_X509_LOOKUP:
++- giterr_set(GITERR_NET, "SSL error: x509 error");
++- break;
++- case SSL_ERROR_SYSCALL:
++- e = ERR_get_error();
++- if (e > 0) {
++- giterr_set(GITERR_NET, "SSL error: %s",
++- ERR_error_string(e, NULL));
++- break;
++- } else if (error < 0) {
++- giterr_set(GITERR_OS, "SSL error: syscall failure");
++- break;
++- }
++- giterr_set(GITERR_NET, "SSL error: received early EOF");
++- return GIT_EEOF;
++- break;
++- case SSL_ERROR_SSL:
++- e = ERR_get_error();
++- giterr_set(GITERR_NET, "SSL error: %s",
++- ERR_error_string(e, NULL));
++- break;
++- case SSL_ERROR_NONE:
++- case SSL_ERROR_ZERO_RETURN:
++- default:
++- giterr_set(GITERR_NET, "SSL error: unknown error");
++- break;
++- }
++- return -1;
++-}
++-
++-static int ssl_teardown(SSL *ssl)
++-{
++- int ret;
++-
++- ret = SSL_shutdown(ssl);
++- if (ret < 0)
++- ret = ssl_set_error(ssl, ret);
++- else
++- ret = 0;
++-
++- 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(SSL *ssl, const char *host)
++-{
++- X509 *cert;
++- X509_NAME *peer_name;
++- ASN1_STRING *str;
++- unsigned char *peer_cn = NULL;
++- int matched = -1, type = GEN_DNS;
++- GENERAL_NAMES *alts;
++- struct in6_addr addr6;
++- struct in_addr addr4;
++- void *addr;
++- int i = -1,j;
++-
++- if (SSL_get_verify_result(ssl) != X509_V_OK) {
++- giterr_set(GITERR_SSL, "the SSL certificate is invalid");
++- return GIT_ECERTIFICATE;
++- }
++-
++- /* Try to parse the host as an IP address to see if it is */
++- if (p_inet_pton(AF_INET, host, &addr4)) {
++- type = GEN_IPADD;
++- addr = &addr4;
++- } else {
++- if(p_inet_pton(AF_INET6, host, &addr6)) {
++- type = GEN_IPADD;
++- addr = &addr6;
++- }
++- }
++-
++-
++- cert = SSL_get_peer_certificate(ssl);
++- if (!cert) {
++- giterr_set(GITERR_SSL, "the server did not provide a certificate");
++- return -1;
++- }
++-
++- /* Check the alternative names */
++- alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
++- if (alts) {
++- int num;
++-
++- num = sk_GENERAL_NAME_num(alts);
++- for (i = 0; i < num && matched != 1; i++) {
++- const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i);
++- const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5);
++- size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5);
++-
++- /* Skip any names of a type we're not looking for */
++- if (gn->type != type)
++- continue;
++-
++- if (type == GEN_DNS) {
++- /* If it contains embedded NULs, don't even try */
++- if (memchr(name, '\0', namelen))
++- continue;
++-
++- if (check_host_name(name, host) < 0)
++- matched = 0;
++- else
++- matched = 1;
++- } else if (type == GEN_IPADD) {
++- /* Here name isn't so much a name but a binary representation of the IP */
++- matched = !!memcmp(name, addr, namelen);
++- }
++- }
++- }
++- GENERAL_NAMES_free(alts);
++-
++- if (matched == 0)
++- goto cert_fail_name;
++-
++- if (matched == 1)
++- return 0;
++-
++- /* If no alternative names are available, check the common name */
++- peer_name = X509_get_subject_name(cert);
++- if (peer_name == NULL)
++- goto on_error;
++-
++- if (peer_name) {
++- /* Get the index of the last CN entry */
++- while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0)
++- i = j;
++- }
++-
++- if (i < 0)
++- goto on_error;
++-
++- str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i));
++- if (str == NULL)
++- goto on_error;
++-
++- /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
++- if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) {
++- int size = ASN1_STRING_length(str);
++-
++- if (size > 0) {
++- peer_cn = OPENSSL_malloc(size + 1);
++- GITERR_CHECK_ALLOC(peer_cn);
++- memcpy(peer_cn, ASN1_STRING_get0_data(str), size);
++- peer_cn[size] = '\0';
++- } else {
++- goto cert_fail_name;
++- }
++- } else {
++- int size = ASN1_STRING_to_UTF8(&peer_cn, str);
++- GITERR_CHECK_ALLOC(peer_cn);
++- if (memchr(peer_cn, '\0', size))
++- goto cert_fail_name;
++- }
++-
++- if (check_host_name((char *)peer_cn, host) < 0)
++- goto cert_fail_name;
++-
++- OPENSSL_free(peer_cn);
++-
++- return 0;
++-
++-on_error:
++- OPENSSL_free(peer_cn);
++- return ssl_set_error(ssl, 0);
++-
++-cert_fail_name:
++- OPENSSL_free(peer_cn);
++- giterr_set(GITERR_SSL, "hostname does not match certificate");
++- return GIT_ECERTIFICATE;
++-}
++-
++-typedef struct {
++- git_stream parent;
++- git_stream *io;
++- bool connected;
++- char *host;
++- SSL *ssl;
++- git_cert_x509 cert_info;
++-} openssl_stream;
++-
++-int openssl_close(git_stream *stream);
++-
++-int openssl_connect(git_stream *stream)
++-{
++- int ret;
++- BIO *bio;
++- openssl_stream *st = (openssl_stream *) stream;
++-
++- if ((ret = git_stream_connect(st->io)) < 0)
++- return ret;
++-
++- st->connected = true;
++-
++- bio = BIO_new(git_stream_bio_method);
++- GITERR_CHECK_ALLOC(bio);
++-
++- BIO_set_data(bio, st->io);
++- SSL_set_bio(st->ssl, bio, bio);
++-
++- /* specify the host in case SNI is needed */
++-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
++- SSL_set_tlsext_host_name(st->ssl, st->host);
++-#endif
++-
++- if ((ret = SSL_connect(st->ssl)) <= 0)
++- return ssl_set_error(st->ssl, ret);
++-
++- return verify_server_cert(st->ssl, st->host);
++-}
++-
++-int openssl_certificate(git_cert **out, git_stream *stream)
++-{
++- openssl_stream *st = (openssl_stream *) stream;
++- int len;
++- X509 *cert = SSL_get_peer_certificate(st->ssl);
++- unsigned char *guard, *encoded_cert;
++-
++- /* Retrieve the length of the certificate first */
++- len = i2d_X509(cert, NULL);
++- if (len < 0) {
++- giterr_set(GITERR_NET, "failed to retrieve certificate information");
++- return -1;
++- }
++-
++- encoded_cert = git__malloc(len);
++- GITERR_CHECK_ALLOC(encoded_cert);
++- /* i2d_X509 makes 'guard' point to just after the data */
++- guard = encoded_cert;
++-
++- len = i2d_X509(cert, &guard);
++- if (len < 0) {
++- git__free(encoded_cert);
++- giterr_set(GITERR_NET, "failed to retrieve certificate information");
++- return -1;
++- }
++-
++- st->cert_info.parent.cert_type = GIT_CERT_X509;
++- st->cert_info.data = encoded_cert;
++- st->cert_info.len = len;
++-
++- *out = &st->cert_info.parent;
++-
++- return 0;
++-}
++-
++-static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
++-{
++- openssl_stream *st = (openssl_stream *) stream;
++-
++- return git_stream_set_proxy(st->io, proxy_opts);
++-}
++-
++-ssize_t openssl_write(git_stream *stream, const char *data, size_t len, int flags)
++-{
++- openssl_stream *st = (openssl_stream *) stream;
++- int ret;
++-
++- GIT_UNUSED(flags);
++-
++- if ((ret = SSL_write(st->ssl, data, len)) <= 0) {
++- return ssl_set_error(st->ssl, ret);
++- }
++-
++- return ret;
++-}
++-
++-ssize_t openssl_read(git_stream *stream, void *data, size_t len)
++-{
++- openssl_stream *st = (openssl_stream *) stream;
++- int ret;
++-
++- if ((ret = SSL_read(st->ssl, data, len)) <= 0)
++- return ssl_set_error(st->ssl, ret);
++-
++- return ret;
++-}
++-
++-int openssl_close(git_stream *stream)
++-{
++- openssl_stream *st = (openssl_stream *) stream;
++- int ret;
++-
++- if (st->connected && (ret = ssl_teardown(st->ssl)) < 0)
++- return -1;
++-
++- st->connected = false;
++-
++- return git_stream_close(st->io);
++-}
++-
++-void openssl_free(git_stream *stream)
++-{
++- openssl_stream *st = (openssl_stream *) stream;
++-
++- SSL_free(st->ssl);
++- git__free(st->host);
++- git__free(st->cert_info.data);
++- git_stream_free(st->io);
++- git__free(st);
++-}
++-
++-int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
++-{
++- int error;
++- openssl_stream *st;
++-
++- st = git__calloc(1, sizeof(openssl_stream));
++- GITERR_CHECK_ALLOC(st);
++-
++- st->io = NULL;
++-#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)
++- goto out_err;
++-
++- st->ssl = SSL_new(git__ssl_ctx);
++- if (st->ssl == NULL) {
++- giterr_set(GITERR_SSL, "failed to create ssl object");
++- error = -1;
++- goto out_err;
++- }
++-
++- 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 = openssl_connect;
++- st->parent.certificate = openssl_certificate;
++- st->parent.set_proxy = openssl_set_proxy;
++- st->parent.read = openssl_read;
++- st->parent.write = openssl_write;
++- st->parent.close = openssl_close;
++- st->parent.free = openssl_free;
++-
++- *out = (git_stream *) st;
++- return 0;
++-
++-out_err:
++- git_stream_free(st->io);
++- git__free(st);
++-
++- return error;
++-}
++-
++-#else
++-
++-#include "stream.h"
++-#include "git2/sys/openssl.h"
++-
++-int git_openssl_stream_global_init(void)
++-{
++- return 0;
++-}
++-
++-int git_openssl_set_locking(void)
++-{
++- giterr_set(GITERR_SSL, "libgit2 was not built with OpenSSL support");
++- return -1;
++-}
++-
++-int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
++-{
++- GIT_UNUSED(out);
++- GIT_UNUSED(host);
++- GIT_UNUSED(port);
++-
++- giterr_set(GITERR_SSL, "openssl is not supported in this version");
++- return -1;
++-}
++-
++-#endif
++diff --git a/src/openssl_stream.h b/src/openssl_stream.h
++deleted file mode 100644
++index f5e59da..0000000
++--- a/src/openssl_stream.h
+++++ /dev/null
++@@ -1,122 +0,0 @@
++-/*
++- * 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_openssl_stream_h__
++-#define INCLUDE_openssl_stream_h__
++-
++-#include "git2/sys/stream.h"
++-
++-extern int git_openssl_stream_global_init(void);
++-
++-extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
++-
++-/*
++- * 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.
++- */
++-#ifdef GIT_OPENSSL
++-# include <openssl/ssl.h>
++-# include <openssl/err.h>
++-# include <openssl/x509v3.h>
++-# include <openssl/bio.h>
++-
++-
++-
++-# if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++-
++-GIT_INLINE(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;
++-}
++-
++-GIT_INLINE(void) BIO_meth_free(BIO_METHOD *biom)
++-{
++- git__free(biom);
++-}
++-
++-GIT_INLINE(int) BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
++-{
++- biom->bwrite = write;
++- return 1;
++-}
++-
++-GIT_INLINE(int) BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
++-{
++- biom->bread = read;
++- return 1;
++-}
++-
++-GIT_INLINE(int) BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
++-{
++- biom->bputs = puts;
++- return 1;
++-}
++-
++-GIT_INLINE(int) BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
++-
++-{
++- biom->bgets = gets;
++- return 1;
++-}
++-
++-GIT_INLINE(int) BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
++-{
++- biom->ctrl = ctrl;
++- return 1;
++-}
++-
++-GIT_INLINE(int) BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *))
++-{
++- biom->create = create;
++- return 1;
++-}
++-
++-GIT_INLINE(int) BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *))
++-{
++- biom->destroy = destroy;
++- return 1;
++-}
++-
++-GIT_INLINE(int) BIO_get_new_index(void)
++-{
++- /* This exists as of 1.1 so before we'd just have 0 */
++- return 0;
++-}
++-
++-GIT_INLINE(void) BIO_set_init(BIO *b, int init)
++-{
++- b->init = init;
++-}
++-
++-GIT_INLINE(void) BIO_set_data(BIO *a, void *ptr)
++-{
++- a->ptr = ptr;
++-}
++-
++-GIT_INLINE(void*) BIO_get_data(BIO *a)
++-{
++- return a->ptr;
++-}
++-
++-GIT_INLINE(const unsigned char *) ASN1_STRING_get0_data(const ASN1_STRING *x)
++-{
++- return ASN1_STRING_data((ASN1_STRING *)x);
++-}
++-
++-# endif // OpenSSL < 1.1
++-#endif // GIT_OPENSSL
++-
++-#endif
++diff --git a/src/settings.c b/src/settings.c
++index 52b861b..3a46f0d 100644
++--- a/src/settings.c
+++++ b/src/settings.c
++@@ -9,6 +9,10 @@
++ # include <openssl/err.h>
++ #endif
++
+++#ifdef GIT_MBEDTLS
+++# include <mbedtls/error.h>
+++#endif
+++
++ #include <git2.h>
++ #include "common.h"
++ #include "sysdir.h"
++@@ -18,6 +22,8 @@
++ #include "odb.h"
++ #include "refs.h"
++ #include "transports/smart.h"
+++#include "streams/openssl.h"
+++#include "streams/mbedtls.h"
++
++ void git_libgit2_version(int *major, int *minor, int *rev)
++ {
++@@ -171,14 +177,19 @@ int git_libgit2_opts(int key, ...)
++ {
++ const char *file = va_arg(ap, const char *);
++ const char *path = va_arg(ap, const char *);
++- if (!SSL_CTX_load_verify_locations(git__ssl_ctx, file, path)) {
++- giterr_set(GITERR_NET, "SSL error: %s",
++- ERR_error_string(ERR_get_error(), NULL));
++- error = -1;
++- }
+++ error = git_openssl_set_cert_file(file, path);
+++ }
+++#elif GIT_MBEDTLS
+++ {
+++ const char *file = va_arg(ap, const char *);
+++ const char *path = va_arg(ap, const char *);
+++ if (file)
+++ error = git_mbedtls_set_cert_file(file, 0);
+++ if (error && path)
+++ error = git_mbedtls_set_cert_file(path, 0);
++ }
++ #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/socket_stream.c b/src/socket_stream.c
++deleted file mode 100644
++index c0a1684..0000000
++--- a/src/socket_stream.c
+++++ /dev/null
++@@ -1,210 +0,0 @@
++-/*
++- * 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 "posix.h"
++-#include "netops.h"
++-#include "stream.h"
++-#include "socket_stream.h"
++-
++-#ifndef _WIN32
++-# include <sys/types.h>
++-# include <sys/socket.h>
++-# include <sys/select.h>
++-# include <sys/time.h>
++-# include <netdb.h>
++-# include <netinet/in.h>
++-# include <arpa/inet.h>
++-#else
++-# include <winsock2.h>
++-# include <ws2tcpip.h>
++-# ifdef _MSC_VER
++-# pragma comment(lib, "ws2_32")
++-# endif
++-#endif
++-
++-#ifdef GIT_WIN32
++-static void net_set_error(const char *str)
++-{
++- int error = WSAGetLastError();
++- char * win32_error = git_win32_get_error_message(error);
++-
++- if (win32_error) {
++- giterr_set(GITERR_NET, "%s: %s", str, win32_error);
++- git__free(win32_error);
++- } else {
++- giterr_set(GITERR_NET, str);
++- }
++-}
++-#else
++-static void net_set_error(const char *str)
++-{
++- giterr_set(GITERR_NET, "%s: %s", str, strerror(errno));
++-}
++-#endif
++-
++-static int close_socket(GIT_SOCKET s)
++-{
++- if (s == INVALID_SOCKET)
++- return 0;
++-
++-#ifdef GIT_WIN32
++- if (SOCKET_ERROR == closesocket(s))
++- return -1;
++-
++- if (0 != WSACleanup()) {
++- giterr_set(GITERR_OS, "winsock cleanup failed");
++- return -1;
++- }
++-
++- return 0;
++-#else
++- return close(s);
++-#endif
++-
++-}
++-
++-int socket_connect(git_stream *stream)
++-{
++- struct addrinfo *info = NULL, *p;
++- struct addrinfo hints;
++- git_socket_stream *st = (git_socket_stream *) stream;
++- GIT_SOCKET s = INVALID_SOCKET;
++- int ret;
++-
++-#ifdef GIT_WIN32
++- /* on win32, the WSA context needs to be initialized
++- * before any socket calls can be performed */
++- WSADATA wsd;
++-
++- if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
++- giterr_set(GITERR_OS, "winsock init failed");
++- return -1;
++- }
++-
++- if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) {
++- WSACleanup();
++- giterr_set(GITERR_OS, "winsock init failed");
++- return -1;
++- }
++-#endif
++-
++- memset(&hints, 0x0, sizeof(struct addrinfo));
++- hints.ai_socktype = SOCK_STREAM;
++- hints.ai_family = AF_UNSPEC;
++-
++- if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) {
++- giterr_set(GITERR_NET,
++- "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret));
++- return -1;
++- }
++-
++- for (p = info; p != NULL; p = p->ai_next) {
++- s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
++-
++- if (s == INVALID_SOCKET)
++- continue;
++-
++- if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
++- break;
++-
++- /* If we can't connect, try the next one */
++- close_socket(s);
++- s = INVALID_SOCKET;
++- }
++-
++- /* Oops, we couldn't connect to any address */
++- if (s == INVALID_SOCKET && p == NULL) {
++- giterr_set(GITERR_OS, "failed to connect to %s", st->host);
++- p_freeaddrinfo(info);
++- return -1;
++- }
++-
++- st->s = s;
++- p_freeaddrinfo(info);
++- return 0;
++-}
++-
++-ssize_t socket_write(git_stream *stream, const char *data, size_t len, int flags)
++-{
++- ssize_t ret;
++- size_t off = 0;
++- git_socket_stream *st = (git_socket_stream *) stream;
++-
++- while (off < len) {
++- errno = 0;
++- ret = p_send(st->s, data + off, len - off, flags);
++- if (ret < 0) {
++- net_set_error("Error sending data");
++- return -1;
++- }
++-
++- off += ret;
++- }
++-
++- return off;
++-}
++-
++-ssize_t socket_read(git_stream *stream, void *data, size_t len)
++-{
++- ssize_t ret;
++- git_socket_stream *st = (git_socket_stream *) stream;
++-
++- if ((ret = p_recv(st->s, data, len, 0)) < 0)
++- net_set_error("Error receiving socket data");
++-
++- return ret;
++-}
++-
++-int socket_close(git_stream *stream)
++-{
++- git_socket_stream *st = (git_socket_stream *) stream;
++- int error;
++-
++- error = close_socket(st->s);
++- st->s = INVALID_SOCKET;
++-
++- return error;
++-}
++-
++-void socket_free(git_stream *stream)
++-{
++- git_socket_stream *st = (git_socket_stream *) stream;
++-
++- git__free(st->host);
++- git__free(st->port);
++- git__free(st);
++-}
++-
++-int git_socket_stream_new(git_stream **out, const char *host, const char *port)
++-{
++- git_socket_stream *st;
++-
++- assert(out && host);
++-
++- st = git__calloc(1, sizeof(git_socket_stream));
++- GITERR_CHECK_ALLOC(st);
++-
++- st->host = git__strdup(host);
++- GITERR_CHECK_ALLOC(st->host);
++-
++- if (port) {
++- st->port = git__strdup(port);
++- GITERR_CHECK_ALLOC(st->port);
++- }
++-
++- st->parent.version = GIT_STREAM_VERSION;
++- st->parent.connect = socket_connect;
++- st->parent.write = socket_write;
++- st->parent.read = socket_read;
++- st->parent.close = socket_close;
++- st->parent.free = socket_free;
++- st->s = INVALID_SOCKET;
++-
++- *out = (git_stream *) st;
++- return 0;
++-}
++diff --git a/src/socket_stream.h b/src/socket_stream.h
++deleted file mode 100644
++index 8e9949f..0000000
++--- a/src/socket_stream.h
+++++ /dev/null
++@@ -1,21 +0,0 @@
++-/*
++- * 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_socket_stream_h__
++-#define INCLUDE_socket_stream_h__
++-
++-#include "netops.h"
++-
++-typedef struct {
++- git_stream parent;
++- char *host;
++- char *port;
++- GIT_SOCKET s;
++-} git_socket_stream;
++-
++-extern int git_socket_stream_new(git_stream **out, const char *host, const char *port);
++-
++-#endif
++diff --git a/src/stransport_stream.c b/src/stransport_stream.c
++deleted file mode 100644
++index 50ed945..0000000
++--- a/src/stransport_stream.c
+++++ /dev/null
++@@ -1,294 +0,0 @@
++-/*
++- * 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_SECURE_TRANSPORT
++-
++-#include <CoreFoundation/CoreFoundation.h>
++-#include <Security/SecureTransport.h>
++-#include <Security/SecCertificate.h>
++-
++-#include "git2/transport.h"
++-
++-#include "socket_stream.h"
++-#include "curl_stream.h"
++-
++-static int stransport_error(OSStatus ret)
++-{
++- CFStringRef message;
++-
++- if (ret == noErr || ret == errSSLClosedGraceful) {
++- giterr_clear();
++- return 0;
++- }
++-
++-#if !TARGET_OS_IPHONE
++- message = SecCopyErrorMessageString(ret, NULL);
++- GITERR_CHECK_ALLOC(message);
++-
++- giterr_set(GITERR_NET, "SecureTransport error: %s", CFStringGetCStringPtr(message, kCFStringEncodingUTF8));
++- CFRelease(message);
++-#else
++- giterr_set(GITERR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret);
++- GIT_UNUSED(message);
++-#endif
++-
++- return -1;
++-}
++-
++-typedef struct {
++- git_stream parent;
++- git_stream *io;
++- SSLContextRef ctx;
++- CFDataRef der_data;
++- git_cert_x509 cert_info;
++-} stransport_stream;
++-
++-static int stransport_connect(git_stream *stream)
++-{
++- stransport_stream *st = (stransport_stream *) stream;
++- int error;
++- SecTrustRef trust = NULL;
++- SecTrustResultType sec_res;
++- OSStatus ret;
++-
++- if ((error = git_stream_connect(st->io)) < 0)
++- return error;
++-
++- ret = SSLHandshake(st->ctx);
++- if (ret != errSSLServerAuthCompleted) {
++- giterr_set(GITERR_SSL, "unexpected return value from ssl handshake %d", ret);
++- return -1;
++- }
++-
++- if ((ret = SSLCopyPeerTrust(st->ctx, &trust)) != noErr)
++- goto on_error;
++-
++- if (!trust)
++- return GIT_ECERTIFICATE;
++-
++- if ((ret = SecTrustEvaluate(trust, &sec_res)) != noErr)
++- goto on_error;
++-
++- CFRelease(trust);
++-
++- if (sec_res == kSecTrustResultInvalid || sec_res == kSecTrustResultOtherError) {
++- giterr_set(GITERR_SSL, "internal security trust error");
++- return -1;
++- }
++-
++- if (sec_res == kSecTrustResultDeny || sec_res == kSecTrustResultRecoverableTrustFailure ||
++- sec_res == kSecTrustResultFatalTrustFailure)
++- return GIT_ECERTIFICATE;
++-
++- return 0;
++-
++-on_error:
++- if (trust)
++- CFRelease(trust);
++-
++- return stransport_error(ret);
++-}
++-
++-static int stransport_certificate(git_cert **out, git_stream *stream)
++-{
++- stransport_stream *st = (stransport_stream *) stream;
++- SecTrustRef trust = NULL;
++- SecCertificateRef sec_cert;
++- OSStatus ret;
++-
++- if ((ret = SSLCopyPeerTrust(st->ctx, &trust)) != noErr)
++- return stransport_error(ret);
++-
++- sec_cert = SecTrustGetCertificateAtIndex(trust, 0);
++- st->der_data = SecCertificateCopyData(sec_cert);
++- CFRelease(trust);
++-
++- if (st->der_data == NULL) {
++- giterr_set(GITERR_SSL, "retrieved invalid certificate data");
++- return -1;
++- }
++-
++- st->cert_info.parent.cert_type = GIT_CERT_X509;
++- st->cert_info.data = (void *) CFDataGetBytePtr(st->der_data);
++- st->cert_info.len = CFDataGetLength(st->der_data);
++-
++- *out = (git_cert *)&st->cert_info;
++- return 0;
++-}
++-
++-static int stransport_set_proxy(
++- git_stream *stream,
++- const git_proxy_options *proxy_opts)
++-{
++- stransport_stream *st = (stransport_stream *) stream;
++-
++- return git_stream_set_proxy(st->io, proxy_opts);
++-}
++-
++-/*
++- * Contrary to typical network IO callbacks, Secure Transport write callback is
++- * expected to write *all* passed data, not just as much as it can, and any
++- * other case would be considered a failure.
++- *
++- * This behavior is actually not specified in the Apple documentation, but is
++- * required for things to work correctly (and incidentally, that's also how
++- * Apple implements it in its projects at opensource.apple.com).
++- *
++- * Libgit2 streams happen to already have this very behavior so this is just
++- * passthrough.
++- */
++-static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len)
++-{
++- git_stream *io = (git_stream *) conn;
++-
++- if (git_stream_write(io, data, *len, 0) < 0) {
++- return -36; /* "ioErr" from MacErrors.h which is not available on iOS */
++- }
++-
++- return noErr;
++-}
++-
++-static ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int flags)
++-{
++- stransport_stream *st = (stransport_stream *) stream;
++- size_t data_len, processed;
++- OSStatus ret;
++-
++- GIT_UNUSED(flags);
++-
++- data_len = len;
++- if ((ret = SSLWrite(st->ctx, data, data_len, &processed)) != noErr)
++- return stransport_error(ret);
++-
++- return processed;
++-}
++-
++-/*
++- * Contrary to typical network IO callbacks, Secure Transport read callback is
++- * expected to read *exactly* the requested number of bytes, not just as much
++- * as it can, and any other case would be considered a failure.
++- *
++- * This behavior is actually not specified in the Apple documentation, but is
++- * required for things to work correctly (and incidentally, that's also how
++- * Apple implements it in its projects at opensource.apple.com).
++- */
++-static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len)
++-{
++- git_stream *io = (git_stream *) conn;
++- OSStatus error = noErr;
++- size_t off = 0;
++- ssize_t ret;
++-
++- do {
++- ret = git_stream_read(io, data + off, *len - off);
++- if (ret < 0) {
++- error = -36; /* "ioErr" from MacErrors.h which is not available on iOS */
++- break;
++- }
++- if (ret == 0) {
++- error = errSSLClosedGraceful;
++- break;
++- }
++-
++- off += ret;
++- } while (off < *len);
++-
++- *len = off;
++- return error;
++-}
++-
++-static ssize_t stransport_read(git_stream *stream, void *data, size_t len)
++-{
++- stransport_stream *st = (stransport_stream *) stream;
++- size_t processed;
++- OSStatus ret;
++-
++- if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr)
++- return stransport_error(ret);
++-
++- return processed;
++-}
++-
++-static int stransport_close(git_stream *stream)
++-{
++- stransport_stream *st = (stransport_stream *) stream;
++- OSStatus ret;
++-
++- ret = SSLClose(st->ctx);
++- if (ret != noErr && ret != errSSLClosedGraceful)
++- return stransport_error(ret);
++-
++- return git_stream_close(st->io);
++-}
++-
++-static void stransport_free(git_stream *stream)
++-{
++- stransport_stream *st = (stransport_stream *) stream;
++-
++- git_stream_free(st->io);
++- CFRelease(st->ctx);
++- if (st->der_data)
++- CFRelease(st->der_data);
++- git__free(st);
++-}
++-
++-int git_stransport_stream_new(git_stream **out, const char *host, const char *port)
++-{
++- stransport_stream *st;
++- int error;
++- OSStatus ret;
++-
++- assert(out && host);
++-
++- st = git__calloc(1, sizeof(stransport_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){
++- git__free(st);
++- return error;
++- }
++-
++- st->ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
++- if (!st->ctx) {
++- giterr_set(GITERR_NET, "failed to create SSL context");
++- git__free(st);
++- return -1;
++- }
++-
++- if ((ret = SSLSetIOFuncs(st->ctx, read_cb, write_cb)) != noErr ||
++- (ret = SSLSetConnection(st->ctx, st->io)) != noErr ||
++- (ret = SSLSetSessionOption(st->ctx, kSSLSessionOptionBreakOnServerAuth, true)) != noErr ||
++- (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr ||
++- (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr ||
++- (ret = SSLSetPeerDomainName(st->ctx, host, strlen(host))) != noErr) {
++- CFRelease(st->ctx);
++- git__free(st);
++- return stransport_error(ret);
++- }
++-
++- st->parent.version = GIT_STREAM_VERSION;
++- st->parent.encrypted = 1;
++- st->parent.proxy_support = git_stream_supports_proxy(st->io);
++- st->parent.connect = stransport_connect;
++- st->parent.certificate = stransport_certificate;
++- st->parent.set_proxy = stransport_set_proxy;
++- st->parent.read = stransport_read;
++- st->parent.write = stransport_write;
++- st->parent.close = stransport_close;
++- st->parent.free = stransport_free;
++-
++- *out = (git_stream *) st;
++- return 0;
++-}
++-
++-#endif
++diff --git a/src/stransport_stream.h b/src/stransport_stream.h
++deleted file mode 100644
++index 714f902..0000000
++--- a/src/stransport_stream.h
+++++ /dev/null
++@@ -1,14 +0,0 @@
++-/*
++- * 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_stransport_stream_h__
++-#define INCLUDE_stransport_stream_h__
++-
++-#include "git2/sys/stream.h"
++-
++-extern int git_stransport_stream_new(git_stream **out, const char *host, const char *port);
++-
++-#endif
++diff --git a/src/streams/curl.c b/src/streams/curl.c
++new file mode 100644
++index 0000000..4e0455c
++--- /dev/null
+++++ b/src/streams/curl.c
++@@ -0,0 +1,362 @@
+++/*
+++ * 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_CURL
+++
+++#include <curl/curl.h>
+++
+++#include "stream.h"
+++#include "git2/transport.h"
+++#include "buffer.h"
+++#include "vector.h"
+++#include "proxy.h"
+++
+++/* This is for backwards compatibility with curl<7.45.0. */
+++#ifndef CURLINFO_ACTIVESOCKET
+++# define CURLINFO_ACTIVESOCKET CURLINFO_LASTSOCKET
+++# define GIT_CURL_BADSOCKET -1
+++# define git_activesocket_t long
+++#else
+++# define GIT_CURL_BADSOCKET CURL_SOCKET_BAD
+++# define git_activesocket_t curl_socket_t
+++#endif
+++
+++typedef struct {
+++ git_stream parent;
+++ CURL *handle;
+++ curl_socket_t socket;
+++ char curl_error[CURL_ERROR_SIZE + 1];
+++ git_cert_x509 cert_info;
+++ git_strarray cert_info_strings;
+++ git_proxy_options proxy;
+++ git_cred *proxy_cred;
+++} curl_stream;
+++
+++static int seterr_curl(curl_stream *s)
+++{
+++ giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
+++ return -1;
+++}
+++
+++GIT_INLINE(int) error_no_credentials(void)
+++{
+++ giterr_set(GITERR_NET, "proxy authentication required, but no callback provided");
+++ return GIT_EAUTH;
+++}
+++
+++static int apply_proxy_creds(curl_stream *s)
+++{
+++ CURLcode res;
+++ git_cred_userpass_plaintext *userpass;
+++
+++ if (!s->proxy_cred)
+++ return GIT_ENOTFOUND;
+++
+++ userpass = (git_cred_userpass_plaintext *) s->proxy_cred;
+++ if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYUSERNAME, userpass->username)) != CURLE_OK)
+++ return seterr_curl(s);
+++ if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYPASSWORD, userpass->password)) != CURLE_OK)
+++ return seterr_curl(s);
+++
+++ return 0;
+++}
+++
+++static int ask_and_apply_proxy_creds(curl_stream *s)
+++{
+++ int error;
+++ git_proxy_options *opts = &s->proxy;
+++
+++ if (!opts->credentials)
+++ return error_no_credentials();
+++
+++ /* TODO: see if PROXYAUTH_AVAIL helps us here */
+++ git_cred_free(s->proxy_cred);
+++ s->proxy_cred = NULL;
+++ giterr_clear();
+++ error = opts->credentials(&s->proxy_cred, opts->url, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, opts->payload);
+++ if (error == GIT_PASSTHROUGH)
+++ return error_no_credentials();
+++ if (error < 0) {
+++ if (!giterr_last())
+++ giterr_set(GITERR_NET, "proxy authentication was aborted by the user");
+++ return error;
+++ }
+++
+++ if (s->proxy_cred->credtype != GIT_CREDTYPE_USERPASS_PLAINTEXT) {
+++ giterr_set(GITERR_NET, "credentials callback returned invalid credential type");
+++ return -1;
+++ }
+++
+++ return apply_proxy_creds(s);
+++}
+++
+++static int curls_connect(git_stream *stream)
+++{
+++ curl_stream *s = (curl_stream *) stream;
+++ git_activesocket_t sockextr;
+++ long connect_last = 0;
+++ int failed_cert = 0, error;
+++ bool retry_connect;
+++ CURLcode res;
+++
+++ /* Apply any credentials we've already established */
+++ error = apply_proxy_creds(s);
+++ if (error < 0 && error != GIT_ENOTFOUND)
+++ return seterr_curl(s);
+++
+++ do {
+++ retry_connect = 0;
+++ res = curl_easy_perform(s->handle);
+++
+++ curl_easy_getinfo(s->handle, CURLINFO_HTTP_CONNECTCODE, &connect_last);
+++
+++ /* HTTP 407 Proxy Authentication Required */
+++ if (connect_last == 407) {
+++ if ((error = ask_and_apply_proxy_creds(s)) < 0)
+++ return error;
+++
+++ retry_connect = true;
+++ }
+++ } while (retry_connect);
+++
+++ if (res != CURLE_OK && res != CURLE_PEER_FAILED_VERIFICATION)
+++ return seterr_curl(s);
+++ if (res == CURLE_PEER_FAILED_VERIFICATION)
+++ failed_cert = 1;
+++
+++ if ((res = curl_easy_getinfo(s->handle, CURLINFO_ACTIVESOCKET, &sockextr)) != CURLE_OK) {
+++ return seterr_curl(s);
+++ }
+++
+++ if (sockextr == GIT_CURL_BADSOCKET) {
+++ giterr_set(GITERR_NET, "curl socket is no longer valid");
+++ return -1;
+++ }
+++
+++ s->socket = sockextr;
+++
+++ if (s->parent.encrypted && failed_cert)
+++ return GIT_ECERTIFICATE;
+++
+++ return 0;
+++}
+++
+++static int curls_certificate(git_cert **out, git_stream *stream)
+++{
+++ int error;
+++ CURLcode res;
+++ struct curl_slist *slist;
+++ struct curl_certinfo *certinfo;
+++ git_vector strings = GIT_VECTOR_INIT;
+++ curl_stream *s = (curl_stream *) stream;
+++
+++ if ((res = curl_easy_getinfo(s->handle, CURLINFO_CERTINFO, &certinfo)) != CURLE_OK)
+++ return seterr_curl(s);
+++
+++ /* No information is available, can happen with SecureTransport */
+++ if (certinfo->num_of_certs == 0) {
+++ s->cert_info.parent.cert_type = GIT_CERT_NONE;
+++ s->cert_info.data = NULL;
+++ s->cert_info.len = 0;
+++ return 0;
+++ }
+++
+++ if ((error = git_vector_init(&strings, 8, NULL)) < 0)
+++ return error;
+++
+++ for (slist = certinfo->certinfo[0]; slist; slist = slist->next) {
+++ char *str = git__strdup(slist->data);
+++ GITERR_CHECK_ALLOC(str);
+++ git_vector_insert(&strings, str);
+++ }
+++
+++ /* Copy the contents of the vector into a strarray so we can expose them */
+++ s->cert_info_strings.strings = (char **) strings.contents;
+++ s->cert_info_strings.count = strings.length;
+++
+++ s->cert_info.parent.cert_type = GIT_CERT_STRARRAY;
+++ s->cert_info.data = &s->cert_info_strings;
+++ s->cert_info.len = strings.length;
+++
+++ *out = &s->cert_info.parent;
+++
+++ return 0;
+++}
+++
+++static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
+++{
+++ int error;
+++ CURLcode res;
+++ curl_stream *s = (curl_stream *) stream;
+++
+++ if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0)
+++ return error;
+++
+++ if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, s->proxy.url)) != CURLE_OK)
+++ return seterr_curl(s);
+++
+++ if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY)) != CURLE_OK)
+++ return seterr_curl(s);
+++
+++ return 0;
+++}
+++
+++static int wait_for(curl_socket_t fd, bool reading)
+++{
+++ int ret;
+++ fd_set infd, outfd, errfd;
+++
+++ FD_ZERO(&infd);
+++ FD_ZERO(&outfd);
+++ FD_ZERO(&errfd);
+++
+++ assert(fd >= 0);
+++ FD_SET(fd, &errfd);
+++ if (reading)
+++ FD_SET(fd, &infd);
+++ else
+++ FD_SET(fd, &outfd);
+++
+++ if ((ret = select(fd + 1, &infd, &outfd, &errfd, NULL)) < 0) {
+++ giterr_set(GITERR_OS, "error in select");
+++ return -1;
+++ }
+++
+++ return 0;
+++}
+++
+++static ssize_t curls_write(git_stream *stream, const char *data, size_t len, int flags)
+++{
+++ int error;
+++ size_t off = 0, sent;
+++ CURLcode res;
+++ curl_stream *s = (curl_stream *) stream;
+++
+++ GIT_UNUSED(flags);
+++
+++ do {
+++ if ((error = wait_for(s->socket, false)) < 0)
+++ return error;
+++
+++ res = curl_easy_send(s->handle, data + off, len - off, &sent);
+++ if (res == CURLE_OK)
+++ off += sent;
+++ } while ((res == CURLE_OK || res == CURLE_AGAIN) && off < len);
+++
+++ if (res != CURLE_OK)
+++ return seterr_curl(s);
+++
+++ return len;
+++}
+++
+++static ssize_t curls_read(git_stream *stream, void *data, size_t len)
+++{
+++ int error;
+++ size_t read;
+++ CURLcode res;
+++ curl_stream *s = (curl_stream *) stream;
+++
+++ do {
+++ if ((error = wait_for(s->socket, true)) < 0)
+++ return error;
+++
+++ res = curl_easy_recv(s->handle, data, len, &read);
+++ } while (res == CURLE_AGAIN);
+++
+++ if (res != CURLE_OK)
+++ return seterr_curl(s);
+++
+++ return read;
+++}
+++
+++static int curls_close(git_stream *stream)
+++{
+++ curl_stream *s = (curl_stream *) stream;
+++
+++ if (!s->handle)
+++ return 0;
+++
+++ curl_easy_cleanup(s->handle);
+++ s->handle = NULL;
+++ s->socket = 0;
+++
+++ return 0;
+++}
+++
+++static void curls_free(git_stream *stream)
+++{
+++ curl_stream *s = (curl_stream *) stream;
+++
+++ curls_close(stream);
+++ git_strarray_free(&s->cert_info_strings);
+++ git__free(s);
+++}
+++
+++int git_curl_stream_new(git_stream **out, const char *host, const char *port)
+++{
+++ curl_stream *st;
+++ CURL *handle;
+++ int iport = 0, error;
+++
+++ st = git__calloc(1, sizeof(curl_stream));
+++ GITERR_CHECK_ALLOC(st);
+++
+++ handle = curl_easy_init();
+++ if (handle == NULL) {
+++ giterr_set(GITERR_NET, "failed to create curl handle");
+++ git__free(st);
+++ return -1;
+++ }
+++
+++ if ((error = git__strtol32(&iport, port, NULL, 10)) < 0) {
+++ git__free(st);
+++ return error;
+++ }
+++
+++ curl_easy_setopt(handle, CURLOPT_URL, host);
+++ curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, st->curl_error);
+++ curl_easy_setopt(handle, CURLOPT_PORT, iport);
+++ curl_easy_setopt(handle, CURLOPT_CONNECT_ONLY, 1);
+++ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1);
+++ curl_easy_setopt(handle, CURLOPT_CERTINFO, 1);
+++ curl_easy_setopt(handle, CURLOPT_HTTPPROXYTUNNEL, 1);
+++ curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+++
+++ /* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); */
+++
+++ st->parent.version = GIT_STREAM_VERSION;
+++ st->parent.encrypted = 0; /* we don't encrypt ourselves */
+++ st->parent.proxy_support = 1;
+++ st->parent.connect = curls_connect;
+++ st->parent.certificate = curls_certificate;
+++ st->parent.set_proxy = curls_set_proxy;
+++ st->parent.read = curls_read;
+++ st->parent.write = curls_write;
+++ st->parent.close = curls_close;
+++ st->parent.free = curls_free;
+++ st->handle = handle;
+++
+++ *out = (git_stream *) st;
+++ return 0;
+++}
+++
+++#else
+++
+++#include "stream.h"
+++
+++int git_curl_stream_new(git_stream **out, const char *host, const char *port)
+++{
+++ GIT_UNUSED(out);
+++ GIT_UNUSED(host);
+++ GIT_UNUSED(port);
+++
+++ giterr_set(GITERR_NET, "curl is not supported in this version");
+++ return -1;
+++}
+++
+++
+++#endif
++diff --git a/src/streams/curl.h b/src/streams/curl.h
++new file mode 100644
++index 0000000..283f0fe
++--- /dev/null
+++++ b/src/streams/curl.h
++@@ -0,0 +1,14 @@
+++/*
+++ * 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_curl_stream_h__
+++#define INCLUDE_curl_stream_h__
+++
+++#include "git2/sys/stream.h"
+++
+++extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
+++
+++#endif
++diff --git a/src/streams/mbedtls.c b/src/streams/mbedtls.c
+ new file mode 100644
+-index 0000000..98ff808
++index 0000000..0376ee4
+ --- /dev/null
+-+++ b/src/mbedtls_stream.c
+-@@ -0,0 +1,483 @@
+++++ b/src/streams/mbedtls.c
++@@ -0,0 +1,538 @@
+ +/*
+ + * Copyright (C) the libgit2 contributors. All rights reserved.
+ + *
+@@ -277,26 +2709,26 @@ index 0000000..98ff808
+ +
+ +#include "global.h"
+ +#include "stream.h"
+-+#include "socket_stream.h"
+++#include "streams/socket.h"
+++#include "netops.h"
+ +#include "git2/transport.h"
+++#include "util.h"
+ +
+ +#ifdef GIT_CURL
+-+# include "curl_stream.h"
+++# include "streams/curl.h"
+ +#endif
+ +
+-+#include "mbedtls/config.h"
+-+#include <mbedtls/x509.h>
+-+#include <mbedtls/x509_crt.h>
+++#include <mbedtls/config.h>
+++#include <mbedtls/ssl.h>
+ +#include <mbedtls/error.h>
+-+#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"
+++#include <mbedtls/entropy.h>
+++#include <mbedtls/ctr_drbg.h>
+ +
+ +#ifndef OPENSSLDIR
+-+# define OPENSSLDIR "/usr/lib/ssl"
+++//# define OPENSSLDIR
+++# define OPENSSLDIR "/etc/ssl" // Debian
+++//# define OPENSSLDIR "/usr/lib/ssl" //Ubuntu
+++//# define OPENSSLDIR "/usr/local/etc/openssl" // mostly-Darwin
+ +#endif
+ +#define X509_CERT_DIR OPENSSLDIR "/certs"
+ +#define X509_CERT_FILE OPENSSLDIR "/cert.pem"
+@@ -306,7 +2738,8 @@ index 0000000..98ff808
+ +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"
+++#define GIT_SSL_DEFAULT_CIPHERS "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-DSS-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-DSS-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-DSS-WITH-AES-128-CBC-SHA256:TLS-DHE-DSS-WITH-AES-256-CBC-SHA256:TLS-DHE-DSS-WITH-AES-128-CBC-SHA:TLS-DHE-DSS-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-AES-128-GCM-SHA256:TLS-RSA-WITH-AES-256-GCM-SHA384:TLS-RSA-WITH-AES-128-C
BC-SHA256:TLS-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA"
+++#define GIT_SSL_DEFAULT_CIPHERS_COUNT 30
+ +
+ +/**
+ + * This function aims to clean-up the SSL context which
+@@ -314,565 +2747,1985 @@ index 0000000..98ff808
+ + */
+ +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;
+-+ }
+++ 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_set_cert_file(const char *path, int is_dir);
+++
+ +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);
+++ int found = -1, loaded = 0;
+++ char *crtpath;
+++ struct stat statbuf;
+++ mbedtls_ctr_drbg_context *ctr_drbg = NULL;
+ +
+-+ return 0;
+++ int *ciphers_list = NULL;
+++ int ciphers_known = 0;
+++ char *cipher_name = NULL;
+++ char *cipher_string = NULL;
+++ char *cipher_string_tmp = NULL;
+++
+++ mbedtls_x509_crt *cacert = NULL;
+++
+++ 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) {
+++ giterr_set(GITERR_SSL, "failed to initialize mbedTLS");
+++ goto cleanup;
+++ }
+++
+++ // configure TLSv1
+++ mbedtls_ssl_conf_min_version(git__ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0);
+++ // verify_server_cert is responsible for making the check.
+++ // OPTIONAL because REQUIRED drops the certificate as soon as the check
+++ // is made, so we can never see the certificate and override it.
+++ mbedtls_ssl_conf_authmode(git__ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+++
+++ // set the list of allowed ciphersuites
+++ ciphers_list = calloc(GIT_SSL_DEFAULT_CIPHERS_COUNT, sizeof(int));
+++ ciphers_known = 0;
+++ cipher_string = cipher_string_tmp = git__strdup(GIT_SSL_DEFAULT_CIPHERS);
+++ while ((cipher_name = git__strtok(&cipher_string_tmp, ":")) != NULL) {
+++ int cipherid = mbedtls_ssl_get_ciphersuite_id(cipher_name);
+++ if (cipherid == 0) continue;
+++
+++ ciphers_list[ciphers_known++] = cipherid;
+++ }
+++ git__free(cipher_string);
+++
+++ if (!ciphers_known) {
+++ giterr_set(GITERR_SSL, "no cipher could be enabled");
+++ goto cleanup;
+++ }
+++ mbedtls_ssl_conf_ciphersuites(git__ssl_conf, ciphers_list);
+++
+++ // Seeding the random number generator
+++ mbedtls_entropy = git__malloc(sizeof(mbedtls_entropy_context));
+++ mbedtls_entropy_init(mbedtls_entropy);
+++
+++ 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) {
+++ giterr_set(GITERR_SSL, "failed to initialize mbedTLS entropy pool");
+++ goto cleanup;
+++ }
+++
+++ mbedtls_ssl_conf_rng(git__ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg);
+++
+++ // find locations for which CA certificates
+++ {
+++ crtpath = getenv(X509_CERT_FILE_EVP);
+++ found = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode);
+++ if (found)
+++ loaded = (git_mbedtls_set_cert_file(crtpath, 0) == 0);
+++ }
+++ if (!loaded) {
+++ crtpath = getenv(X509_CERT_DIR_EVP);
+++ found = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode);
+++ if (found)
+++ loaded = (git_mbedtls_set_cert_file(crtpath, 1) == 0);
+++ }
+++ if (!loaded) {
+++ crtpath = X509_CERT_FILE;
+++ found = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode);
+++ if (found)
+++ loaded = (git_mbedtls_set_cert_file(crtpath, 0) == 0);
+++ }
+++ if (!loaded) {
+++ crtpath = X509_CERT_DIR;
+++ found = crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode);
+++ if (found)
+++ loaded = (git_mbedtls_set_cert_file(crtpath, 1) == 0);
+++ }
+++
+++ git__on_shutdown(shutdown_ssl);
+++
+++ return 0;
+++
+++cleanup:
+++ 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;
+ +}
+ +
+++mbedtls_ssl_config *git__ssl_conf;
+++
+ +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);
+++ 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);
+++ 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;
+++ 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 );
+ +
+-+ assert(error != MBEDTLS_ERR_SSL_WANT_READ);
+-+ assert(error != MBEDTLS_ERR_SSL_WANT_WRITE);
+++ switch(error){
+++ case 0:
+++ giterr_set(GITERR_SSL, "SSL error: unknown error");
+++ break;
+ +
+-+ if (error != 0)
+-+ mbedtls_strerror( error, errbuf, 512 );
+++ 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;
+ +
+-+ 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);
+-+ }
+++ default:
+++ giterr_set(GITERR_SSL, "SSL error: %x - %s", error, errbuf);
+++ }
+ +
+-+ return ret;
+++ return ret;
+ +}
+ +
+ +static int ssl_teardown(mbedtls_ssl_context *ssl)
+ +{
+-+ int ret = 0;
+++ int ret = 0;
+ +
+-+ ret = mbedtls_ssl_close_notify(ssl);
+-+ if (ret < 0)
+-+ ret = ssl_set_error(ssl, ret);
+++ ret = mbedtls_ssl_close_notify(ssl);
+++ if (ret < 0)
+++ ret = ssl_set_error(ssl, ret);
+ +
+-+ mbedtls_ssl_free(ssl);
+-+ return 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 (!strcasecmp(name, host))
+++ return 0;
+ +
+-+ if (gitno__match_host(name, host) < 0)
+-+ return -1;
+++ if (gitno__match_host(name, host) < 0)
+++ return -1;
+ +
+-+ return 0;
+++ 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;
+++ 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];
+ +
+-+ return 0;
+++
+++ 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);
+++ return ssl_set_error(ssl, 0);
+ +
+ +cert_fail_name:
+-+ giterr_set(GITERR_SSL, "hostname does not match certificate");
+-+ return GIT_ECERTIFICATE;
+++ 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;
+++ 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;
+++ int ret;
+++ mbedtls_stream *st = (mbedtls_stream *) stream;
+ +
+-+ if ((ret = git_stream_connect(st->io)) < 0)
+-+ return ret;
+++ if ((ret = git_stream_connect(st->io)) < 0)
+++ return ret;
+ +
+-+ st->connected = true;
+++ st->connected = true;
+ +
+-+ mbedtls_ssl_set_hostname(st->ssl, st->host);
+++ mbedtls_ssl_set_hostname(st->ssl, st->host);
+ +
+-+ mbedtls_ssl_set_bio(st->ssl, st->io, bio_write, bio_read, NULL);
+++ 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);
+++ if ((ret = mbedtls_ssl_handshake(st->ssl)) != 0)
+++ return ssl_set_error(st->ssl, ret);
+ +
+-+ return verify_server_cert(st->ssl, st->host);
+++ 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;
+++ 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;
+-+ }
+++ 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;
+-+ }
+++ /* 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);
+++ 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;
+++ 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;
+++ *out = &st->cert_info.parent;
+ +
+-+ return 0;
+++ return 0;
+ +}
+ +
+-+static int mbedtls_set_proxy(git_stream *stream, const char *proxy_url)
+++static int mbedtls_set_proxy(git_stream *stream, const git_proxy_options *proxy_options)
+ +{
+-+ mbedtls_stream *st = (mbedtls_stream *) stream;
+++ mbedtls_stream *st = (mbedtls_stream *) stream;
+ +
+-+ return git_stream_set_proxy(st->io, proxy_url);
+++ return git_stream_set_proxy(st->io, proxy_options);
+ +}
+ +
+ +ssize_t mbedtls_stream_write(git_stream *stream, const char *data, size_t len, int flags)
+ +{
+-+ mbedtls_stream *st = (mbedtls_stream *) stream;
+-+ int ret;
+++ size_t read = 0;
+++ mbedtls_stream *st = (mbedtls_stream *) stream;
+ +
+-+ GIT_UNUSED(flags);
+++ GIT_UNUSED(flags);
+ +
+-+ if ((ret = mbedtls_ssl_write(st->ssl, (const unsigned char *)data, len)) <= 0) {
+-+ return ssl_set_error(st->ssl, ret);
+-+ }
+++ do {
+++ int error = mbedtls_ssl_write(st->ssl, (const unsigned char *)data + read, len - read);
+++ if (error <= 0) {
+++ return ssl_set_error(st->ssl, error);
+++ }
+++ read += error;
+++ } while (read < len);
+ +
+-+ return ret;
+++ return read;
+ +}
+ +
+ +ssize_t mbedtls_stream_read(git_stream *stream, void *data, size_t len)
+ +{
+-+ mbedtls_stream *st = (mbedtls_stream *) stream;
+-+ int ret;
+++ 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);
+++ if ((ret = mbedtls_ssl_read(st->ssl, (unsigned char *)data, len)) <= 0)
+++ ssl_set_error(st->ssl, ret);
+ +
+-+ return ret;
+++ return ret;
+ +}
+ +
+ +int mbedtls_stream_close(git_stream *stream)
+ +{
+-+ mbedtls_stream *st = (mbedtls_stream *) stream;
+-+ int ret = 0;
+++ mbedtls_stream *st = (mbedtls_stream *) stream;
+++ int ret = 0;
+ +
+-+ if (st->connected && (ret = ssl_teardown(st->ssl)) != 0)
+-+ return -1;
+++ if (st->connected && (ret = ssl_teardown(st->ssl)) != 0)
+++ return -1;
+ +
+-+ st->connected = false;
+++ st->connected = false;
+ +
+-+ return git_stream_close(st->io);
+++ return git_stream_close(st->io);
+ +}
+ +
+ +void mbedtls_stream_free(git_stream *stream)
+ +{
+-+ mbedtls_stream *st = (mbedtls_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);
+++ 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;
+++ int error;
+++ mbedtls_stream *st;
+ +
+-+ st = git__calloc(1, sizeof(mbedtls_stream));
+-+ GITERR_CHECK_ALLOC(st);
+++ st = git__calloc(1, sizeof(mbedtls_stream));
+++ GITERR_CHECK_ALLOC(st);
+ +
+ +#ifdef GIT_CURL
+-+ error = git_curl_stream_new(&st->io, host, port);
+++ error = git_curl_stream_new(&st->io, host, port);
+ +#else
+-+ error = git_socket_stream_new(&st->io, host, port);
+++ 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;
+-+}
+++ if (error < 0)
+++ goto out_err;
+ +
+-+#else
+++ st->ssl = git__malloc(sizeof(mbedtls_ssl_context));
+++ GITERR_CHECK_ALLOC(st->ssl);
+++ mbedtls_ssl_init(st->ssl);
+++ if (mbedtls_ssl_setup(st->ssl, git__ssl_conf)) {
+++ giterr_set(GITERR_SSL, "failed to create ssl object");
+++ error = -1;
+++ goto out_err;
+++ }
+ +
+-+#include "stream.h"
+-+#include "git2/sys/openssl.h"
+++ 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;
+++
+++out_err:
+++ mbedtls_ssl_free(st->ssl);
+++ git_stream_free(st->io);
+++ git__free(st);
+++
+++ return error;
+++}
+++
+++int git_mbedtls_set_cert_file(const char *path, int is_dir)
+++{
+++ int ret = 0;
+++ char errbuf[512];
+++ mbedtls_x509_crt *cacert;
+++
+++ assert(path != NULL);
+++
+++ cacert = git__malloc(sizeof(mbedtls_x509_crt));
+++ mbedtls_x509_crt_init(cacert);
+++ if (is_dir) {
+++ ret = mbedtls_x509_crt_parse_path(cacert, path);
+++ } else {
+++ ret = mbedtls_x509_crt_parse_file(cacert, path);
+++ }
+++ // mbedtls_x509_crt_parse_path returns the number of invalid certs on success
+++ if (ret <= 0) {
+++ mbedtls_x509_crt_free(cacert);
+++ git__free(cacert);
+++ mbedtls_strerror( ret, errbuf, 512 );
+++ giterr_set(GITERR_SSL, "failed to load CA certificates : %s (%d)", errbuf, ret);
+++ return -1;
+++ }
+++
+++ 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);
+++
+++ return 0;
+++}
+++
+++#else
+++
+++#include "stream.h"
+ +
+ +int git_mbedtls_stream_global_init(void)
+ +{
+-+ return 0;
+++ 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;
+++}
+++
+++int git_mbedtls_set_cert_file(const char *path, int is_dir)
+++{
+++ GIT_UNUSED(is_dir);
+++
+++ giterr_set(GITERR_SSL, "mbedTLS is not supported in this version");
+++ return -1;
+++}
+++
+++#endif
++diff --git a/src/streams/mbedtls.h b/src/streams/mbedtls.h
++new file mode 100644
++index 0000000..7501397
++--- /dev/null
+++++ b/src/streams/mbedtls.h
++@@ -0,0 +1,18 @@
+++/*
+++ * 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);
+++
+++extern int git_mbedtls_set_cert_file(const char *path, int is_dir);
+++
+++#endif
++diff --git a/src/streams/openssl.c b/src/streams/openssl.c
++new file mode 100644
++index 0000000..8668b78
++--- /dev/null
+++++ b/src/streams/openssl.c
++@@ -0,0 +1,675 @@
+++/*
+++ * 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_OPENSSL
+++
+++#include <ctype.h>
+++
+++#include "global.h"
+++#include "posix.h"
+++#include "stream.h"
+++#include "streams/socket.h"
+++#include "streams/openssl.h"
+++#include "netops.h"
+++#include "git2/transport.h"
+++#include "git2/sys/openssl.h"
+++
+++#ifdef GIT_CURL
+++# include "streams/curl.h"
+++#endif
+++
+++#ifndef GIT_WIN32
+++# include <sys/types.h>
+++# include <sys/socket.h>
+++# include <netinet/in.h>
+++#endif
+++
+++#include <openssl/ssl.h>
+++#include <openssl/err.h>
+++#include <openssl/x509v3.h>
+++#include <openssl/bio.h>
+++
+++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(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
+++
+++static git_mutex *openssl_locks;
+++
+++static void openssl_locking_function(
+++ int mode, int n, const char *file, int line)
+++{
+++ int lock;
+++
+++ GIT_UNUSED(file);
+++ GIT_UNUSED(line);
+++
+++ lock = mode & CRYPTO_LOCK;
+++
+++ if (lock) {
+++ git_mutex_lock(&openssl_locks[n]);
+++ } else {
+++ git_mutex_unlock(&openssl_locks[n]);
+++ }
+++}
+++
+++static void shutdown_ssl_locking(void)
+++{
+++ int num_locks, i;
+++
+++ num_locks = CRYPTO_num_locks();
+++ CRYPTO_set_locking_callback(NULL);
+++
+++ for (i = 0; i < num_locks; ++i)
+++ git_mutex_free(&openssl_locks[i]);
+++ git__free(openssl_locks);
+++}
+++
+++#endif /* GIT_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L */
+++
+++static BIO_METHOD *git_stream_bio_method;
+++static int init_bio_method(void);
+++
+++/**
+++ * This function aims to clean-up the SSL context which
+++ * we allocated.
+++ */
+++static void shutdown_ssl(void)
+++{
+++ if (git_stream_bio_method) {
+++ BIO_meth_free(git_stream_bio_method);
+++ git_stream_bio_method = NULL;
+++ }
+++
+++ if (git__ssl_ctx) {
+++ SSL_CTX_free(git__ssl_ctx);
+++ git__ssl_ctx = NULL;
+++ }
+++}
+++
+++int git_openssl_stream_global_init(void)
+++{
+++#ifdef GIT_OPENSSL
+++ long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+++ const char *ciphers = git_libgit2__ssl_ciphers();
+++
+++ /* Older OpenSSL and MacOS OpenSSL doesn't have this */
+++#ifdef SSL_OP_NO_COMPRESSION
+++ ssl_opts |= SSL_OP_NO_COMPRESSION;
+++#endif
+++
+++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+++ SSL_load_error_strings();
+++ OpenSSL_add_ssl_algorithms();
+++#else
+++ OPENSSL_init_ssl(0, NULL);
+++#endif
+++
+++ /*
+++ * Load SSLv{2,3} and TLSv1 so that we can talk with servers
+++ * which use the SSL hellos, which are often used for
+++ * compatibility. We then disable SSL so we only allow OpenSSL
+++ * to speak TLSv1 to perform the encryption itself.
+++ */
+++ git__ssl_ctx = SSL_CTX_new(SSLv23_method());
+++ SSL_CTX_set_options(git__ssl_ctx, ssl_opts);
+++ SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY);
+++ SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL);
+++ if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) {
+++ SSL_CTX_free(git__ssl_ctx);
+++ git__ssl_ctx = NULL;
+++ return -1;
+++ }
+++
+++ if (!ciphers) {
+++ ciphers = GIT_SSL_DEFAULT_CIPHERS;
+++ }
+++
+++ if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers)) {
+++ SSL_CTX_free(git__ssl_ctx);
+++ git__ssl_ctx = NULL;
+++ return -1;
+++ }
+++
+++ if (init_bio_method() < 0) {
+++ SSL_CTX_free(git__ssl_ctx);
+++ git__ssl_ctx = NULL;
+++ return -1;
+++ }
+++
+++#endif
+++
+++ git__on_shutdown(shutdown_ssl);
+++
+++ return 0;
+++}
+++
+++int git_openssl_set_locking(void)
+++{
+++#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
+++ int num_locks, i;
+++
+++ num_locks = CRYPTO_num_locks();
+++ openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
+++ GITERR_CHECK_ALLOC(openssl_locks);
+++
+++ for (i = 0; i < num_locks; i++) {
+++ if (git_mutex_init(&openssl_locks[i]) != 0) {
+++ giterr_set(GITERR_SSL, "failed to initialize openssl locks");
+++ return -1;
+++ }
+++ }
+++
+++ CRYPTO_set_locking_callback(openssl_locking_function);
+++ git__on_shutdown(shutdown_ssl_locking);
+++ return 0;
+++#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
+++ return 0;
+++#else
+++ giterr_set(GITERR_THREAD, "libgit2 was not built with threads");
+++ return -1;
+++#endif
+++}
+++
+++
+++static int bio_create(BIO *b)
+++{
+++ BIO_set_init(b, 1);
+++ BIO_set_data(b, NULL);
+++
+++ return 1;
+++}
+++
+++static int bio_destroy(BIO *b)
+++{
+++ if (!b)
+++ return 0;
+++
+++ BIO_set_data(b, NULL);
+++
+++ return 1;
+++}
+++
+++static int bio_read(BIO *b, char *buf, int len)
+++{
+++ git_stream *io = (git_stream *) BIO_get_data(b);
+++
+++ return (int) git_stream_read(io, buf, len);
+++}
+++
+++static int bio_write(BIO *b, const char *buf, int len)
+++{
+++ git_stream *io = (git_stream *) BIO_get_data(b);
+++
+++ return (int) git_stream_write(io, buf, len, 0);
+++}
+++
+++static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
+++{
+++ GIT_UNUSED(b);
+++ GIT_UNUSED(num);
+++ GIT_UNUSED(ptr);
+++
+++ if (cmd == BIO_CTRL_FLUSH)
+++ return 1;
+++
+++ return 0;
+++}
+++
+++static int bio_gets(BIO *b, char *buf, int len)
+++{
+++ GIT_UNUSED(b);
+++ GIT_UNUSED(buf);
+++ GIT_UNUSED(len);
+++ return -1;
+++}
+++
+++static int bio_puts(BIO *b, const char *str)
+++{
+++ return bio_write(b, str, strlen(str));
+++}
+++
+++static int init_bio_method(void)
+++{
+++ /* Set up the BIO_METHOD we use for wrapping our own stream implementations */
+++ git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream");
+++ GITERR_CHECK_ALLOC(git_stream_bio_method);
+++
+++ BIO_meth_set_write(git_stream_bio_method, bio_write);
+++ BIO_meth_set_read(git_stream_bio_method, bio_read);
+++ BIO_meth_set_puts(git_stream_bio_method, bio_puts);
+++ BIO_meth_set_gets(git_stream_bio_method, bio_gets);
+++ BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl);
+++ BIO_meth_set_create(git_stream_bio_method, bio_create);
+++ BIO_meth_set_destroy(git_stream_bio_method, bio_destroy);
+++
+++ return 0;
+++}
+++
+++static int ssl_set_error(SSL *ssl, int error)
+++{
+++ int err;
+++ unsigned long e;
+++
+++ err = SSL_get_error(ssl, error);
+++
+++ assert(err != SSL_ERROR_WANT_READ);
+++ assert(err != SSL_ERROR_WANT_WRITE);
+++
+++ switch (err) {
+++ case SSL_ERROR_WANT_CONNECT:
+++ case SSL_ERROR_WANT_ACCEPT:
+++ giterr_set(GITERR_NET, "SSL error: connection failure");
+++ break;
+++ case SSL_ERROR_WANT_X509_LOOKUP:
+++ giterr_set(GITERR_NET, "SSL error: x509 error");
+++ break;
+++ case SSL_ERROR_SYSCALL:
+++ e = ERR_get_error();
+++ if (e > 0) {
+++ giterr_set(GITERR_NET, "SSL error: %s",
+++ ERR_error_string(e, NULL));
+++ break;
+++ } else if (error < 0) {
+++ giterr_set(GITERR_OS, "SSL error: syscall failure");
+++ break;
+++ }
+++ giterr_set(GITERR_NET, "SSL error: received early EOF");
+++ return GIT_EEOF;
+++ break;
+++ case SSL_ERROR_SSL:
+++ e = ERR_get_error();
+++ giterr_set(GITERR_NET, "SSL error: %s",
+++ ERR_error_string(e, NULL));
+++ break;
+++ case SSL_ERROR_NONE:
+++ case SSL_ERROR_ZERO_RETURN:
+++ default:
+++ giterr_set(GITERR_NET, "SSL error: unknown error");
+++ break;
+++ }
+++ return -1;
+++}
+++
+++static int ssl_teardown(SSL *ssl)
+++{
+++ int ret;
+++
+++ ret = SSL_shutdown(ssl);
+++ if (ret < 0)
+++ ret = ssl_set_error(ssl, ret);
+++ else
+++ ret = 0;
+++
+++ 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(SSL *ssl, const char *host)
+++{
+++ X509 *cert;
+++ X509_NAME *peer_name;
+++ ASN1_STRING *str;
+++ unsigned char *peer_cn = NULL;
+++ int matched = -1, type = GEN_DNS;
+++ GENERAL_NAMES *alts;
+++ struct in6_addr addr6;
+++ struct in_addr addr4;
+++ void *addr;
+++ int i = -1,j;
+++
+++ if (SSL_get_verify_result(ssl) != X509_V_OK) {
+++ giterr_set(GITERR_SSL, "the SSL certificate is invalid");
+++ return GIT_ECERTIFICATE;
+++ }
+++
+++ /* Try to parse the host as an IP address to see if it is */
+++ if (p_inet_pton(AF_INET, host, &addr4)) {
+++ type = GEN_IPADD;
+++ addr = &addr4;
+++ } else {
+++ if(p_inet_pton(AF_INET6, host, &addr6)) {
+++ type = GEN_IPADD;
+++ addr = &addr6;
+++ }
+++ }
+++
+++
+++ cert = SSL_get_peer_certificate(ssl);
+++ if (!cert) {
+++ giterr_set(GITERR_SSL, "the server did not provide a certificate");
+++ return -1;
+++ }
+++
+++ /* Check the alternative names */
+++ alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+++ if (alts) {
+++ int num;
+++
+++ num = sk_GENERAL_NAME_num(alts);
+++ for (i = 0; i < num && matched != 1; i++) {
+++ const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i);
+++ const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5);
+++ size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5);
+++
+++ /* Skip any names of a type we're not looking for */
+++ if (gn->type != type)
+++ continue;
+++
+++ if (type == GEN_DNS) {
+++ /* If it contains embedded NULs, don't even try */
+++ if (memchr(name, '\0', namelen))
+++ continue;
+++
+++ if (check_host_name(name, host) < 0)
+++ matched = 0;
+++ else
+++ matched = 1;
+++ } else if (type == GEN_IPADD) {
+++ /* Here name isn't so much a name but a binary representation of the IP */
+++ matched = !!memcmp(name, addr, namelen);
+++ }
+++ }
+++ }
+++ GENERAL_NAMES_free(alts);
+++
+++ if (matched == 0)
+++ goto cert_fail_name;
+++
+++ if (matched == 1)
+++ return 0;
+++
+++ /* If no alternative names are available, check the common name */
+++ peer_name = X509_get_subject_name(cert);
+++ if (peer_name == NULL)
+++ goto on_error;
+++
+++ if (peer_name) {
+++ /* Get the index of the last CN entry */
+++ while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0)
+++ i = j;
+++ }
+++
+++ if (i < 0)
+++ goto on_error;
+++
+++ str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i));
+++ if (str == NULL)
+++ goto on_error;
+++
+++ /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
+++ if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) {
+++ int size = ASN1_STRING_length(str);
+++
+++ if (size > 0) {
+++ peer_cn = OPENSSL_malloc(size + 1);
+++ GITERR_CHECK_ALLOC(peer_cn);
+++ memcpy(peer_cn, ASN1_STRING_get0_data(str), size);
+++ peer_cn[size] = '\0';
+++ } else {
+++ goto cert_fail_name;
+++ }
+++ } else {
+++ int size = ASN1_STRING_to_UTF8(&peer_cn, str);
+++ GITERR_CHECK_ALLOC(peer_cn);
+++ if (memchr(peer_cn, '\0', size))
+++ goto cert_fail_name;
+++ }
+++
+++ if (check_host_name((char *)peer_cn, host) < 0)
+++ goto cert_fail_name;
+++
+++ OPENSSL_free(peer_cn);
+++
+++ return 0;
+++
+++on_error:
+++ OPENSSL_free(peer_cn);
+++ return ssl_set_error(ssl, 0);
+++
+++cert_fail_name:
+++ OPENSSL_free(peer_cn);
+++ giterr_set(GITERR_SSL, "hostname does not match certificate");
+++ return GIT_ECERTIFICATE;
+++}
+++
+++typedef struct {
+++ git_stream parent;
+++ git_stream *io;
+++ bool connected;
+++ char *host;
+++ SSL *ssl;
+++ git_cert_x509 cert_info;
+++} openssl_stream;
+++
+++int openssl_close(git_stream *stream);
+++
+++int openssl_connect(git_stream *stream)
+++{
+++ int ret;
+++ BIO *bio;
+++ openssl_stream *st = (openssl_stream *) stream;
+++
+++ if ((ret = git_stream_connect(st->io)) < 0)
+++ return ret;
+++
+++ st->connected = true;
+++
+++ bio = BIO_new(git_stream_bio_method);
+++ GITERR_CHECK_ALLOC(bio);
+++
+++ BIO_set_data(bio, st->io);
+++ SSL_set_bio(st->ssl, bio, bio);
+++
+++ /* specify the host in case SNI is needed */
+++#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+++ SSL_set_tlsext_host_name(st->ssl, st->host);
+++#endif
+++
+++ if ((ret = SSL_connect(st->ssl)) <= 0)
+++ return ssl_set_error(st->ssl, ret);
+++
+++ return verify_server_cert(st->ssl, st->host);
+++}
+++
+++int openssl_certificate(git_cert **out, git_stream *stream)
+++{
+++ openssl_stream *st = (openssl_stream *) stream;
+++ int len;
+++ X509 *cert = SSL_get_peer_certificate(st->ssl);
+++ unsigned char *guard, *encoded_cert;
+++
+++ /* Retrieve the length of the certificate first */
+++ len = i2d_X509(cert, NULL);
+++ if (len < 0) {
+++ giterr_set(GITERR_NET, "failed to retrieve certificate information");
+++ return -1;
+++ }
+++
+++ encoded_cert = git__malloc(len);
+++ GITERR_CHECK_ALLOC(encoded_cert);
+++ /* i2d_X509 makes 'guard' point to just after the data */
+++ guard = encoded_cert;
+++
+++ len = i2d_X509(cert, &guard);
+++ if (len < 0) {
+++ git__free(encoded_cert);
+++ giterr_set(GITERR_NET, "failed to retrieve certificate information");
+++ return -1;
+++ }
+++
+++ st->cert_info.parent.cert_type = GIT_CERT_X509;
+++ st->cert_info.data = encoded_cert;
+++ st->cert_info.len = len;
+++
+++ *out = &st->cert_info.parent;
+++
+++ return 0;
+++}
+++
+++static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
+++{
+++ openssl_stream *st = (openssl_stream *) stream;
+++
+++ return git_stream_set_proxy(st->io, proxy_opts);
+++}
+++
+++ssize_t openssl_write(git_stream *stream, const char *data, size_t len, int flags)
+++{
+++ openssl_stream *st = (openssl_stream *) stream;
+++ int ret;
+++
+++ GIT_UNUSED(flags);
+++
+++ if ((ret = SSL_write(st->ssl, data, len)) <= 0) {
+++ return ssl_set_error(st->ssl, ret);
+++ }
+++
+++ return ret;
+++}
+++
+++ssize_t openssl_read(git_stream *stream, void *data, size_t len)
+++{
+++ openssl_stream *st = (openssl_stream *) stream;
+++ int ret;
+++
+++ if ((ret = SSL_read(st->ssl, data, len)) <= 0)
+++ return ssl_set_error(st->ssl, ret);
+++
+++ return ret;
+++}
+++
+++int openssl_close(git_stream *stream)
+++{
+++ openssl_stream *st = (openssl_stream *) stream;
+++ int ret;
+++
+++ if (st->connected && (ret = ssl_teardown(st->ssl)) < 0)
+++ return -1;
+++
+++ st->connected = false;
+++
+++ return git_stream_close(st->io);
+++}
+++
+++void openssl_free(git_stream *stream)
+++{
+++ openssl_stream *st = (openssl_stream *) stream;
+++
+++ SSL_free(st->ssl);
+++ git__free(st->host);
+++ git__free(st->cert_info.data);
+++ git_stream_free(st->io);
+++ git__free(st);
+++}
+++
+++int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
+++{
+++ int error;
+++ openssl_stream *st;
+++
+++ st = git__calloc(1, sizeof(openssl_stream));
+++ GITERR_CHECK_ALLOC(st);
+++
+++ st->io = NULL;
+++#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)
+++ goto out_err;
+++
+++ st->ssl = SSL_new(git__ssl_ctx);
+++ if (st->ssl == NULL) {
+++ giterr_set(GITERR_SSL, "failed to create ssl object");
+++ error = -1;
+++ goto out_err;
+++ }
+++
+++ 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 = openssl_connect;
+++ st->parent.certificate = openssl_certificate;
+++ st->parent.set_proxy = openssl_set_proxy;
+++ st->parent.read = openssl_read;
+++ st->parent.write = openssl_write;
+++ st->parent.close = openssl_close;
+++ st->parent.free = openssl_free;
+++
+++ *out = (git_stream *) st;
+++ return 0;
+++
+++out_err:
+++ git_stream_free(st->io);
+++ git__free(st);
+++
+++ return error;
+++}
+++
+++int git_openssl_set_cert_file(const char *file, const char *path)
+++{
+++ if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) {
+++ giterr_set(GITERR_SSL, "SSL error: %s",
+++ ERR_error_string(ERR_get_error(), NULL));
+++ return -1;
+++ }
+++ return 0;
+++}
+++
+++#else
+++
+++#include "stream.h"
+++#include "git2/sys/openssl.h"
+++
+++int git_openssl_stream_global_init(void)
+++{
+++ return 0;
+++}
+++
+++int git_openssl_set_locking(void)
+++{
+++ giterr_set(GITERR_SSL, "libgit2 was not built with OpenSSL support");
+++ return -1;
+++}
+++
+++int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
+++{
+++ GIT_UNUSED(out);
+++ GIT_UNUSED(host);
+++ GIT_UNUSED(port);
+++
+++ giterr_set(GITERR_SSL, "openssl is not supported in this version");
+++ return -1;
+++}
+++
+++int git_openssl_set_ca_location(const char *file, const char *path)
+++{
+++ GIT_UNUSED(file);
+++ GIT_UNUSED(path);
+++
+++ giterr_set(GITERR_SSL, "openssl is not supported in this version");
+++ return -1;
+++}
+++
+++#endif
++diff --git a/src/streams/openssl.h b/src/streams/openssl.h
++new file mode 100644
++index 0000000..8c7a84d
++--- /dev/null
+++++ b/src/streams/openssl.h
++@@ -0,0 +1,124 @@
+++/*
+++ * 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_openssl_stream_h__
+++#define INCLUDE_openssl_stream_h__
+++
+++#include "git2/sys/stream.h"
+++
+++extern int git_openssl_stream_global_init(void);
+++
+++extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
+++
+++extern int git_openssl_set_cert_file(const char *file, const char *path);
+++
+++/*
+++ * 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.
+++ */
+++#ifdef GIT_OPENSSL
+++# include <openssl/ssl.h>
+++# include <openssl/err.h>
+++# include <openssl/x509v3.h>
+++# include <openssl/bio.h>
+++
+++
+++
+++# if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+++
+++GIT_INLINE(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;
+++}
+++
+++GIT_INLINE(void) BIO_meth_free(BIO_METHOD *biom)
+++{
+++ git__free(biom);
+++}
+++
+++GIT_INLINE(int) BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
+++{
+++ biom->bwrite = write;
+++ return 1;
+++}
+++
+++GIT_INLINE(int) BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
+++{
+++ biom->bread = read;
+++ return 1;
+++}
+++
+++GIT_INLINE(int) BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
+++{
+++ biom->bputs = puts;
+++ return 1;
+++}
+++
+++GIT_INLINE(int) BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
+++
+++{
+++ biom->bgets = gets;
+++ return 1;
+ +}
+ +
+-+int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
+++GIT_INLINE(int) BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
+++{
+++ biom->ctrl = ctrl;
+++ return 1;
+++}
+++
+++GIT_INLINE(int) BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *))
+++{
+++ biom->create = create;
+++ return 1;
+++}
+++
+++GIT_INLINE(int) BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *))
+++{
+++ biom->destroy = destroy;
+++ return 1;
+++}
+++
+++GIT_INLINE(int) BIO_get_new_index(void)
+++{
+++ /* This exists as of 1.1 so before we'd just have 0 */
+++ return 0;
+++}
+++
+++GIT_INLINE(void) BIO_set_init(BIO *b, int init)
+++{
+++ b->init = init;
+++}
+++
+++GIT_INLINE(void) BIO_set_data(BIO *a, void *ptr)
+++{
+++ a->ptr = ptr;
+++}
+++
+++GIT_INLINE(void*) BIO_get_data(BIO *a)
+++{
+++ return a->ptr;
+++}
+++
+++GIT_INLINE(const unsigned char *) ASN1_STRING_get0_data(const ASN1_STRING *x)
+++{
+++ return ASN1_STRING_data((ASN1_STRING *)x);
+++}
+++
+++# endif // OpenSSL < 1.1
+++#endif // GIT_OPENSSL
+++
+++#endif
++diff --git a/src/streams/socket.c b/src/streams/socket.c
++new file mode 100644
++index 0000000..1150b40
++--- /dev/null
+++++ b/src/streams/socket.c
++@@ -0,0 +1,210 @@
+++/*
+++ * 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 "posix.h"
+++#include "netops.h"
+++#include "stream.h"
+++#include "streams/socket.h"
+++
+++#ifndef _WIN32
+++# include <sys/types.h>
+++# include <sys/socket.h>
+++# include <sys/select.h>
+++# include <sys/time.h>
+++# include <netdb.h>
+++# include <netinet/in.h>
+++# include <arpa/inet.h>
+++#else
+++# include <winsock2.h>
+++# include <ws2tcpip.h>
+++# ifdef _MSC_VER
+++# pragma comment(lib, "ws2_32")
+++# endif
+++#endif
+++
+++#ifdef GIT_WIN32
+++static void net_set_error(const char *str)
+++{
+++ int error = WSAGetLastError();
+++ char * win32_error = git_win32_get_error_message(error);
+++
+++ if (win32_error) {
+++ giterr_set(GITERR_NET, "%s: %s", str, win32_error);
+++ git__free(win32_error);
+++ } else {
+++ giterr_set(GITERR_NET, str);
+++ }
+++}
+++#else
+++static void net_set_error(const char *str)
+ +{
+-+ GIT_UNUSED(out);
+-+ GIT_UNUSED(host);
+-+ GIT_UNUSED(port);
+++ giterr_set(GITERR_NET, "%s: %s", str, strerror(errno));
+++}
+++#endif
+++
+++static int close_socket(GIT_SOCKET s)
+++{
+++ if (s == INVALID_SOCKET)
+++ return 0;
+++
+++#ifdef GIT_WIN32
+++ if (SOCKET_ERROR == closesocket(s))
+++ return -1;
+++
+++ if (0 != WSACleanup()) {
+++ giterr_set(GITERR_OS, "winsock cleanup failed");
+++ return -1;
+++ }
+++
+++ return 0;
+++#else
+++ return close(s);
+++#endif
+ +
+-+ giterr_set(GITERR_SSL, "mbedTLS is not supported in this version");
+-+ return -1;
+ +}
+ +
+++int socket_connect(git_stream *stream)
+++{
+++ struct addrinfo *info = NULL, *p;
+++ struct addrinfo hints;
+++ git_socket_stream *st = (git_socket_stream *) stream;
+++ GIT_SOCKET s = INVALID_SOCKET;
+++ int ret;
+++
+++#ifdef GIT_WIN32
+++ /* on win32, the WSA context needs to be initialized
+++ * before any socket calls can be performed */
+++ WSADATA wsd;
+++
+++ if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
+++ giterr_set(GITERR_OS, "winsock init failed");
+++ return -1;
+++ }
+++
+++ if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) {
+++ WSACleanup();
+++ giterr_set(GITERR_OS, "winsock init failed");
+++ return -1;
+++ }
+ +#endif
+ +
+-diff --git a/src/mbedtls_stream.h b/src/mbedtls_stream.h
+++ memset(&hints, 0x0, sizeof(struct addrinfo));
+++ hints.ai_socktype = SOCK_STREAM;
+++ hints.ai_family = AF_UNSPEC;
+++
+++ if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) {
+++ giterr_set(GITERR_NET,
+++ "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret));
+++ return -1;
+++ }
+++
+++ for (p = info; p != NULL; p = p->ai_next) {
+++ s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+++
+++ if (s == INVALID_SOCKET)
+++ continue;
+++
+++ if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
+++ break;
+++
+++ /* If we can't connect, try the next one */
+++ close_socket(s);
+++ s = INVALID_SOCKET;
+++ }
+++
+++ /* Oops, we couldn't connect to any address */
+++ if (s == INVALID_SOCKET && p == NULL) {
+++ giterr_set(GITERR_OS, "failed to connect to %s", st->host);
+++ p_freeaddrinfo(info);
+++ return -1;
+++ }
+++
+++ st->s = s;
+++ p_freeaddrinfo(info);
+++ return 0;
+++}
+++
+++ssize_t socket_write(git_stream *stream, const char *data, size_t len, int flags)
+++{
+++ ssize_t ret;
+++ size_t off = 0;
+++ git_socket_stream *st = (git_socket_stream *) stream;
+++
+++ while (off < len) {
+++ errno = 0;
+++ ret = p_send(st->s, data + off, len - off, flags);
+++ if (ret < 0) {
+++ net_set_error("Error sending data");
+++ return -1;
+++ }
+++
+++ off += ret;
+++ }
+++
+++ return off;
+++}
+++
+++ssize_t socket_read(git_stream *stream, void *data, size_t len)
+++{
+++ ssize_t ret;
+++ git_socket_stream *st = (git_socket_stream *) stream;
+++
+++ if ((ret = p_recv(st->s, data, len, 0)) < 0)
+++ net_set_error("Error receiving socket data");
+++
+++ return ret;
+++}
+++
+++int socket_close(git_stream *stream)
+++{
+++ git_socket_stream *st = (git_socket_stream *) stream;
+++ int error;
+++
+++ error = close_socket(st->s);
+++ st->s = INVALID_SOCKET;
+++
+++ return error;
+++}
+++
+++void socket_free(git_stream *stream)
+++{
+++ git_socket_stream *st = (git_socket_stream *) stream;
+++
+++ git__free(st->host);
+++ git__free(st->port);
+++ git__free(st);
+++}
+++
+++int git_socket_stream_new(git_stream **out, const char *host, const char *port)
+++{
+++ git_socket_stream *st;
+++
+++ assert(out && host);
+++
+++ st = git__calloc(1, sizeof(git_socket_stream));
+++ GITERR_CHECK_ALLOC(st);
+++
+++ st->host = git__strdup(host);
+++ GITERR_CHECK_ALLOC(st->host);
+++
+++ if (port) {
+++ st->port = git__strdup(port);
+++ GITERR_CHECK_ALLOC(st->port);
+++ }
+++
+++ st->parent.version = GIT_STREAM_VERSION;
+++ st->parent.connect = socket_connect;
+++ st->parent.write = socket_write;
+++ st->parent.read = socket_read;
+++ st->parent.close = socket_close;
+++ st->parent.free = socket_free;
+++ st->s = INVALID_SOCKET;
+++
+++ *out = (git_stream *) st;
+++ return 0;
+++}
++diff --git a/src/streams/socket.h b/src/streams/socket.h
+ new file mode 100644
+-index 0000000..5cb1071
++index 0000000..8e9949f
+ --- /dev/null
+-+++ b/src/mbedtls_stream.h
+-@@ -0,0 +1,16 @@
+++++ b/src/streams/socket.h
++@@ -0,0 +1,21 @@
+ +/*
+ + * 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__
+++#ifndef INCLUDE_socket_stream_h__
+++#define INCLUDE_socket_stream_h__
+ +
+-+#include "git2/sys/stream.h"
+++#include "netops.h"
+ +
+-+extern int git_mbedtls_stream_global_init(void);
+++typedef struct {
+++ git_stream parent;
+++ char *host;
+++ char *port;
+++ GIT_SOCKET s;
+++} git_socket_stream;
+ +
+-+extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port);
+++extern int git_socket_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 <openssl/err.h>
+- #endif
+-
+-+#ifdef GIT_MBEDTLS
+-+# include <mbedtls/error.h>
++diff --git a/src/streams/stransport.c b/src/streams/stransport.c
++new file mode 100644
++index 0000000..4c099f9
++--- /dev/null
+++++ b/src/streams/stransport.c
++@@ -0,0 +1,294 @@
+++/*
+++ * 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_SECURE_TRANSPORT
+++
+++#include <CoreFoundation/CoreFoundation.h>
+++#include <Security/SecureTransport.h>
+++#include <Security/SecCertificate.h>
+++
+++#include "git2/transport.h"
+++
+++#include "streams/socket.h"
+++#include "streams/curl.h"
+++
+++static int stransport_error(OSStatus ret)
+++{
+++ CFStringRef message;
+++
+++ if (ret == noErr || ret == errSSLClosedGraceful) {
+++ giterr_clear();
+++ return 0;
+++ }
+++
+++#if !TARGET_OS_IPHONE
+++ message = SecCopyErrorMessageString(ret, NULL);
+++ GITERR_CHECK_ALLOC(message);
+++
+++ giterr_set(GITERR_NET, "SecureTransport error: %s", CFStringGetCStringPtr(message, kCFStringEncodingUTF8));
+++ CFRelease(message);
+++#else
+++ giterr_set(GITERR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret);
+++ GIT_UNUSED(message);
+ +#endif
+ +
+- #include <git2.h>
+- #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);
+-+ }
+++ return -1;
+++}
+++
+++typedef struct {
+++ git_stream parent;
+++ git_stream *io;
+++ SSLContextRef ctx;
+++ CFDataRef der_data;
+++ git_cert_x509 cert_info;
+++} stransport_stream;
+++
+++static int stransport_connect(git_stream *stream)
+++{
+++ stransport_stream *st = (stransport_stream *) stream;
+++ int error;
+++ SecTrustRef trust = NULL;
+++ SecTrustResultType sec_res;
+++ OSStatus ret;
+++
+++ if ((error = git_stream_connect(st->io)) < 0)
+++ return error;
+++
+++ ret = SSLHandshake(st->ctx);
+++ if (ret != errSSLServerAuthCompleted) {
+++ giterr_set(GITERR_SSL, "unexpected return value from ssl handshake %d", ret);
+++ return -1;
+++ }
+++
+++ if ((ret = SSLCopyPeerTrust(st->ctx, &trust)) != noErr)
+++ goto on_error;
+++
+++ if (!trust)
+++ return GIT_ECERTIFICATE;
+++
+++ if ((ret = SecTrustEvaluate(trust, &sec_res)) != noErr)
+++ goto on_error;
+++
+++ CFRelease(trust);
+++
+++ if (sec_res == kSecTrustResultInvalid || sec_res == kSecTrustResultOtherError) {
+++ giterr_set(GITERR_SSL, "internal security trust error");
+++ return -1;
+++ }
+++
+++ if (sec_res == kSecTrustResultDeny || sec_res == kSecTrustResultRecoverableTrustFailure ||
+++ sec_res == kSecTrustResultFatalTrustFailure)
+++ return GIT_ECERTIFICATE;
+++
+++ return 0;
+++
+++on_error:
+++ if (trust)
+++ CFRelease(trust);
+++
+++ return stransport_error(ret);
+++}
+++
+++static int stransport_certificate(git_cert **out, git_stream *stream)
+++{
+++ stransport_stream *st = (stransport_stream *) stream;
+++ SecTrustRef trust = NULL;
+++ SecCertificateRef sec_cert;
+++ OSStatus ret;
+++
+++ if ((ret = SSLCopyPeerTrust(st->ctx, &trust)) != noErr)
+++ return stransport_error(ret);
+++
+++ sec_cert = SecTrustGetCertificateAtIndex(trust, 0);
+++ st->der_data = SecCertificateCopyData(sec_cert);
+++ CFRelease(trust);
+++
+++ if (st->der_data == NULL) {
+++ giterr_set(GITERR_SSL, "retrieved invalid certificate data");
+++ return -1;
+++ }
+++
+++ st->cert_info.parent.cert_type = GIT_CERT_X509;
+++ st->cert_info.data = (void *) CFDataGetBytePtr(st->der_data);
+++ st->cert_info.len = CFDataGetLength(st->der_data);
+++
+++ *out = (git_cert *)&st->cert_info;
+++ return 0;
+++}
+++
+++static int stransport_set_proxy(
+++ git_stream *stream,
+++ const git_proxy_options *proxy_opts)
+++{
+++ stransport_stream *st = (stransport_stream *) stream;
+++
+++ return git_stream_set_proxy(st->io, proxy_opts);
+++}
+++
+++/*
+++ * Contrary to typical network IO callbacks, Secure Transport write callback is
+++ * expected to write *all* passed data, not just as much as it can, and any
+++ * other case would be considered a failure.
+++ *
+++ * This behavior is actually not specified in the Apple documentation, but is
+++ * required for things to work correctly (and incidentally, that's also how
+++ * Apple implements it in its projects at opensource.apple.com).
+++ *
+++ * Libgit2 streams happen to already have this very behavior so this is just
+++ * passthrough.
+++ */
+++static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len)
+++{
+++ git_stream *io = (git_stream *) conn;
+++
+++ if (git_stream_write(io, data, *len, 0) < 0) {
+++ return -36; /* "ioErr" from MacErrors.h which is not available on iOS */
+++ }
+++
+++ return noErr;
+++}
+++
+++static ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int flags)
+++{
+++ stransport_stream *st = (stransport_stream *) stream;
+++ size_t data_len, processed;
+++ OSStatus ret;
+++
+++ GIT_UNUSED(flags);
+++
+++ data_len = len;
+++ if ((ret = SSLWrite(st->ctx, data, data_len, &processed)) != noErr)
+++ return stransport_error(ret);
+++
+++ return processed;
+++}
+++
+++/*
+++ * Contrary to typical network IO callbacks, Secure Transport read callback is
+++ * expected to read *exactly* the requested number of bytes, not just as much
+++ * as it can, and any other case would be considered a failure.
+++ *
+++ * This behavior is actually not specified in the Apple documentation, but is
+++ * required for things to work correctly (and incidentally, that's also how
+++ * Apple implements it in its projects at opensource.apple.com).
+++ */
+++static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len)
+++{
+++ git_stream *io = (git_stream *) conn;
+++ OSStatus error = noErr;
+++ size_t off = 0;
+++ ssize_t ret;
+++
+++ do {
+++ ret = git_stream_read(io, data + off, *len - off);
+++ if (ret < 0) {
+++ error = -36; /* "ioErr" from MacErrors.h which is not available on iOS */
+++ break;
+ + }
+- #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;
+++ if (ret == 0) {
+++ error = errSSLClosedGraceful;
+++ break;
+++ }
+++
+++ off += ret;
+++ } while (off < *len);
+++
+++ *len = off;
+++ return error;
+++}
+++
+++static ssize_t stransport_read(git_stream *stream, void *data, size_t len)
+++{
+++ stransport_stream *st = (stransport_stream *) stream;
+++ size_t processed;
+++ OSStatus ret;
+++
+++ if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr)
+++ return stransport_error(ret);
+++
+++ return processed;
+++}
+++
+++static int stransport_close(git_stream *stream)
+++{
+++ stransport_stream *st = (stransport_stream *) stream;
+++ OSStatus ret;
+++
+++ ret = SSLClose(st->ctx);
+++ if (ret != noErr && ret != errSSLClosedGraceful)
+++ return stransport_error(ret);
+++
+++ return git_stream_close(st->io);
+++}
+++
+++static void stransport_free(git_stream *stream)
+++{
+++ stransport_stream *st = (stransport_stream *) stream;
+++
+++ git_stream_free(st->io);
+++ CFRelease(st->ctx);
+++ if (st->der_data)
+++ CFRelease(st->der_data);
+++ git__free(st);
+++}
+++
+++int git_stransport_stream_new(git_stream **out, const char *host, const char *port)
+++{
+++ stransport_stream *st;
+++ int error;
+++ OSStatus ret;
+++
+++ assert(out && host);
+++
+++ st = git__calloc(1, sizeof(stransport_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){
+++ git__free(st);
+++ return error;
+++ }
+++
+++ st->ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
+++ if (!st->ctx) {
+++ giterr_set(GITERR_NET, "failed to create SSL context");
+++ git__free(st);
+++ return -1;
+++ }
+++
+++ if ((ret = SSLSetIOFuncs(st->ctx, read_cb, write_cb)) != noErr ||
+++ (ret = SSLSetConnection(st->ctx, st->io)) != noErr ||
+++ (ret = SSLSetSessionOption(st->ctx, kSSLSessionOptionBreakOnServerAuth, true)) != noErr ||
+++ (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr ||
+++ (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr ||
+++ (ret = SSLSetPeerDomainName(st->ctx, host, strlen(host))) != noErr) {
+++ CFRelease(st->ctx);
+++ git__free(st);
+++ return stransport_error(ret);
+++ }
+++
+++ st->parent.version = GIT_STREAM_VERSION;
+++ st->parent.encrypted = 1;
+++ st->parent.proxy_support = git_stream_supports_proxy(st->io);
+++ st->parent.connect = stransport_connect;
+++ st->parent.certificate = stransport_certificate;
+++ st->parent.set_proxy = stransport_set_proxy;
+++ st->parent.read = stransport_read;
+++ st->parent.write = stransport_write;
+++ st->parent.close = stransport_close;
+++ st->parent.free = stransport_free;
+++
+++ *out = (git_stream *) st;
+++ return 0;
+++}
+++
+++#endif
++diff --git a/src/streams/stransport.h b/src/streams/stransport.h
++new file mode 100644
++index 0000000..714f902
++--- /dev/null
+++++ b/src/streams/stransport.h
++@@ -0,0 +1,14 @@
+++/*
+++ * 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_stransport_stream_h__
+++#define INCLUDE_stransport_stream_h__
+++
+++#include "git2/sys/stream.h"
+++
+++extern int git_stransport_stream_new(git_stream **out, const char *host, const char *port);
+++
+++#endif
+ diff --git a/src/tls_stream.c b/src/tls_stream.c
+-index 83e2d06..6fb538f 100644
++index 83e2d06..27e5cc2 100644
+ --- a/src/tls_stream.c
+ +++ b/src/tls_stream.c
+-@@ -9,6 +9,7 @@
++@@ -8,8 +8,9 @@
++ #include "git2/errors.h"
+ #include "common.h"
+
+- #include "openssl_stream.h"
+-+#include "mbedtls_stream.h"
+- #include "stransport_stream.h"
++-#include "openssl_stream.h"
++-#include "stransport_stream.h"
+++#include "streams/mbedtls.h"
+++#include "streams/openssl.h"
+++#include "streams/stransport.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);
+++ return git_mbedtls_stream_new(out, host, port);
+ #else
+ GIT_UNUSED(out);
+ GIT_UNUSED(host);
++diff --git a/src/transports/git.c b/src/transports/git.c
++index 01edfdc..cae10c3 100644
++--- a/src/transports/git.c
+++++ b/src/transports/git.c
++@@ -10,7 +10,7 @@
++ #include "netops.h"
++ #include "git2/sys/transport.h"
++ #include "stream.h"
++-#include "socket_stream.h"
+++#include "streams/socket.h"
++
++ #define OWNING_SUBTRANSPORT(s) ((git_subtransport *)(s)->parent.subtransport)
++
++diff --git a/src/transports/http.c b/src/transports/http.c
++index cb4a6d0..b602adf 100644
++--- a/src/transports/http.c
+++++ b/src/transports/http.c
++@@ -16,8 +16,8 @@
++ #include "auth.h"
++ #include "auth_negotiate.h"
++ #include "tls_stream.h"
++-#include "socket_stream.h"
++-#include "curl_stream.h"
+++#include "streams/socket.h"
+++#include "streams/curl.h"
++
++ git_http_auth_scheme auth_schemes[] = {
++ { GIT_AUTHTYPE_NEGOTIATE, "Negotiate", GIT_CREDTYPE_DEFAULT, git_http_auth_negotiate },
++diff --git a/src/transports/ssh.c b/src/transports/ssh.c
++index 4c55e3f..3cb5655 100644
++--- a/src/transports/ssh.c
+++++ b/src/transports/ssh.c
++@@ -15,7 +15,7 @@
++ #include "netops.h"
++ #include "smart.h"
++ #include "cred.h"
++-#include "socket_stream.h"
+++#include "streams/socket.h"
++ #include "ssh.h"
++
++ #ifdef GIT_SSH
+ diff --git a/tests/core/stream.c b/tests/core/stream.c
+-index 0cbf442..a4fa2b4 100644
++index 0cbf442..2da4b2f 100644
+ --- a/tests/core/stream.c
+ +++ b/tests/core/stream.c
+-@@ -38,7 +38,7 @@ void test_core_stream__register_tls(void)
++@@ -37,8 +37,7 @@ void test_core_stream__register_tls(void)
++ * or when openssl support is disabled (except on OSX
+ * with Security framework).
+ */
+- #if defined(GIT_WIN32) || \
++-#if defined(GIT_WIN32) || \
+ - (!defined(GIT_SECURE_TRANSPORT) && !defined(GIT_OPENSSL))
+-+ (!defined(GIT_SECURE_TRANSPORT) && !(defined(GIT_OPENSSL) || defined(GIT_MBEDTLS)))
+++#if defined(GIT_WIN32) || !defined(GIT_HTTPS)
+ 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 @@
++diff --git a/tests/main.c b/tests/main.c
++index f67c8ff..3dadc5d 100644
++--- a/tests/main.c
+++++ b/tests/main.c
++@@ -11,7 +11,11 @@ int main(int argc, char *argv[])
+
+- static git_repository *g_repo;
++ clar_test_init(argc, argv);
++
++- git_libgit2_init();
+++ res = git_libgit2_init();
+++ if (res < 0) {
+++ return res;
+++ }
+++
++ cl_global_trace_register();
++ cl_sandbox_set_search_path_defaults();
+
+--#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-remote-push-NULL.patch b/deps/patches/libgit2-remote-push-NULL.patch
+deleted file mode 100644
+index ac84d6d1bacb..000000000000
+--- a/deps/patches/libgit2-remote-push-NULL.patch
++++ /dev/null
+@@ -1,26 +0,0 @@
+-From 90cdf44ffb7c78cb9d36709f8a07a216e06bd919 Mon Sep 17 00:00:00 2001
+-From: Yichao Yu <yyc1992@gmail.com>
+-Date: Sat, 29 Apr 2017 13:00:07 -0400
+-Subject: [PATCH] Allow NULL refspec in git_remote_push
+-
+-Since this is allowed in `git_remote_upload`
+----
+- src/remote.c | 2 +-
+- 1 file changed, 1 insertion(+), 1 deletion(-)
+-
+-diff --git a/src/remote.c b/src/remote.c
+-index d3132f75c..4cbc45eda 100644
+---- a/src/remote.c
+-+++ b/src/remote.c
+-@@ -2412,7 +2412,7 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
+- proxy = &opts->proxy_opts;
+- }
+-
+-- assert(remote && refspecs);
+-+ assert(remote);
+-
+- if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
+- return error;
+---
+-2.12.2
+-
+
+From 5492792021061ec6861564dad9575d5d6889c80d Mon Sep 17 00:00:00 2001
+From: Curtis Vogt <curtis.vogt@gmail.com>
+Date: Sun, 2 Jul 2017 23:30:48 -0500
+Subject: [PATCH 2/2] Remove libgit2-free-config patch
+
+---
+ deps/patches/libgit2-free-config.patch | 25 -------------------------
+ 1 file changed, 25 deletions(-)
+ delete mode 100644 deps/patches/libgit2-free-config.patch
+
+diff --git a/deps/patches/libgit2-free-config.patch b/deps/patches/libgit2-free-config.patch
+deleted file mode 100644
+index 767aa816c3c1..000000000000
+--- a/deps/patches/libgit2-free-config.patch
++++ /dev/null
+@@ -1,25 +0,0 @@
+-From 5552237686dae90fb9c22f0088de488b48654828 Mon Sep 17 00:00:00 2001
+-From: Yichao Yu <yyc1992@gmail.com>
+-Date: Sat, 29 Apr 2017 12:28:35 -0400
+-Subject: [PATCH] Do not free config when creating remote
+-
+-The regression was introduced in 22261344de18b3cc60ee6937468d66a6a6a28875
+----
+- src/remote.c | 1 -
+- 1 file changed, 1 deletion(-)
+-
+-diff --git a/src/remote.c b/src/remote.c
+-index d3132f75c..15752ab27 100644
+---- a/src/remote.c
+-+++ b/src/remote.c
+-@@ -260,7 +260,6 @@ on_error:
+- if (error)
+- git_remote_free(remote);
+-
+-- git_config_free(config);
+- git_buf_free(&canonical_url);
+- git_buf_free(&var);
+- return error;
+---
+-2.12.2
+-
--
2.15.0
---
Unsubscribe: alpine-aports+unsubscribe@lists.alpinelinux.org
Help: alpine-aports+help@lists.alpinelinux.org
---