TLS: TLSv1.3 earlydata support for curl

Based on #14135, implement TLSv1.3 earlydata support for the curl
command line, libcurl and its implementation in GnuTLS.

If a known TLS session announces early data support, and the feature is
enabled *and* it is not a "connect-only" transfer, delay the TLS
handshake until the first request is being sent.

- Add --tls-earldata as new boolean command line option for curl.
- Add CURLSSLOPT_EARLYDATA to libcurl to enable use of the feature.
- Add CURLINFO_EARLYDATA_SENT_T to libcurl, reporting the amount of
  bytes sent and accepted/rejected by the server.

Implementation details:
- store the ALPN protocol selected at the SSL session.
- When reusing the session and enabling earlydata, use exactly
  that ALPN protocol for negoptiation with the server. When the
  sessions ALPN does not match the connections ALPN, earlydata
  will not be enabled.
- Check that the server selected the correct ALPN protocol for
  an earlydata connect. If the server does not confirm or reports
  something different, the connect fails.
- HTTP/2: delay sending the initial SETTINGS frames during connect,
  if not connect-only.

Verification:
- add test_02_32 to verify earlydata GET with nghttpx.
- add test_07_70 to verify earlydata PUT with nghttpx.
- add support in 'hx-download', 'hx-upload' clients for the feature

Assisted-by: ad-chaos on github
Closes #15211
This commit is contained in:
Stefan Eissing 2024-10-09 14:46:32 +02:00 committed by Daniel Stenberg
parent d0377f5a86
commit 962097b8dd
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
40 changed files with 899 additions and 134 deletions

View file

@ -281,6 +281,7 @@ DPAGES = \
tftp-blksize.md \
tftp-no-options.md \
time-cond.md \
tls-earlydata.md \
tls-max.md \
tls13-ciphers.md \
tlsauthtype.md \

View file

@ -0,0 +1,41 @@
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: tls-earlydata
Help: Allow use of TLSv1.3 early data (0RTT)
Protocols: TLS
Added: 8.11.0
Category: tls
Multi: boolean
See-also:
- tlsv1.3
- tls-max
Example:
- --tls-earlydata $URL
---
# `--tls-earlydata`
Enable the use of TLSv1.3 early data, also known as '0RTT' where possible.
This has security implications for the requests sent that way.
This option is used when curl is built to use GnuTLS.
If a server supports this TLSv1.3 feature, and to what extent, is announced
as part of the TLS "session" sent back to curl. Until curl has seen such
a session in a previous request, early data cannot be used.
When a new connection is initiated with a known TLSv1.3 session, and that
session announced early data support, the first request on this connection is
sent *before* the TLS handshake is complete. While the early data is also
encrypted, it is not protected against replays. An attacker can send
your early data to the server again and the server would accept it.
If your request contacts a public server and only retrieves a file, there
may be no harm in that. If the first request orders a refrigerator
for you, it is probably not a good idea to use early data for it. curl
cannot deduce what the security implications of your requests actually
are and make this decision for you.
**WARNING**: this option has security implications. See above for more
details.

View file

@ -112,6 +112,11 @@ curl_easy_header(3) instead. See CURLINFO_CONTENT_TYPE(3)
List of all known cookies. See CURLINFO_COOKIELIST(3)
## CURLINFO_EARLYDATA_SENT_T
Amount of TLS early data sent (in number of bytes) when
CURLSSLOPT_EARLYDATA is enabled.
## CURLINFO_EFFECTIVE_METHOD
Last used HTTP method. See CURLINFO_EFFECTIVE_METHOD(3)

View file

@ -0,0 +1,75 @@
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_EARLYDATA_SENT_T
Section: 3
Source: libcurl
See-also:
- curl_easy_getinfo (3)
- curl_easy_setopt (3)
Protocol:
- TLS
TLS-backend:
- GnuTLS
Added-in: 8.11.0
---
# NAME
CURLINFO_EARLYDATA_SENT_T - get the number of bytes sent as TLS early data
# SYNOPSIS
~~~c
#include <curl/curl.h>
CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_EARLYDATA_SENT_T,
curl_off_t *amount);
~~~
# DESCRIPTION
Pass a pointer to an *curl_off_t* to receive the total amount of bytes that
were sent to the server as TLSv1.3 early data. When no TLS early
data is used, this reports 0.
TLS early data is only attempted when CURLSSLOPT_EARLYDATA is set for the
transfer. In addition, it is only used by libcurl when a TLS session exists
that announces support.
The amount is **negative** when the sent data was rejected
by the server. TLS allows a server that announces support for early data to
reject any attempt to use it at its own discretion. When for example 127
bytes had been sent, but were rejected, it reports -127 as the amount "sent".
# %PROTOCOLS%
# EXAMPLE
~~~c
int main(void)
{
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
/* Perform the request */
res = curl_easy_perform(curl);
if(!res) {
curl_off_t amount;
res = curl_easy_getinfo(curl, CURLINFO_EARLYDATA_SENT_T, &amount);
if(!res) {
printf("TLS earlydata: %" CURL_FORMAT_CURL_OFF_T " bytes\n", amount);
}
}
}
}
~~~
# %AVAILABILITY%
# RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.

View file

@ -86,6 +86,15 @@ certificate that supports client authentication in the OS certificate store it
could be a privacy violation and unexpected.
(Added in 7.77.0)
## CURLSSLOPT_EARLYDATA
Tell libcurl to try sending application data as TLS1.3 early data. This option
is only supported for GnuTLS. This option works on a best effort basis,
in cases when it wasn't possible to send early data the request is resent
normally post-handshake.
This option does not work when using QUIC.
(Added in 8.11.0)
# DEFAULT
0

View file

@ -167,6 +167,7 @@ man_MANS = \
CURLOPT_DOH_SSL_VERIFYPEER.3 \
CURLOPT_DOH_SSL_VERIFYSTATUS.3 \
CURLOPT_DOH_URL.3 \
CURLINFO_EARLYDATA_SENT_T.3 \
CURLOPT_ECH.3 \
CURLOPT_EGDSOCKET.3 \
CURLOPT_ERRORBUFFER.3 \

View file

@ -435,6 +435,7 @@ CURLINFO_COOKIELIST 7.14.1
CURLINFO_DATA_IN 7.9.6
CURLINFO_DATA_OUT 7.9.6
CURLINFO_DOUBLE 7.4.1
CURLINFO_EARLYDATA_SENT_T 8.11.0
CURLINFO_EFFECTIVE_METHOD 7.72.0
CURLINFO_EFFECTIVE_URL 7.4
CURLINFO_END 7.9.6
@ -1054,6 +1055,7 @@ CURLSSLOPT_NATIVE_CA 7.71.0
CURLSSLOPT_NO_PARTIALCHAIN 7.68.0
CURLSSLOPT_NO_REVOKE 7.44.0
CURLSSLOPT_REVOKE_BEST_EFFORT 7.70.0
CURLSSLOPT_EARLYDATA 8.11.0
CURLSSLSET_NO_BACKENDS 7.56.0
CURLSSLSET_OK 7.56.0
CURLSSLSET_TOO_LATE 7.56.0

View file

@ -246,6 +246,7 @@
--tftp-blksize 7.20.0
--tftp-no-options 7.48.0
--time-cond (-z) 5.8
--tls-earlydata 8.11.0
--tls-max 7.54.0
--tls13-ciphers 7.61.0
--tlsauthtype 7.21.4