Skip to content

Commit 86a1cdd

Browse files
authored
Merge pull request libgit2#5384 from ianhattendorf/fix/winhttp-client-cert
winhttp: support optional client cert
2 parents 21fe183 + 6a10b80 commit 86a1cdd

File tree

1 file changed

+49
-26
lines changed

1 file changed

+49
-26
lines changed

src/transports/winhttp.c

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -874,42 +874,65 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
874874

875875
static int send_request(winhttp_stream *s, size_t len, bool chunked)
876876
{
877-
int request_failed = 0, cert_valid = 1, error = 0;
878-
DWORD ignore_flags;
877+
int request_failed = 1, error, attempts = 0;
878+
DWORD ignore_flags, send_request_error;
879879

880880
git_error_clear();
881-
if ((error = do_send_request(s, len, chunked)) < 0) {
882-
if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
883-
git_error_set(GIT_ERROR_OS, "failed to send request");
884-
return -1;
881+
882+
while (request_failed && attempts++ < 3) {
883+
int cert_valid = 1;
884+
int client_cert_requested = 0;
885+
request_failed = 0;
886+
if ((error = do_send_request(s, len, chunked)) < 0) {
887+
send_request_error = GetLastError();
888+
request_failed = 1;
889+
switch (send_request_error) {
890+
case ERROR_WINHTTP_SECURE_FAILURE:
891+
cert_valid = 0;
892+
break;
893+
case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
894+
client_cert_requested = 1;
895+
break;
896+
default:
897+
git_error_set(GIT_ERROR_OS, "failed to send request");
898+
return -1;
899+
}
885900
}
886901

887-
request_failed = 1;
888-
cert_valid = 0;
889-
}
902+
if (!request_failed || !cert_valid) {
903+
git_error_clear();
904+
if ((error = certificate_check(s, cert_valid)) < 0) {
905+
if (!git_error_last())
906+
git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
890907

891-
git_error_clear();
892-
if ((error = certificate_check(s, cert_valid)) < 0) {
893-
if (!git_error_last())
894-
git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
895-
896-
return error;
897-
}
908+
return error;
909+
}
910+
}
898911

899-
/* if neither the request nor the certificate check returned errors, we're done */
900-
if (!request_failed)
901-
return 0;
912+
/* if neither the request nor the certificate check returned errors, we're done */
913+
if (!request_failed)
914+
return 0;
902915

903-
ignore_flags = no_check_cert_flags;
916+
if (!cert_valid) {
917+
ignore_flags = no_check_cert_flags;
918+
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
919+
git_error_set(GIT_ERROR_OS, "failed to set security options");
920+
return -1;
921+
}
922+
}
904923

905-
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
906-
git_error_set(GIT_ERROR_OS, "failed to set security options");
907-
return -1;
924+
if (client_cert_requested) {
925+
/*
926+
* Client certificates are not supported, explicitly tell the server that
927+
* (it's possible a client certificate was requested but is not required)
928+
*/
929+
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) {
930+
git_error_set(GIT_ERROR_OS, "failed to set client cert context");
931+
return -1;
932+
}
933+
}
908934
}
909935

910-
if ((error = do_send_request(s, len, chunked)) < 0)
911-
git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate");
912-
913936
return error;
914937
}
915938

0 commit comments

Comments
 (0)