[1/3] http: add support for selecting SSL backends at runtime
diff mbox series

Message ID 8c5ecdb6c9a73405036672db8bc1e36c5c6c6951.1539598481.git.gitgitgadget@gmail.com
State New
Headers show
Series
  • Allow choosing the SSL backend cURL uses (plus related patches)
Related show

Commit Message

starlord via GitGitGadget Oct. 15, 2018, 10:14 a.m. UTC
From: Johannes Schindelin <johannes.schindelin@gmx.de>

As of version 7.56.0, curl supports being compiled with multiple SSL
backends.

This patch adds the Git side of that feature: by setting http.sslBackend
to "openssl" or "schannel", Git for Windows can now choose the SSL
backend at runtime.

This comes in handy on Windows because Secure Channel ("schannel") is
the native solution, accessing the Windows Credential Store, thereby
allowing for enterprise-wide management of certificates. For historical
reasons, Git for Windows needs to support OpenSSL still, as it has
previously been the only supported SSL backend in Git for Windows for
almost a decade.

The patch has been carried in Git for Windows for over a year, and is
considered mature.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Documentation/config.txt |  5 +++++
 http.c                   | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

Comments

Eric Sunshine Oct. 15, 2018, 2:06 p.m. UTC | #1
On Mon, Oct 15, 2018 at 6:14 AM Johannes Schindelin via GitGitGadget
<gitgitgadget@gmail.com> wrote:
> This patch adds the Git side of that feature: by setting http.sslBackend
> to "openssl" or "schannel", Git for Windows can now choose the SSL
> backend at runtime.
> [...]
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
> diff --git a/http.c b/http.c
> @@ -995,6 +1003,33 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
> +#if LIBCURL_VERSION_NUM >= 0x073800
> +       if (http_ssl_backend) {
> +               const curl_ssl_backend **backends;
> +               struct strbuf buf = STRBUF_INIT;
> +               int i;
> +
> +               switch (curl_global_sslset(-1, http_ssl_backend, &backends)) {
> +               case CURLSSLSET_UNKNOWN_BACKEND:
> +                       strbuf_addf(&buf, _("Unsupported SSL backend '%s'. "
> +                                           "Supported SSL backends:"),
> +                                           http_ssl_backend);
> +                       for (i = 0; backends[i]; i++)
> +                               strbuf_addf(&buf, "\n\t%s", backends[i]->name);
> +                       die("%s", buf.buf);

This is the only 'case' arm which utilizes 'strbuf buf', and it
die()s, so no leak despite a lack of strbuf_release(). Okay.

> +               case CURLSSLSET_NO_BACKENDS:
> +                       die(_("Could not set SSL backend to '%s': "
> +                             "cURL was built without SSL backends"),
> +                           http_ssl_backend);
> +               case CURLSSLSET_TOO_LATE:
> +                       die(_("Could not set SSL backend to '%s': already set"),
> +                           http_ssl_backend);
> +               case CURLSSLSET_OK:
> +                       break; /* Okay! */
> +               }
> +       }
> +#endif

Patch
diff mbox series

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1546833213..7d38f0bf1a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1984,6 +1984,11 @@  http.sslCAPath::
 	with when fetching or pushing over HTTPS. Can be overridden
 	by the `GIT_SSL_CAPATH` environment variable.
 
+http.sslBackend::
+	Name of the SSL backend to use (e.g. "openssl" or "schannel").
+	This option is ignored if cURL lacks support for choosing the SSL
+	backend at runtime.
+
 http.pinnedpubkey::
 	Public key of the https service. It may either be the filename of
 	a PEM or DER encoded public key file or a string starting with
diff --git a/http.c b/http.c
index 98ff122585..7fb37a061b 100644
--- a/http.c
+++ b/http.c
@@ -155,6 +155,8 @@  static struct active_request_slot *active_queue_head;
 
 static char *cached_accept_language;
 
+static char *http_ssl_backend;
+
 size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
 {
 	size_t size = eltsize * nmemb;
@@ -302,6 +304,12 @@  static int http_options(const char *var, const char *value, void *cb)
 		curl_ssl_try = git_config_bool(var, value);
 		return 0;
 	}
+	if (!strcmp("http.sslbackend", var)) {
+		free(http_ssl_backend);
+		http_ssl_backend = xstrdup_or_null(value);
+		return 0;
+	}
+
 	if (!strcmp("http.minsessions", var)) {
 		min_curl_sessions = git_config_int(var, value);
 #ifndef USE_CURL_MULTI
@@ -995,6 +1003,33 @@  void http_init(struct remote *remote, const char *url, int proactive_auth)
 	git_config(urlmatch_config_entry, &config);
 	free(normalized_url);
 
+#if LIBCURL_VERSION_NUM >= 0x073800
+	if (http_ssl_backend) {
+		const curl_ssl_backend **backends;
+		struct strbuf buf = STRBUF_INIT;
+		int i;
+
+		switch (curl_global_sslset(-1, http_ssl_backend, &backends)) {
+		case CURLSSLSET_UNKNOWN_BACKEND:
+			strbuf_addf(&buf, _("Unsupported SSL backend '%s'. "
+					    "Supported SSL backends:"),
+					    http_ssl_backend);
+			for (i = 0; backends[i]; i++)
+				strbuf_addf(&buf, "\n\t%s", backends[i]->name);
+			die("%s", buf.buf);
+		case CURLSSLSET_NO_BACKENDS:
+			die(_("Could not set SSL backend to '%s': "
+			      "cURL was built without SSL backends"),
+			    http_ssl_backend);
+		case CURLSSLSET_TOO_LATE:
+			die(_("Could not set SSL backend to '%s': already set"),
+			    http_ssl_backend);
+		case CURLSSLSET_OK:
+			break; /* Okay! */
+		}
+	}
+#endif
+
 	if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
 		die("curl_global_init failed");