@@ -874,42 +874,65 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
874874
875875static 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