openssl: auto-pause on verify callback retry

When an application install its own OpenSSL verify callback and that
callback invokes `SSL_set_retry_verify()`, the transfer is automatically
paused and does not progress the connect attempt any further until
unpaused via `curl_easy_pause().

Added test758 to verify.

Ref: #18284
Original PR by @Natris
Bug: https://curl.se/mail/lib-2025-08/0012.html
Closes #18288
This commit is contained in:
Stefan Eissing 2025-08-14 14:12:54 +02:00 committed by Daniel Stenberg
parent c5f76b8096
commit a5f0ab7995
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
7 changed files with 599 additions and 22 deletions

View file

@ -1026,9 +1026,13 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data,
case MSTATE_CONNECTING:
case MSTATE_TUNNELING:
result = mstate_connecting_pollset(data, ps);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, ps);
if(!Curl_xfer_recv_is_paused(data)) {
result = mstate_connecting_pollset(data, ps);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, ps);
}
else
expect_sockets = FALSE;
break;
case MSTATE_PROTOCONNECT:
@ -2434,22 +2438,24 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case MSTATE_CONNECTING:
/* awaiting a completion of an asynch TCP connect */
DEBUGASSERT(data->conn);
result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
if(connected && !result) {
if(!data->conn->bits.reuse &&
Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
/* new connection, can multiplex, wake pending handles */
process_pending_handles(data->multi);
if(!Curl_xfer_recv_is_paused(data)) {
result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
if(connected && !result) {
if(!data->conn->bits.reuse &&
Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
/* new connection, can multiplex, wake pending handles */
process_pending_handles(data->multi);
}
rc = CURLM_CALL_MULTI_PERFORM;
multistate(data, MSTATE_PROTOCONNECT);
}
else if(result) {
/* failure detected */
multi_posttransfer(data);
multi_done(data, result, TRUE);
stream_error = TRUE;
break;
}
rc = CURLM_CALL_MULTI_PERFORM;
multistate(data, MSTATE_PROTOCONNECT);
}
else if(result) {
/* failure detected */
multi_posttransfer(data);
multi_done(data, result, TRUE);
stream_error = TRUE;
break;
}
break;

View file

@ -61,6 +61,7 @@
#include "../vauth/vauth.h"
#include "keylog.h"
#include "hostcheck.h"
#include "../transfer.h"
#include "../multiif.h"
#include "../curlx/strparse.h"
#include "../strdup.h"
@ -4602,7 +4603,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
#ifdef SSL_ERROR_WANT_RETRY_VERIFY
if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want retry_verify");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
Curl_xfer_pause_recv(data, TRUE);
return CURLE_AGAIN;
}
#endif