diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2020-12-13 13:44:56 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-13 13:44:56 +0000 |
commit | 86a1cdd38ee1cad0c578373a3888b92dbcb30106 (patch) | |
tree | 2834620f72606e8ac9330183ef985902aaa808ac | |
parent | 21fe183e1c5a9d4b39af8d76a8825c3d2ab61fe6 (diff) | |
parent | 6a10b80201fe26288b60bf7dda568408e75ffb88 (diff) | |
download | libgit2-86a1cdd38ee1cad0c578373a3888b92dbcb30106.tar.gz |
Merge pull request #5384 from ianhattendorf/fix/winhttp-client-cert
winhttp: support optional client cert
-rw-r--r-- | src/transports/winhttp.c | 75 |
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; } |