From: Junio C Hamano Date: Wed, 24 Feb 2016 21:25:58 +0000 (-0800) Subject: Merge branch 'ce/https-public-key-pinning' X-Git-Tag: v2.8.0-rc0~30 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/e79112d21024beb997951381db21a70b087d459d?hp=-c Merge branch 'ce/https-public-key-pinning' You can now set http.[.]pinnedpubkey to specify the pinned public key when building with recent enough versions of libcURL. * ce/https-public-key-pinning: http: implement public key pinning --- e79112d21024beb997951381db21a70b087d459d diff --combined Documentation/config.txt index 542cb229c8,bc0237fd62..2cd6bdd7d2 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@@ -308,15 -308,6 +308,15 @@@ core.trustctime: crawlers and some backup systems). See linkgit:git-update-index[1]. True by default. +core.untrackedCache:: + Determines what to do about the untracked cache feature of the + index. It will be kept, if this variable is unset or set to + `keep`. It will automatically be added if set to `true`. And + it will automatically be removed, if set to `false`. Before + setting it to `true`, you should check that mtime is working + properly on your system. + See linkgit:git-update-index[1]. `keep` by default. + core.checkStat:: Determines which stat fields to match between the index and work tree. The user can set this to 'default' or @@@ -879,8 -870,6 +879,8 @@@ When preserve, also pass `--preserve-me so that locally committed merge commits will not be flattened by running 'git pull'. + +When the value is `interactive`, the rebase is run in interactive mode. ++ *NOTE*: this is a possibly dangerous operation; do *not* use it unless you understand the implications (see linkgit:git-rebase[1] for details). @@@ -1254,10 -1243,6 +1254,10 @@@ format.coverLetter: format-patch is invoked, but in addition can be set to "auto", to generate a cover-letter only when there's more than one patch. +format.outputDirectory:: + Set a custom directory to store the resulting files instead of the + current working directory. + filter..clean:: The command which is used to convert the content of a worktree file to a blob upon checkin. See linkgit:gitattributes[5] for @@@ -1465,14 -1450,6 +1465,14 @@@ grep.extendedRegexp: option is ignored when the 'grep.patternType' option is set to a value other than 'default'. +grep.threads:: + Number of grep worker threads to use. + See `grep.threads` in linkgit:git-grep[1] for more information. + +grep.fallbackToNoIndex:: + If set to true, fall back to git grep --no-index if git grep + is executed outside of a git repository. Defaults to false. + gpg.program:: Use this custom program instead of "gpg" found on $PATH when making or verifying a PGP signature. The program must support the @@@ -1619,40 -1596,9 +1619,40 @@@ help.htmlPath: http.proxy:: Override the HTTP proxy, normally configured using the 'http_proxy', - 'https_proxy', and 'all_proxy' environment variables (see - `curl(1)`). This can be overridden on a per-remote basis; see - remote..proxy + 'https_proxy', and 'all_proxy' environment variables (see `curl(1)`). In + addition to the syntax understood by curl, it is possible to specify a + proxy string with a user name but no password, in which case git will + attempt to acquire one in the same way it does for other credentials. See + linkgit:gitcredentials[7] for more information. The syntax thus is + '[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden + on a per-remote basis; see remote..proxy + +http.proxyAuthMethod:: + Set the method with which to authenticate against the HTTP proxy. This + only takes effect if the configured proxy string contains a user name part + (i.e. is of the form 'user@host' or 'user@host:port'). This can be + overridden on a per-remote basis; see `remote..proxyAuthMethod`. + Both can be overridden by the 'GIT_HTTP_PROXY_AUTHMETHOD' environment + variable. Possible values are: ++ +-- +* `anyauth` - Automatically pick a suitable authentication method. It is + assumed that the proxy answers an unauthenticated request with a 407 + status code and one or more Proxy-authenticate headers with supported + authentication methods. This is the default. +* `basic` - HTTP Basic authentication +* `digest` - HTTP Digest authentication; this prevents the password from being + transmitted to the proxy in clear text +* `negotiate` - GSS-Negotiate authentication (compare the --negotiate option + of `curl(1)`) +* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`) +-- + +http.emptyAuth:: + Attempt authentication without seeking a username or password. This + can be used to attempt GSS-Negotiate authentication without specifying + a username in the URL, as libcurl normally requires a username for + authentication. http.cookieFile:: File containing previously stored cookie lines which should be used @@@ -1733,6 -1679,14 +1733,14 @@@ http.sslCAPath: with when fetching or pushing over HTTPS. Can be overridden by the 'GIT_SSL_CAPATH' environment variable. + 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 + 'sha256//' followed by the base64 encoded sha256 hash of the + public key. See also libcurl 'CURLOPT_PINNEDPUBLICKEY'. git will + exit with an error if this option is set but not supported by + cURL. + http.sslTry:: Attempt to use AUTH SSL/TLS and encrypted data transfers when connecting via regular FTP protocol. This might be needed @@@ -2128,7 -2082,7 +2136,7 @@@ pack.indexVersion: larger than 2 GB. + If you have an old Git that does not understand the version 2 `*.idx` file, -cloning or fetching over a non native protocol (e.g. "http" and "rsync") +cloning or fetching over a non native protocol (e.g. "http") that will copy both `*.pack` file and corresponding `*.idx` file from the other side may give you a repository that cannot be accessed with your older version of Git. If the `*.pack` file is smaller than 2 GB, however, @@@ -2203,8 -2157,6 +2211,8 @@@ When preserve, also pass `--preserve-me so that locally committed merge commits will not be flattened by running 'git pull'. + +When the value is `interactive`, the rebase is run in interactive mode. ++ *NOTE*: this is a possibly dangerous operation; do *not* use it unless you understand the implications (see linkgit:git-rebase[1] for details). @@@ -2463,11 -2415,6 +2471,11 @@@ remote..proxy: the proxy to use for that remote. Set to the empty string to disable proxying for that remote. +remote..proxyAuthMethod:: + For remotes that require curl (http, https and ftp), the method to use for + authenticating against the proxy in use (probably set in + `remote..proxy`). See `http.proxyAuthMethod`. + remote..fetch:: The default set of "refspec" for linkgit:git-fetch[1]. See linkgit:git-fetch[1]. @@@ -2836,16 -2783,6 +2844,16 @@@ user.name: Can be overridden by the 'GIT_AUTHOR_NAME' and 'GIT_COMMITTER_NAME' environment variables. See linkgit:git-commit-tree[1]. +user.useConfigOnly:: + Instruct Git to avoid trying to guess defaults for 'user.email' + and 'user.name', and instead retrieve the values only from the + configuration. For example, if you have multiple email addresses + and would like to use a different one for each repository, then + with this configuration option set to `true` in the global config + along with a name, Git will prompt you to set up an email before + making new commits in a newly cloned repository. + Defaults to `false`. + user.signingKey:: If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the key you want it to automatically when creating a signed tag or diff --combined http.c index 279b6f2e9a,3475040107..1d5e3bbd11 --- a/http.c +++ b/http.c @@@ -11,11 -11,6 +11,11 @@@ #include "gettext.h" #include "transport.h" +#if LIBCURL_VERSION_NUM >= 0x070a08 +long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER; +#else +long int git_curl_ipresolve; +#endif int active_requests; int http_is_verbose; size_t http_post_buffer = 16 * LARGE_PACKET_MAX; @@@ -62,37 -57,19 +62,40 @@@ static const char *ssl_key #if LIBCURL_VERSION_NUM >= 0x070908 static const char *ssl_capath; #endif + #if LIBCURL_VERSION_NUM >= 0x072c00 + static const char *ssl_pinnedkey; + #endif static const char *ssl_cainfo; static long curl_low_speed_limit = -1; 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 struct { + const char *name; + long curlauth_param; +} proxy_authmethods[] = { + { "basic", CURLAUTH_BASIC }, + { "digest", CURLAUTH_DIGEST }, + { "negotiate", CURLAUTH_GSSNEGOTIATE }, + { "ntlm", CURLAUTH_NTLM }, +#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY + { "anyauth", CURLAUTH_ANY }, +#endif + /* + * CURLAUTH_DIGEST_IE has no corresponding command-line option in + * curl(1) and is not included in CURLAUTH_ANY, so we leave it out + * here, too + */ +}; +static struct credential proxy_auth = CREDENTIAL_INIT; +static const char *curl_proxyuserpwd; static const char *curl_cookie_file; static int curl_save_cookies; struct credential http_auth = CREDENTIAL_INIT; static int http_proactive_auth; static const char *user_agent; +static int curl_empty_auth; #if LIBCURL_VERSION_NUM >= 0x071700 /* Use CURLOPT_KEYPASSWD as is */ @@@ -185,9 -162,6 +188,9 @@@ static void finish_active_slot(struct a #else slot->results->auth_avail = 0; #endif + + curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE, + &slot->results->http_connectcode); } /* Run callback if appropriate */ @@@ -285,9 -259,6 +288,9 @@@ static int http_options(const char *var if (!strcmp("http.proxy", var)) return git_config_string(&curl_http_proxy, var, value); + if (!strcmp("http.proxyauthmethod", var)) + return git_config_string(&http_proxy_authmethod, var, value); + if (!strcmp("http.cookiefile", var)) return git_config_string(&curl_cookie_file, var, value); if (!strcmp("http.savecookies", var)) { @@@ -305,22 -276,22 +308,31 @@@ if (!strcmp("http.useragent", var)) return git_config_string(&user_agent, var, value); + if (!strcmp("http.emptyauth", var)) { + curl_empty_auth = git_config_bool(var, value); + return 0; + } + + if (!strcmp("http.pinnedpubkey", var)) { + #if LIBCURL_VERSION_NUM >= 0x072c00 + return git_config_pathname(&ssl_pinnedkey, var, value); + #else + warning(_("Public key pinning not supported with cURL < 7.44.0")); + return 0; + #endif + } ++ /* Fall back on the default ones */ return git_default_config(var, value, cb); } static void init_curl_http_auth(CURL *result) { - if (!http_auth.username) + if (!http_auth.username) { + if (curl_empty_auth) + curl_easy_setopt(result, CURLOPT_USERPWD, ":"); return; + } credential_fill(&http_auth); @@@ -344,64 -315,6 +356,64 @@@ #endif } +/* *var must be free-able */ +static void var_override(const char **var, char *value) +{ + if (value) { + free((void *)*var); + *var = xstrdup(value); + } +} + +static void set_proxyauth_name_password(CURL *result) +{ +#if LIBCURL_VERSION_NUM >= 0x071301 + curl_easy_setopt(result, CURLOPT_PROXYUSERNAME, + proxy_auth.username); + curl_easy_setopt(result, CURLOPT_PROXYPASSWORD, + proxy_auth.password); +#else + struct strbuf s = STRBUF_INIT; + + strbuf_addstr_urlencode(&s, proxy_auth.username, 1); + strbuf_addch(&s, ':'); + strbuf_addstr_urlencode(&s, proxy_auth.password, 1); + curl_proxyuserpwd = strbuf_detach(&s, NULL); + curl_easy_setopt(result, CURLOPT_PROXYUSERPWD, curl_proxyuserpwd); +#endif +} + +static void init_curl_proxy_auth(CURL *result) +{ + if (proxy_auth.username) { + if (!proxy_auth.password) + credential_fill(&proxy_auth); + set_proxyauth_name_password(result); + } + + var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD")); + +#if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */ + if (http_proxy_authmethod) { + int i; + for (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) { + if (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) { + curl_easy_setopt(result, CURLOPT_PROXYAUTH, + proxy_authmethods[i].curlauth_param); + break; + } + } + if (i == ARRAY_SIZE(proxy_authmethods)) { + warning("unsupported proxy authentication method %s: using anyauth", + http_proxy_authmethod); + curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + } + } + else + curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); +#endif +} + static int has_cert_password(void) { if (ssl_cert == NULL || ssl_cert_password_required != 1) @@@ -512,6 -425,10 +524,10 @@@ static CURL *get_curl_handle(void #if LIBCURL_VERSION_NUM >= 0x070908 if (ssl_capath != NULL) curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath); + #endif + #if LIBCURL_VERSION_NUM >= 0x072c00 + if (ssl_pinnedkey != NULL) + curl_easy_setopt(result, CURLOPT_PINNEDPUBLICKEY, ssl_pinnedkey); #endif if (ssl_cainfo != NULL) curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo); @@@ -560,31 -477,6 +576,31 @@@ curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY); #endif + /* + * CURL also examines these variables as a fallback; but we need to query + * them here in order to decide whether to prompt for missing password (cf. + * init_curl_proxy_auth()). + * + * Unlike many other common environment variables, these are historically + * lowercase only. It appears that CURL did not know this and implemented + * only uppercase variants, which was later corrected to take both - with + * the exception of http_proxy, which is lowercase only also in CURL. As + * the lowercase versions are the historical quasi-standard, they take + * precedence here, as in CURL. + */ + if (!curl_http_proxy) { + if (!strcmp(http_auth.protocol, "https")) { + var_override(&curl_http_proxy, getenv("HTTPS_PROXY")); + var_override(&curl_http_proxy, getenv("https_proxy")); + } else { + var_override(&curl_http_proxy, getenv("http_proxy")); + } + if (!curl_http_proxy) { + var_override(&curl_http_proxy, getenv("ALL_PROXY")); + var_override(&curl_http_proxy, getenv("all_proxy")); + } + } + if (curl_http_proxy) { curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); #if LIBCURL_VERSION_NUM >= 0x071800 @@@ -598,18 -490,10 +614,18 @@@ curl_easy_setopt(result, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); #endif + if (strstr(curl_http_proxy, "://")) + credential_from_url(&proxy_auth, curl_http_proxy); + else { + struct strbuf url = STRBUF_INIT; + strbuf_addf(&url, "http://%s", curl_http_proxy); + credential_from_url(&proxy_auth, url.buf); + strbuf_release(&url); + } + + curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host); } -#if LIBCURL_VERSION_NUM >= 0x070a07 - curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); -#endif + init_curl_proxy_auth(result); set_curl_keepalive(result); @@@ -650,9 -534,6 +666,9 @@@ void http_init(struct remote *remote, c if (remote && remote->http_proxy) curl_http_proxy = xstrdup(remote->http_proxy); + if (remote) + var_override(&http_proxy_authmethod, remote->http_proxy_authmethod); + pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache"); no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); @@@ -751,18 -632,6 +767,18 @@@ void http_cleanup(void curl_http_proxy = NULL; } + if (proxy_auth.password) { + memset(proxy_auth.password, 0, strlen(proxy_auth.password)); + free(proxy_auth.password); + proxy_auth.password = NULL; + } + + free((void *)curl_proxyuserpwd); + curl_proxyuserpwd = NULL; + + free((void *)http_proxy_authmethod); + http_proxy_authmethod = NULL; + if (cert_auth.password != NULL) { memset(cert_auth.password, 0, strlen(cert_auth.password)); free(cert_auth.password); @@@ -838,14 -707,10 +854,14 @@@ struct active_request_slot *get_active_ curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL); + +#if LIBCURL_VERSION_NUM >= 0x070a08 + curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve); +#endif #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods); #endif - if (http_auth.password) + if (http_auth.password || curl_empty_auth) init_curl_http_auth(slot->curl); return slot; @@@ -1096,8 -961,6 +1112,8 @@@ static int handle_curl_result(struct sl if (results->curl_result == CURLE_OK) { credential_approve(&http_auth); + if (proxy_auth.password) + credential_approve(&proxy_auth); return HTTP_OK; } else if (missing_target(results)) return HTTP_MISSING_TARGET; @@@ -1112,8 -975,6 +1128,8 @@@ return HTTP_REAUTH; } } else { + if (results->http_connectcode == 407) + credential_reject(&proxy_auth); #if LIBCURL_VERSION_NUM >= 0x070c00 if (!curl_errorstr[0]) strlcpy(curl_errorstr,