@@ -864,42 +864,68 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
864864
865865static 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