summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2020-12-13 13:44:56 +0000
committerGitHub <noreply@github.com>2020-12-13 13:44:56 +0000
commit86a1cdd38ee1cad0c578373a3888b92dbcb30106 (patch)
tree2834620f72606e8ac9330183ef985902aaa808ac
parent21fe183e1c5a9d4b39af8d76a8825c3d2ab61fe6 (diff)
parent6a10b80201fe26288b60bf7dda568408e75ffb88 (diff)
downloadlibgit2-86a1cdd38ee1cad0c578373a3888b92dbcb30106.tar.gz
Merge pull request #5384 from ianhattendorf/fix/winhttp-client-cert
winhttp: support optional client cert
-rw-r--r--src/transports/winhttp.c75
1 files changed, 49 insertions, 26 deletions
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index 2b77ec9a7..c82c788ae 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -874,42 +874,65 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
static int send_request(winhttp_stream *s, size_t len, bool chunked)
{
- int request_failed = 0, cert_valid = 1, error = 0;
- DWORD ignore_flags;
+ int request_failed = 1, error, attempts = 0;
+ DWORD ignore_flags, send_request_error;
git_error_clear();
- if ((error = do_send_request(s, len, chunked)) < 0) {
- if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
- git_error_set(GIT_ERROR_OS, "failed to send request");
- return -1;
+
+ while (request_failed && attempts++ < 3) {
+ int cert_valid = 1;
+ int client_cert_requested = 0;
+ request_failed = 0;
+ if ((error = do_send_request(s, len, chunked)) < 0) {
+ send_request_error = GetLastError();
+ request_failed = 1;
+ switch (send_request_error) {
+ case ERROR_WINHTTP_SECURE_FAILURE:
+ cert_valid = 0;
+ break;
+ case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
+ client_cert_requested = 1;
+ break;
+ default:
+ git_error_set(GIT_ERROR_OS, "failed to send request");
+ return -1;
+ }
}
- request_failed = 1;
- cert_valid = 0;
- }
+ if (!request_failed || !cert_valid) {
+ git_error_clear();
+ if ((error = certificate_check(s, cert_valid)) < 0) {
+ if (!git_error_last())
+ git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
- git_error_clear();
- if ((error = certificate_check(s, cert_valid)) < 0) {
- if (!git_error_last())
- git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
-
- return error;
- }
+ return error;
+ }
+ }
- /* if neither the request nor the certificate check returned errors, we're done */
- if (!request_failed)
- return 0;
+ /* if neither the request nor the certificate check returned errors, we're done */
+ if (!request_failed)
+ return 0;
- ignore_flags = no_check_cert_flags;
+ if (!cert_valid) {
+ ignore_flags = no_check_cert_flags;
+ if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
+ git_error_set(GIT_ERROR_OS, "failed to set security options");
+ return -1;
+ }
+ }
- if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
- git_error_set(GIT_ERROR_OS, "failed to set security options");
- return -1;
+ if (client_cert_requested) {
+ /*
+ * Client certificates are not supported, explicitly tell the server that
+ * (it's possible a client certificate was requested but is not required)
+ */
+ if (!WinHttpSetOption(s->request, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) {
+ git_error_set(GIT_ERROR_OS, "failed to set client cert context");
+ return -1;
+ }
+ }
}
- if ((error = do_send_request(s, len, chunked)) < 0)
- git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate");
-
return error;
}