mbedtls: fix handling of blocked sends

mbedtls is picky when a mbedtls_ssl_write) was previously blocked. It
requires to be called with the same amount of bytes again, or it will
lose bytes, e.g. reporting all was sent but they were not. Remember the
blocked length and use that when set.

Reported-by: Tamás Bálint Misius
Fixes #15801
Closes #15846
This commit is contained in:
Stefan Eissing 2024-12-28 12:19:19 +01:00 committed by Daniel Stenberg
parent c445b7426a
commit a2622cdbd5
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
3 changed files with 28 additions and 0 deletions

View file

@ -21,6 +21,7 @@ problems may have been fixed or changed somewhat since this was written.
2.7 Client cert (MTLS) issues with Schannel
2.11 Schannel TLS 1.2 handshake bug in old Windows versions
2.13 CURLOPT_CERTINFO results in CURLE_OUT_OF_MEMORY with Schannel
2.14 mbedTLS and CURLE_AGAIN handling
3. Email protocols
3.1 IMAP SEARCH ALL truncated response
@ -159,6 +160,10 @@ problems may have been fixed or changed somewhat since this was written.
https://github.com/curl/curl/issues/8741
2.14 mbedTLS and CURLE_AGAIN handling
https://github.com/curl/curl/issues/15801
3. Email protocols
3.1 IMAP SEARCH ALL truncated response

View file

@ -101,8 +101,10 @@ struct mbed_ssl_backend_data {
const char *protocols[3];
#endif
int *ciphersuites;
size_t send_blocked_len;
BIT(initialized); /* mbedtls_ssl_context is initialized */
BIT(sent_shutdown);
BIT(send_blocked);
};
/* apply threading? */
@ -1196,6 +1198,17 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
(void)data;
DEBUGASSERT(backend);
/* mbedtls is picky when a mbedtls_ssl_write) was previously blocked.
* It requires to be called with the same amount of bytes again, or it
* will lose bytes, e.g. reporting all was sent but they were not.
* Remember the blocked length and use that when set. */
if(backend->send_blocked) {
DEBUGASSERT(backend->send_blocked_len <= len);
CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> previously blocked "
"on %zu bytes", len, backend->send_blocked_len);
len = backend->send_blocked_len;
}
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
if(ret < 0) {
@ -1207,6 +1220,14 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#endif
) ? CURLE_AGAIN : CURLE_SEND_ERROR;
ret = -1;
if((*curlcode == CURLE_AGAIN) && !backend->send_blocked) {
backend->send_blocked = TRUE;
backend->send_blocked_len = len;
}
}
else {
CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d", len, ret);
backend->send_blocked = FALSE;
}
return ret;

View file

@ -212,6 +212,8 @@ class TestCaddy:
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
def test_08_08_earlydata(self, env: Env, httpd, caddy, proto):
if proto == 'h3' and not env.have_h3():
pytest.skip("h3 not supported")
count = 2
docname = 'data10k.data'
url = f'https://{env.domain1}:{caddy.port}/{docname}'