]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
h3: HTTPS-RR use in HTTP/3
authorStefan Eissing <stefan@eissing.org>
Tue, 7 Apr 2026 11:53:42 +0000 (13:53 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 9 Apr 2026 07:30:52 +0000 (09:30 +0200)
When HTTPS-RR is needed for the HTTP/3 handshake, delay the connect
until it arrives. Relevant only for TLS backends that support ECH, for
now.

Closes #21253

lib/vquic/curl_ngtcp2.c
lib/vquic/curl_quiche.c
lib/vtls/openssl.c
lib/vtls/openssl.h
lib/vtls/wolfssl.c
lib/vtls/wolfssl.h

index 7815e18357aec9f2499b1a614770cb25a77dc8cd..04c6ed1feef84d111513c7ce88f3026a8cbf16cf 100644 (file)
@@ -52,6 +52,7 @@
 #include "rand.h"
 #include "multiif.h"
 #include "cfilters.h"
+#include "cf-dns.h"
 #include "cf-socket.h"
 #include "connect.h"
 #include "progress.h"
@@ -2594,6 +2595,18 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
   return result;
 }
 
+static bool cf_ngtcp2_need_httpsrr(struct Curl_easy *data)
+{
+#ifdef USE_OPENSSL
+  return Curl_ossl_need_httpsrr(data);
+#elif defined(USE_WOLFSSL)
+  return Curl_wssl_need_httpsrr(data);
+#else
+  (void)data;
+  return FALSE;
+#endif
+}
+
 /*
  * Might be called twice for happy eyeballs.
  */
@@ -2708,8 +2721,14 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
   }
 
   *done = FALSE;
-  pktx_init(&pktx, cf, data);
 
+  if(cf_ngtcp2_need_httpsrr(data) &&
+     !Curl_conn_dns_resolved_https(data, cf->sockindex)) {
+    CURL_TRC_CF(data, cf, "need HTTPS-RR, delaying connect");
+    return CURLE_OK;
+  }
+
+  pktx_init(&pktx, cf, data);
   CF_DATA_SAVE(save, cf, data);
 
   if(!ctx->qconn) {
index e612f67ad778b83ad11c778ca7860d978a0ef3e8..8a24e1f6a5384d92269f9fb4ed30430baa7d2318 100644 (file)
@@ -32,6 +32,7 @@
 #include "uint-hash.h"
 #include "urldata.h"
 #include "cfilters.h"
+#include "cf-dns.h"
 #include "cf-socket.h"
 #include "curl_trc.h"
 #include "rand.h"
@@ -1378,6 +1379,12 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
   }
 
   *done = FALSE;
+  if(Curl_ossl_need_httpsrr(data) &&
+     !Curl_conn_dns_resolved_https(data, cf->sockindex)) {
+    CURL_TRC_CF(data, cf, "need HTTPS-RR, delaying connect");
+    return CURLE_OK;
+  }
+
   vquic_ctx_update_time(&ctx->q, Curl_pgrs_now(data));
 
   if(!ctx->qconn) {
index 1537d18d951f5d9edee46453a7721cf8b3fd6b52..9958e1030375c53a6d54ee05fce8c695c2818cef 100644 (file)
@@ -3424,7 +3424,7 @@ ossl_init_session_and_alpns(struct ossl_ctx *octx,
 }
 
 #ifdef HAVE_SSL_SET1_ECH_CONFIG_LIST
-static bool ossl_ech_need_httpsrr(struct Curl_easy *data)
+bool Curl_ossl_need_httpsrr(struct Curl_easy *data)
 {
   if(!CURLECH_ENABLED(data))
     return FALSE;
@@ -3506,7 +3506,7 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx,
       const unsigned char *ecl = rinfo->echconfiglist;
       size_t elen = rinfo->echconfiglist_len;
 
-      infof(data, "ECH: ECHConfig from DoH HTTPS RR");
+      infof(data, "ECH: ECHConfig from HTTPS RR");
       if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) {
         infof(data, "ECH: SSL_set1_ech_config_list failed");
         if(data->set.tls_ech & CURLECH_HARD)
@@ -3550,7 +3550,13 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx,
 
   return CURLE_OK;
 }
-#endif /* HAVE_SSL_SET1_ECH_CONFIG_LIST */
+#else /* HAVE_SSL_SET1_ECH_CONFIG_LIST */
+bool Curl_ossl_need_httpsrr(struct Curl_easy *data)
+{
+  (void)data;
+  return FALSE;
+}
+#endif /* else HAVE_SSL_SET1_ECH_CONFIG_LIST */
 
 static CURLcode ossl_init_ssl(struct ossl_ctx *octx,
                               struct Curl_cfilter *cf,
@@ -4943,15 +4949,11 @@ static CURLcode ossl_connect(struct Curl_cfilter *cf,
   connssl->io_need = CURL_SSL_IO_NEED_NONE;
 
   if(ssl_connect_1 == connssl->connecting_state) {
-#ifdef HAVE_SSL_SET1_ECH_CONFIG_LIST
-    /* if we do ECH and need the HTTPS-RR information for it,
-     * we delay the connect until it arrives or DNS resolve fails. */
-    if(ossl_ech_need_httpsrr(data) &&
+    if(Curl_ossl_need_httpsrr(data) &&
        !Curl_conn_dns_resolved_https(data, cf->sockindex)) {
-      CURL_TRC_CF(data, cf, "need HTTPS-RR for ECH, delaying connect");
+      CURL_TRC_CF(data, cf, "need HTTPS-RR, delaying connect");
       return CURLE_OK;
     }
-#endif
     CURL_TRC_CF(data, cf, "ossl_connect, step1");
     result = ossl_connect_step1(cf, data);
     if(result)
index 44153ba4bf06b02d50b614889e438d59ce2ac0d3..61d4a1757e252fc7e5a79758989fedf2a67ee96a 100644 (file)
@@ -147,6 +147,9 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
                             void *ssl_user_data,
                             Curl_ossl_init_session_reuse_cb *sess_reuse_cb);
 
+/* Is a resolved HTTPS-RR needed for initializing OpenSSL? */
+bool Curl_ossl_need_httpsrr(struct Curl_easy *data);
+
 #ifndef HAVE_OPENSSL3
 #define SSL_get1_peer_certificate SSL_get_peer_certificate
 #endif
index 97f5f5549d9da353714e79f3d72dc0d68a4f8a76..15c81c2874bd51b3547e13e5157f3929498d77e4 100644 (file)
@@ -1297,7 +1297,7 @@ static CURLcode wssl_init_ech(struct wssl_ctx *wctx,
       const unsigned char *ecl = rinfo->echconfiglist;
       size_t elen = rinfo->echconfiglist_len;
 
-      infof(data, "ECH: ECHConfig from DoH HTTPS RR");
+      infof(data, "ECH: ECHConfig from HTTPS RR");
       if(wolfSSL_SetEchConfigs(wctx->ssl, ecl, (word32)elen) !=
          WOLFSSL_SUCCESS) {
         infof(data, "ECH: wolfSSL_SetEchConfigs failed");
@@ -1487,17 +1487,20 @@ out:
   return result;
 }
 
-#ifdef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
-static bool wssl_ech_need_httpsrr(struct Curl_easy *data)
+bool Curl_wssl_need_httpsrr(struct Curl_easy *data)
 {
+#ifdef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
   if(!CURLECH_ENABLED(data))
     return FALSE;
   if((data->set.tls_ech & CURLECH_GREASE) ||
      (data->set.tls_ech & CURLECH_CLA_CFG))
    return FALSE;
   return TRUE;
-}
+#else
+  (void)data;
+  return FALSE;
 #endif
+}
 
 /*
  * This function loads all the client/CA certificates and CRLs. Setup the TLS
@@ -2171,7 +2174,7 @@ static CURLcode wssl_connect(struct Curl_cfilter *cf,
 #ifdef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
     /* if we do ECH and need the HTTPS-RR information for it,
      * we delay the connect until it arrives or DNS resolve fails. */
-    if(wssl_ech_need_httpsrr(data) &&
+    if(Curl_wssl_need_httpsrr(data) &&
        !Curl_conn_dns_resolved_https(data, cf->sockindex)) {
       CURL_TRC_CF(data, cf, "need HTTPS-RR for ECH, delaying connect");
       return CURLE_OK;
index b097b60b78b72ac6c77b48bce978048c674772d7..c29ca4163cb7db276ebc66f25db700908cab47d4 100644 (file)
@@ -71,6 +71,9 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
                             void *ssl_user_data,
                             Curl_wssl_init_session_reuse_cb *sess_reuse_cb);
 
+/* Is a resolved HTTPS-RR needed for initializing wolfSSL? */
+bool Curl_wssl_need_httpsrr(struct Curl_easy *data);
+
 CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
                                     struct Curl_easy *data,
                                     struct wssl_ctx *wssl);