Skip to content

Commit 5b2cd75

Browse files
committed
winhttp: support optional client cert
1 parent 5597517 commit 5b2cd75

File tree

1 file changed

+52
-26
lines changed

1 file changed

+52
-26
lines changed

src/transports/winhttp.c

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -864,42 +864,68 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
864864

865865
static int send_request(winhttp_stream *s, size_t len, bool chunked)
866866
{
867-
int request_failed = 0, cert_valid = 1, error = 0;
868-
DWORD ignore_flags;
867+
int request_failed = 1, cert_valid, client_cert_requested, error, attempts = 0;
868+
DWORD ignore_flags, send_request_error;
869869

870870
git_error_clear();
871-
if ((error = do_send_request(s, len, chunked)) < 0) {
872-
if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
873-
git_error_set(GIT_ERROR_OS, "failed to send request");
874-
return -1;
875-
}
876871

877-
request_failed = 1;
878-
cert_valid = 0;
879-
}
872+
while (request_failed && attempts++ < 3) {
873+
request_failed = 0;
874+
cert_valid = 1;
875+
client_cert_requested = 0;
876+
if ((error = do_send_request(s, len, chunked)) < 0) {
877+
send_request_error = GetLastError();
878+
request_failed = 1;
879+
switch (send_request_error) {
880+
case ERROR_WINHTTP_SECURE_FAILURE: {
881+
cert_valid = 0;
882+
break;
883+
}
884+
case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED: {
885+
client_cert_requested = 1;
886+
break;
887+
}
888+
default: {
889+
git_error_set(GIT_ERROR_OS, "failed to send request");
890+
return -1;
891+
}
892+
}
893+
}
880894

881-
git_error_clear();
882-
if ((error = certificate_check(s, cert_valid)) < 0) {
883-
if (!git_error_last())
884-
git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
895+
if (!request_failed || send_request_error == ERROR_WINHTTP_SECURE_FAILURE) {
896+
git_error_clear();
897+
if ((error = certificate_check(s, cert_valid)) < 0) {
898+
if (!git_error_last())
899+
git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
885900

886-
return error;
887-
}
901+
return error;
902+
}
903+
}
888904

889-
/* if neither the request nor the certificate check returned errors, we're done */
890-
if (!request_failed)
891-
return 0;
905+
/* if neither the request nor the certificate check returned errors, we're done */
906+
if (!request_failed)
907+
return 0;
892908

893-
ignore_flags = no_check_cert_flags;
909+
if (!cert_valid) {
910+
ignore_flags = no_check_cert_flags;
911+
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
912+
git_error_set(GIT_ERROR_OS, "failed to set security options");
913+
return -1;
914+
}
915+
}
894916

895-
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
896-
git_error_set(GIT_ERROR_OS, "failed to set security options");
897-
return -1;
917+
if (client_cert_requested) {
918+
/*
919+
* Client certificates are not supported, explicitly tell the server that
920+
* (it's possible a client certificate was requested but is not required)
921+
*/
922+
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) {
923+
git_error_set(GIT_ERROR_OS, "failed to set client cert context");
924+
return -1;
925+
}
926+
}
898927
}
899928

900-
if ((error = do_send_request(s, len, chunked)) < 0)
901-
git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate");
902-
903929
return error;
904930
}
905931

0 commit comments

Comments
 (0)