From: Viktor Szakats Date: Wed, 6 Nov 2024 15:37:07 +0000 (+0100) Subject: ECH: enable support for the AWS-LC backend X-Git-Tag: curl-8_11_1~101 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1cd745a581e38e1c8f97c25b21c7ce2a6e0d4479;p=thirdparty%2Fcurl.git ECH: enable support for the AWS-LC backend Extend existing ECH support for BoringSSL to its AWS-LC fork. Also enable ECH in AWS-LC CI jobs. ``` curl 8.11.0-DEV (x86_64-pc-linux-gnu) libcurl/8.11.0-DEV AWS-LC/1.37.0 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libpsl/0.21.2 Release-Date: [unreleased] Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss Features: alt-svc AsynchDNS brotli ECH HSTS HTTPS-proxy IPv6 Largefile libz NTLM PSL SSL threadsafe UnixSockets zstd ``` Closes #15499 --- diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index d00b731ebe..9d3e589d02 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -140,12 +140,12 @@ jobs: - name: awslc install_packages: zlib1g-dev install_steps: awslc - configure: LDFLAGS="-Wl,-rpath,$HOME/awslc/lib" --with-openssl=$HOME/awslc + configure: LDFLAGS="-Wl,-rpath,$HOME/awslc/lib" --with-openssl=$HOME/awslc --enable-httpsrr --enable-ech - name: awslc install_packages: zlib1g-dev install_steps: awslc - generate: -DOPENSSL_ROOT_DIR=$HOME/awslc -DCMAKE_UNITY_BUILD=OFF + generate: -DOPENSSL_ROOT_DIR=$HOME/awslc -DUSE_HTTPSRR=ON -DUSE_ECH=ON -DCMAKE_UNITY_BUILD=OFF - name: openssl default install_steps: pytest diff --git a/CMakeLists.txt b/CMakeLists.txt index be1a2b292a..4dbd2df2ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -834,7 +834,7 @@ if(USE_ECH) if(USE_OPENSSL OR USE_WOLFSSL) # Be sure that the TLS library actually supports ECH. if(NOT DEFINED HAVE_ECH) - if(USE_OPENSSL AND HAVE_BORINGSSL) + if(USE_OPENSSL AND (HAVE_BORINGSSL OR HAVE_AWSLC)) openssl_check_symbol_exists("SSL_set1_ech_config_list" "openssl/ssl.h" HAVE_ECH "") elseif(USE_OPENSSL) openssl_check_symbol_exists("SSL_ech_set1_echconfig" "openssl/ech.h" HAVE_ECH "") @@ -843,12 +843,12 @@ if(USE_ECH) endif() endif() if(NOT HAVE_ECH) - message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/wolfSSL") + message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL") else() message(STATUS "ECH enabled.") endif() else() - message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL or wolfSSL") + message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL, AWS-LC or wolfSSL") endif() endif() diff --git a/docs/ECH.md b/docs/ECH.md index 572292dbc0..cf15314bd8 100644 --- a/docs/ECH.md +++ b/docs/ECH.md @@ -8,8 +8,8 @@ SPDX-License-Identifier: curl We have added support for ECH to curl. It can use HTTPS RRs published in the DNS if curl uses DoH, or else can accept the relevant ECHConfigList values -from the command line. This works with OpenSSL, wolfSSL or BoringSSL as the -TLS provider. +from the command line. This works with OpenSSL, wolfSSL, BoringSSL or AWS-LC as +the TLS provider. This feature is EXPERIMENTAL. DO NOT USE IN PRODUCTION. @@ -149,7 +149,7 @@ the verbose output, e.g.: ``` At that point, you could copy the base64 encoded value above and try again. -For now, this only works for the OpenSSL and BoringSSL builds. +For now, this only works for the OpenSSL and BoringSSL/AWS-LC builds. ## Default settings @@ -334,12 +334,12 @@ Then: make ``` -The BoringSSL APIs are fairly similar to those in our ECH-enabled OpenSSL -fork, so code changes are also in ``lib/vtls/openssl.c``, protected +The BoringSSL/AWS-LC APIs are fairly similar to those in our ECH-enabled +OpenSSL fork, so code changes are also in ``lib/vtls/openssl.c``, protected via ``#ifdef OPENSSL_IS_BORINGSSL`` and are mostly obvious API variations. -The BoringSSL APIs however do not support the ``--ech pn:`` command line -variant as of now. +The BoringSSL/AWS-LC APIs however do not support the ``--ech pn:`` command +line variant as of now. ## wolfSSL build @@ -401,7 +401,7 @@ Then there are some functional code changes: The lack of support for ``--ech false`` is because wolfSSL has decided to always at least GREASE if built to support ECH. In other words, GREASE is a compile time choice for wolfSSL, but a runtime choice for OpenSSL or -BoringSSL. (Both are reasonable.) +BoringSSL/AWS-LC. (Both are reasonable.) ## Additional notes @@ -474,5 +474,5 @@ to get the HTTPS RR and pass the ECHConfigList from that on the command line, if needed, or one can access the value from command line output in verbose more and then reuse that in another invocation. -Both our OpenSSL fork and BoringSSL have APIs for both controlling GREASE and -accessing and logging ``retry_configs``, it seems wolfSSL has neither. +Both our OpenSSL fork and BoringSSL/AWS-LC have APIs for both controlling GREASE +and accessing and logging ``retry_configs``, it seems wolfSSL has neither. diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index f94e941b11..0643ba046e 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -83,7 +83,7 @@ #include #ifdef USE_ECH -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) # include # endif # include "curl_base64.h" @@ -3849,15 +3849,15 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, if(data->set.tls_ech & CURLECH_GREASE) { infof(data, "ECH: will GREASE ClientHello"); -# ifdef OPENSSL_IS_BORINGSSL +# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) SSL_set_enable_ech_grease(octx->ssl, 1); # else SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE); # endif } else if(data->set.tls_ech & CURLECH_CLA_CFG) { -# ifdef OPENSSL_IS_BORINGSSL - /* have to do base64 decode here for boring */ +# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + /* have to do base64 decode here for BoringSSL */ const char *b64 = data->set.str[STRING_ECH_CONFIG]; if(!b64) { @@ -3917,7 +3917,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, size_t elen = rinfo->echconfiglist_len; infof(data, "ECH: ECHConfig from DoH HTTPS RR"); -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) if(SSL_ech_set1_echconfig(octx->ssl, ecl, elen) != 1) { infof(data, "ECH: SSL_ECH_set1_echconfig failed"); if(data->set.tls_ech & CURLECH_HARD) @@ -3925,7 +3925,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, } # else if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) { - infof(data, "ECH: SSL_set1_ech_config_list failed (boring)"); + infof(data, "ECH: SSL_set1_ech_config_list failed (BoringSSL)"); if(data->set.tls_ech & CURLECH_HARD) return CURLE_SSL_CONNECT_ERROR; } @@ -3943,7 +3943,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, Curl_resolv_unlink(data, &dns); } } -# ifdef OPENSSL_IS_BORINGSSL +# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) if(trying_ech_now && outername) { infof(data, "ECH: setting public_name not supported with BoringSSL"); return CURLE_SSL_CONNECT_ERROR; @@ -3960,7 +3960,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, return CURLE_SSL_CONNECT_ERROR; } } -# endif /* not BORING */ +# endif /* OPENSSL_IS_BORINGSSL || OPENSSL_IS_AWSLC */ if(trying_ech_now && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) { infof(data, "ECH: cannot force TLSv1.3 [ERROR]"); @@ -4071,7 +4071,7 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, CURLcode result = CURLE_OK; size_t rcl = 0; int rv = 1; -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) char *inner = NULL; unsigned char *rcs = NULL; char *outer = NULL; @@ -4086,7 +4086,7 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, /* nothing to trace if not doing ECH */ if(!ECH_ENABLED(data)) return; -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) rv = SSL_ech_get_retry_config(ssl, &rcs, &rcl); # else SSL_get0_ech_retry_configs(ssl, &rcs, &rcl); @@ -4103,23 +4103,23 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, if(!result && b64str) infof(data, "ECH: retry_configs %s", b64str); free(b64str); -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) rv = SSL_ech_get_status(ssl, &inner, &outer); infof(data, "ECH: retry_configs for %s from %s, %d %d", inner ? inner : "NULL", outer ? outer : "NULL", reason, rv); -#else +# else rv = SSL_ech_accepted(ssl); servername_type = SSL_get_servername_type(ssl); inner = SSL_get_servername(ssl, servername_type); SSL_get0_ech_name_override(ssl, &outer, &out_name_len); - /* TODO: get the inner from boring */ + /* TODO: get the inner from BoringSSL */ infof(data, "ECH: retry_configs for %s from %s, %d %d", inner ? inner : "NULL", outer ? outer : "NULL", reason, rv); -#endif +# endif } else infof(data, "ECH: no retry_configs (rv = %d)", rv); -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) OPENSSL_free((void *)rcs); # endif return; @@ -4243,7 +4243,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, #endif #ifdef USE_ECH else if((lib == ERR_LIB_SSL) && -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) (reason == SSL_R_ECH_REQUIRED)) { # else (reason == SSL_R_ECH_REJECTED)) { @@ -4309,7 +4309,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, OBJ_nid2sn(psigtype_nid)); #ifdef USE_ECH -# ifndef OPENSSL_IS_BORINGSSL +# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) if(ECH_ENABLED(data)) { char *inner = NULL, *outer = NULL; const char *status = NULL; @@ -4367,7 +4367,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, else { infof(data, "ECH: result: status is not attempted"); } -# endif /* BORING */ +# endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */ #endif /* USE_ECH */ #ifdef HAS_ALPN