Unverified Commit a0fca809 by Edward Thomson Committed by GitHub

Merge pull request #5814 from ianhattendorf/fix/winhttp-proxy-https

winhttp: skip certificate check if unable to send request
parents 752dbecf edffea15
...@@ -111,7 +111,8 @@ typedef struct { ...@@ -111,7 +111,8 @@ typedef struct {
DWORD post_body_len; DWORD post_body_len;
unsigned sent_request : 1, unsigned sent_request : 1,
received_response : 1, received_response : 1,
chunked : 1; chunked : 1,
status_sending_request_reached: 1;
} winhttp_stream; } winhttp_stream;
typedef struct { typedef struct {
...@@ -713,30 +714,36 @@ static void CALLBACK winhttp_status( ...@@ -713,30 +714,36 @@ static void CALLBACK winhttp_status(
DWORD status; DWORD status;
GIT_UNUSED(connection); GIT_UNUSED(connection);
GIT_UNUSED(ctx);
GIT_UNUSED(info_len); GIT_UNUSED(info_len);
if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) switch (code) {
return; case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
status = *((DWORD *)info);
status = *((DWORD *)info);
if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)) git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name"); else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)) git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired"); else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)) git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA"); else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT)) git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid"); else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED)) git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed"); else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED)) git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked"); else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR)) git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded"); else
else git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
break;
case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
((winhttp_stream *) ctx)->status_sending_request_reached = 1;
break;
}
} }
static int winhttp_connect( static int winhttp_connect(
...@@ -836,7 +843,12 @@ static int winhttp_connect( ...@@ -836,7 +843,12 @@ static int winhttp_connect(
goto on_error; goto on_error;
} }
if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) { if (WinHttpSetStatusCallback(
t->connection,
winhttp_status,
WINHTTP_CALLBACK_FLAG_SECURE_FAILURE | WINHTTP_CALLBACK_FLAG_SEND_REQUEST,
0
) == WINHTTP_INVALID_STATUS_CALLBACK) {
git_error_set(GIT_ERROR_OS, "failed to set status callback"); git_error_set(GIT_ERROR_OS, "failed to set status callback");
goto on_error; goto on_error;
} }
...@@ -869,12 +881,12 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked) ...@@ -869,12 +881,12 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
success = WinHttpSendRequest(s->request, success = WinHttpSendRequest(s->request,
WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0, WINHTTP_NO_REQUEST_DATA, 0,
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0); WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, (DWORD_PTR)s);
} else { } else {
success = WinHttpSendRequest(s->request, success = WinHttpSendRequest(s->request,
WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0, WINHTTP_NO_REQUEST_DATA, 0,
(DWORD)len, 0); (DWORD)len, (DWORD_PTR)s);
} }
if (success || GetLastError() != (DWORD)SEC_E_BUFFER_TOO_SMALL) if (success || GetLastError() != (DWORD)SEC_E_BUFFER_TOO_SMALL)
...@@ -911,7 +923,13 @@ static int send_request(winhttp_stream *s, size_t len, bool chunked) ...@@ -911,7 +923,13 @@ static int send_request(winhttp_stream *s, size_t len, bool chunked)
} }
} }
if (!request_failed || !cert_valid) { /*
* Only check the certificate if we were able to reach the sending request phase, or
* received a secure failure error. Otherwise, the server certificate won't be available
* since the request wasn't able to complete (e.g. proxy auth required)
*/
if (!cert_valid ||
(!request_failed && s->status_sending_request_reached)) {
git_error_clear(); git_error_clear();
if ((error = certificate_check(s, cert_valid)) < 0) { if ((error = certificate_check(s, cert_valid)) < 0) {
if (!git_error_last()) if (!git_error_last())
......
...@@ -869,6 +869,28 @@ void test_online_clone__proxy_credentials_in_environment(void) ...@@ -869,6 +869,28 @@ void test_online_clone__proxy_credentials_in_environment(void)
git_buf_dispose(&url); git_buf_dispose(&url);
} }
void test_online_clone__proxy_credentials_in_url_https(void)
{
git_buf url = GIT_BUF_INIT;
if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
cl_skip();
cl_git_pass(git_buf_printf(&url, "%s://%s:%s@%s/",
_remote_proxy_scheme ? _remote_proxy_scheme : "http",
_remote_proxy_user, _remote_proxy_pass, _remote_proxy_host));
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
g_options.fetch_opts.proxy_opts.url = url.ptr;
g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb;
g_options.fetch_opts.callbacks.certificate_check = ssl_cert;
called_proxy_creds = 0;
cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options));
cl_assert(called_proxy_creds == 0);
git_buf_dispose(&url);
}
void test_online_clone__proxy_auto_not_detected(void) void test_online_clone__proxy_auto_not_detected(void)
{ {
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment