diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt index e806033aab86ae..3968fbb697aea2 100644 --- a/Documentation/config/http.txt +++ b/Documentation/config/http.txt @@ -29,6 +29,27 @@ http.proxyAuthMethod:: * `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`) -- +http.proxySSLCert:: + The pathname of a file that stores a client certificate to use to authenticate + with an HTTPS proxy. Can be overridden by the `GIT_PROXY_SSL_CERT` environment + variable. + +http.proxySSLKey:: + The pathname of a file that stores a private key to use to authenticate with + an HTTPS proxy. Can be overridden by the `GIT_PROXY_SSL_KEY` environment + variable. + +http.proxySSLCertPasswordProtected:: + Enable Git's password prompt for the proxy SSL certificate. Otherwise OpenSSL + will prompt the user, possibly many times, if the certificate or private key + is encrypted. Can be overriden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED` + environment variable. + +http.proxySSLCAInfo:: + Pathname to the file containing the certificate bundle that should be used to + verify the proxy with when using an HTTPS proxy. Can be overriden by the + `GIT_PROXY_SSL_CAINFO` environment variable. + http.emptyAuth:: Attempt authentication without seeking a username or password. This can be used to attempt GSS-Negotiate authentication without specifying diff --git a/http.c b/http.c index 00a0e507633b3a..4283be9479b1f5 100644 --- a/http.c +++ b/http.c @@ -86,6 +86,13 @@ static long curl_low_speed_time = -1; static int curl_ftp_no_epsv; static const char *curl_http_proxy; static const char *http_proxy_authmethod; + +static const char *http_proxy_ssl_cert; +static const char *http_proxy_ssl_key; +static const char *http_proxy_ssl_ca_info; +static struct credential proxy_cert_auth = CREDENTIAL_INIT; +static int proxy_ssl_cert_password_required; + static struct { const char *name; long curlauth_param; @@ -365,6 +372,20 @@ static int http_options(const char *var, const char *value, void *cb) if (!strcmp("http.proxyauthmethod", var)) return git_config_string(&http_proxy_authmethod, var, value); + if (!strcmp("http.proxysslcert", var)) + return git_config_string(&http_proxy_ssl_cert, var, value); + + if (!strcmp("http.proxysslkey", var)) + return git_config_string(&http_proxy_ssl_key, var, value); + + if (!strcmp("http.proxysslcainfo", var)) + return git_config_string(&http_proxy_ssl_ca_info, var, value); + + if (!strcmp("http.proxysslcertpasswordprotected", var)) { + proxy_ssl_cert_password_required = git_config_bool(var, value); + return 0; + } + if (!strcmp("http.cookiefile", var)) return git_config_pathname(&curl_cookie_file, var, value); if (!strcmp("http.savecookies", var)) { @@ -565,6 +586,21 @@ static int has_cert_password(void) return 1; } +#if LIBCURL_VERSION_NUM >= 0x073400 +static int has_proxy_cert_password(void) +{ + if (http_proxy_ssl_cert == NULL || proxy_ssl_cert_password_required != 1) + return 0; + if (!proxy_cert_auth.password) { + proxy_cert_auth.protocol = xstrdup("cert"); + proxy_cert_auth.username = xstrdup(""); + proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert); + credential_fill(&proxy_cert_auth); + } + return 1; +} +#endif + #if LIBCURL_VERSION_NUM >= 0x071900 static void set_curl_keepalive(CURL *c) { @@ -924,8 +960,14 @@ static CURL *get_curl_handle(void) #if LIBCURL_VERSION_NUM >= 0x073400 curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, NULL); #endif - } else if (ssl_cainfo != NULL) - curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo); + } else if (ssl_cainfo != NULL || http_proxy_ssl_ca_info != NULL) { + if (ssl_cainfo != NULL) + curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo); +#if LIBCURL_VERSION_NUM >= 0x073400 + if (http_proxy_ssl_ca_info != NULL) + curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, http_proxy_ssl_ca_info); +#endif + } if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) { curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT, @@ -1018,9 +1060,18 @@ static CURL *get_curl_handle(void) CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); #endif #if LIBCURL_VERSION_NUM >= 0x073400 - else if (starts_with(curl_http_proxy, "https")) - curl_easy_setopt(result, - CURLOPT_PROXYTYPE, CURLPROXY_HTTPS); + else if (starts_with(curl_http_proxy, "https")) { + curl_easy_setopt(result, CURLOPT_PROXYTYPE, CURLPROXY_HTTPS); + + if (http_proxy_ssl_cert) + curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT, http_proxy_ssl_cert); + + if (http_proxy_ssl_key) + curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY, http_proxy_ssl_key); + + if (has_proxy_cert_password()) + curl_easy_setopt(result, CURLOPT_PROXY_KEYPASSWD, proxy_cert_auth.password); + } #endif if (strstr(curl_http_proxy, "://")) credential_from_url(&proxy_auth, curl_http_proxy); @@ -1160,6 +1211,13 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) max_requests = DEFAULT_MAX_REQUESTS; #endif + set_from_env(&http_proxy_ssl_cert, "GIT_PROXY_SSL_CERT"); + set_from_env(&http_proxy_ssl_key, "GIT_PROXY_SSL_KEY"); + set_from_env(&http_proxy_ssl_ca_info, "GIT_PROXY_SSL_CAINFO"); + + if (getenv("GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED")) + proxy_ssl_cert_password_required = 1; + if (getenv("GIT_CURL_FTP_NO_EPSV")) curl_ftp_no_epsv = 1; @@ -1230,6 +1288,12 @@ void http_cleanup(void) } ssl_cert_password_required = 0; + if (proxy_cert_auth.password != NULL) { + memset(proxy_cert_auth.password, 0, strlen(proxy_cert_auth.password)); + FREE_AND_NULL(proxy_cert_auth.password); + } + proxy_ssl_cert_password_required = 0; + FREE_AND_NULL(cached_accept_language); }