]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
quic: implement CURLINFO_TLS_SSL_PTR
authorStefan Eissing <stefan@eissing.org>
Thu, 3 Jul 2025 10:06:41 +0000 (12:06 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 6 Jul 2025 18:29:54 +0000 (20:29 +0200)
Replace the old Curl_ssl_get_internals() with a new connection filter
query to retrieve the information. Implement that filter query for TCP
and QUIC TLS filter types.

Add tests in client tls_session_reuse to use the info option and check
that pointers are returned.

Reported-by: Larry Campbell
Fixes #17801
Closes #17809

13 files changed:
lib/cfilters.c
lib/cfilters.h
lib/getinfo.c
lib/vquic/curl_ngtcp2.c
lib/vquic/curl_osslq.c
lib/vquic/curl_quiche.c
lib/vquic/curl_quiche.h
lib/vquic/vquic-tls.c
lib/vquic/vquic-tls.h
lib/vtls/vtls.c
lib/vtls/vtls.h
src/tool_operate.c
tests/client/tls_session_reuse.c

index 2c11ce56e28d1de089984a13f76652cddd9b3c92..4c0f48606f2ee16efb41ee8bc591cc945fc42c19 100644 (file)
@@ -580,6 +580,19 @@ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
   return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
 }
 
+bool Curl_conn_get_ssl_info(struct Curl_easy *data,
+                            struct connectdata *conn, int sockindex,
+                            struct curl_tlssessioninfo *info)
+{
+  if(Curl_conn_is_ssl(conn, sockindex)) {
+    struct Curl_cfilter *cf = conn->cfilter[sockindex];
+    CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO,
+                               NULL, (void *)info) : CURLE_UNKNOWN_OPTION;
+    return !result;
+  }
+  return FALSE;
+}
+
 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
 {
   struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
index 3c49e15005909bbc3fb473d4a5f738395ccfe99d..1487ff615f92b62d5dbd818b8cd7ea5f6304cbb0 100644 (file)
@@ -32,6 +32,7 @@ struct Curl_easy;
 struct Curl_dns_entry;
 struct connectdata;
 struct ip_quadruple;
+struct curl_tlssessioninfo;
 
 /* Callback to destroy resources held by this filter instance.
  * Implementations MUST NOT chain calls to cf->next.
@@ -151,6 +152,12 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
  * - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the
  *                   ip quadruple
  * - CF_QUERY_HOST_PORT: the remote hostname and port a filter talks to
+ * - CF_QUERY_SSL_INFO: fill out the passed curl_tlssessioninfo with the
+ *                      internal from the SSL secured connection when
+ *                      available.
+ * - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX
+ *                      when available, or the same internal pointer
+ *                      when the TLS stack does not differentiate.
  */
 /*      query                             res1       res2     */
 #define CF_QUERY_MAX_CONCURRENT     1  /* number     -        */
@@ -166,6 +173,8 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
  * to NULL when not connected. */
 #define CF_QUERY_REMOTE_ADDR       10  /* -          `Curl_sockaddr_ex *` */
 #define CF_QUERY_HOST_PORT         11  /* port       const char * */
+#define CF_QUERY_SSL_INFO          12  /* -    struct curl_tlssessioninfo * */
+#define CF_QUERY_SSL_CTX_INFO      13  /* -    struct curl_tlssessioninfo * */
 
 /**
  * Query the cfilter for properties. Filters ignorant of a query will
@@ -380,6 +389,15 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
  */
 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
 
+/*
+ * Fill `info` with information about the TLS instance securing
+ * the connection when available, otherwise e.g. when
+ * Curl_conn_is_ssl() is FALSE, return FALSE.
+ */
+bool Curl_conn_get_ssl_info(struct Curl_easy *data,
+                            struct connectdata *conn, int sockindex,
+                            struct curl_tlssessioninfo *info);
+
 /**
  * Connection provides multiplexing of easy handles at `socketindex`.
  */
index 388646bf7514b18d43be92f0e8849759a2521766..7ff78d2d6d7a6fd79e503425370fad7b24317a02 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "urldata.h"
 #include "getinfo.h"
+#include "cfilters.h"
 #include "vtls/vtls.h"
 #include "connect.h" /* Curl_getconnectinfo() */
 #include "progress.h"
@@ -579,19 +580,14 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
                                           param_slistp;
       struct curl_tlssessioninfo *tsi = &data->tsi;
-#ifdef USE_SSL
-      struct connectdata *conn = data->conn;
-#endif
 
+      /* we are exposing a pointer to internal memory with unknown
+       * lifetime here. */
       *tsip = tsi;
-      tsi->backend = Curl_ssl_backend();
-      tsi->internals = NULL;
-
-#ifdef USE_SSL
-      if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
-        tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
+      if(!Curl_conn_get_ssl_info(data, data->conn, FIRSTSOCKET, tsi)) {
+        tsi->backend = Curl_ssl_backend();
+        tsi->internals = NULL;
       }
-#endif
     }
     break;
   default:
index 50dd87376745e268fb7c8b12474061dc26c2180c..5d40fd5ccfd551c01c8d2125ba55b520ce69ccdf 100644 (file)
@@ -2655,6 +2655,14 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
   case CF_QUERY_HTTP_VERSION:
     *pres1 = 30;
     return CURLE_OK;
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+                                   (query == CF_QUERY_SSL_INFO), info))
+      return CURLE_OK;
+    break;
+  }
   default:
     break;
   }
index 8f01ad15e6122abff28925a5a6908340ae2ecc5a..d435d7f512481b00a661781fefc1cafd7df0792b 100644 (file)
@@ -2351,6 +2351,14 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
   case CF_QUERY_HTTP_VERSION:
     *pres1 = 30;
     return CURLE_OK;
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+                                   (query == CF_QUERY_SSL_INFO), info))
+      return CURLE_OK;
+    break;
+  }
   default:
     break;
   }
index b52bf9a35aa465edfe5370b94fbc96123b1cdd11..6d79842fba0ed8d2d26c2a5fd3fa3cfb6cbf60c0 100644 (file)
@@ -1553,6 +1553,14 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
   case CF_QUERY_HTTP_VERSION:
     *pres1 = 30;
     return CURLE_OK;
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+                                   (query == CF_QUERY_SSL_INFO), info))
+      return CURLE_OK;
+    break;
+  }
   default:
     break;
   }
@@ -1658,20 +1666,4 @@ out:
   return result;
 }
 
-bool Curl_conn_is_quiche(const struct Curl_easy *data,
-                         const struct connectdata *conn,
-                         int sockindex)
-{
-  struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
-
-  (void)data;
-  for(; cf; cf = cf->next) {
-    if(cf->cft == &Curl_cft_http3)
-      return TRUE;
-    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
-      return FALSE;
-  }
-  return FALSE;
-}
-
 #endif
index 9832687bdc19b3f38b54d3cce378fa5a9cc0f8ca..b2c767216fb483dc87f6391e5ff40bd151e4df1c 100644 (file)
@@ -41,10 +41,6 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
                                struct connectdata *conn,
                                const struct Curl_addrinfo *ai);
 
-bool Curl_conn_is_quiche(const struct Curl_easy *data,
-                         const struct connectdata *conn,
-                         int sockindex);
-
 #endif
 
 #endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */
index 2a5be138fc68c9f5ac0b4535a5c8815d29eb938e..e6160b39026cbdad76d24c34eec680f66ead9324 100644 (file)
@@ -197,4 +197,28 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
 }
 
 
+bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx,
+                                 bool give_ssl_ctx,
+                                 struct curl_tlssessioninfo *info)
+{
+#ifdef USE_OPENSSL
+  info->backend = CURLSSLBACKEND_OPENSSL;
+  info->internals = give_ssl_ctx ?
+                    (void *)ctx->ossl.ssl_ctx : (void *)ctx->ossl.ssl;
+  return TRUE;
+#elif defined(USE_GNUTLS)
+  (void)give_ssl_ctx; /* gnutls always returns its session */
+  info->backend = CURLSSLBACKEND_OPENSSL;
+  info->internals = ctx->gtls.session;
+  return TRUE;
+#elif defined(USE_WOLFSSL)
+  info->backend = CURLSSLBACKEND_WOLFSSL;
+  info->internals = give_ssl_ctx ?
+                    (void *)ctx->wssl.ssl_ctx : (void *)ctx->wssl.ssl;
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
 #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
index bf29eecc91691e49b0c773c66c32c1ad6c25fd81..49b923a4e45a9168c92551e42b5837d6391f06f3 100644 (file)
@@ -37,6 +37,7 @@
 
 struct ssl_peer;
 struct Curl_ssl_session;
+struct curl_tlssessioninfo;
 
 struct curl_tls_ctx {
 #ifdef USE_OPENSSL
@@ -106,6 +107,10 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
                                     struct Curl_easy *data,
                                     struct ssl_peer *peer);
 
+bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx,
+                                 bool give_ssl_ctx,
+                                 struct curl_tlssessioninfo *info);
+
 #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
 
 #endif /* HEADER_CURL_VQUIC_TLS_H */
index f729ebf7398e86c8ffffa8713272205135ef2529..65ba9df0c4f8fe47b1d21dcaa2094c10028a733e 100644 (file)
@@ -1558,6 +1558,18 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
       *when = connssl->handshake_done;
     return CURLE_OK;
   }
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    struct cf_call_data save;
+    CF_DATA_SAVE(save, cf, data);
+    info->backend = Curl_ssl_backend();
+    info->internals = connssl->ssl_impl->get_internals(
+      cf->ctx, (query == CF_QUERY_SSL_INFO) ?
+      CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION);
+    CF_DATA_RESTORE(cf, save);
+    return CURLE_OK;
+  }
   default:
     break;
   }
@@ -1727,40 +1739,6 @@ bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
   return (Curl_ssl->supports & ssl_option);
 }
 
-static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
-{
-  for(; cf; cf = cf->next) {
-    if(cf->cft == &Curl_cft_ssl)
-      return cf;
-#ifndef CURL_DISABLE_PROXY
-    if(cf->cft == &Curl_cft_ssl_proxy)
-      return cf;
-#endif
-  }
-  return NULL;
-}
-
-
-void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
-                             CURLINFO info, int n)
-{
-  void *result = NULL;
-  (void)n;
-  if(data->conn) {
-    struct Curl_cfilter *cf;
-    /* get first SSL filter in chain, if any is present */
-    cf = get_ssl_filter(data->conn->cfilter[sockindex]);
-    if(cf) {
-      struct ssl_connect_data *connssl = cf->ctx;
-      struct cf_call_data save;
-      CF_DATA_SAVE(save, cf, data);
-      result = connssl->ssl_impl->get_internals(cf->ctx, info);
-      CF_DATA_RESTORE(cf, save);
-    }
-  }
-  return result;
-}
-
 static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
                                        struct Curl_easy *data,
                                        bool send_shutdown, bool *done)
index d37a22a78ca790bf26105c9dd0bb64b54e983f31..a6cf4e0e740c7ae68ec8383420c0c98f0d05c6f5 100644 (file)
@@ -233,16 +233,6 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
  */
 bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option);
 
-/**
- * Get the internal ssl instance (like OpenSSL's SSL*) from the filter
- * chain at `sockindex` of type specified by `info`.
- * For `n` == 0, the first active (top down) instance is returned.
- * 1 gives the second active, etc.
- * NULL is returned when no active SSL filter is present.
- */
-void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
-                             CURLINFO info, int n);
-
 /**
  * Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
  */
@@ -272,7 +262,6 @@ extern struct Curl_cftype Curl_cft_ssl_proxy;
 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt
 #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
 #define Curl_ssl_cert_status_request() FALSE
-#define Curl_ssl_get_internals(a,b,c,d) NULL
 #define Curl_ssl_supports(a,b) FALSE
 #define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
 #define Curl_ssl_cfilter_remove(a,b,c) CURLE_OK
index bd25e99c40e3dff3d7972432873118bbfc816bba..e37ce97be53c8b1cfb4dd0a463fd0b1615d619f6 100644 (file)
@@ -1494,6 +1494,8 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global,
     (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
                            global->parallel_connect ? 0L : 1L);
     (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per);
+    /* curl does not use signals, switching this on saves some system calls */
+    (void)curl_easy_setopt(per->curl, CURLOPT_NOSIGNAL, 1L);
     (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
     (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
     (void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L);
index 12bac86747a68f9686485f25f5ef7acebda58594..4e69383f601a84dd35d6231c428c5d17e8ee7466 100644 (file)
  ***************************************************************************/
 #include "first.h"
 
+static int tse_found_tls_session = FALSE;
+
 static size_t write_tse_cb(char *ptr, size_t size, size_t nmemb, void *opaque)
 {
+  CURL *easy = opaque;
   (void)ptr;
-  (void)opaque;
+  if(!tse_found_tls_session) {
+    struct curl_tlssessioninfo *tlssession;
+    CURLcode rc;
+
+    rc = curl_easy_getinfo(easy, CURLINFO_TLS_SSL_PTR, &tlssession);
+    if(rc) {
+      curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) "
+                    "failed: %s\n", curl_easy_strerror(rc));
+      return rc;
+    }
+    if(tlssession->backend == CURLSSLBACKEND_NONE) {
+      curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) "
+                    "gave no backend\n");
+      return CURLE_FAILED_INIT;
+    }
+    if(!tlssession->internals) {
+      curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) "
+                    "missing\n");
+      return CURLE_FAILED_INIT;
+    }
+    tse_found_tls_session = TRUE;
+  }
   return size * nmemb;
 }
 
-static int add_transfer(CURLM *multi, CURLSH *share,
-                        struct curl_slist *resolve,
-                        const char *url, long http_version)
+static CURL *tse_add_transfer(CURLM *multi, CURLSH *share,
+                              struct curl_slist *resolve,
+                              const char *url, long http_version)
 {
   CURL *easy;
   CURLMcode mc;
@@ -40,7 +64,7 @@ static int add_transfer(CURLM *multi, CURLSH *share,
   easy = curl_easy_init();
   if(!easy) {
     curl_mfprintf(stderr, "curl_easy_init failed\n");
-    return 1;
+    return NULL;
   }
   curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
   curl_easy_setopt(easy, CURLOPT_DEBUGFUNCTION, debug_cb);
@@ -51,7 +75,7 @@ static int add_transfer(CURLM *multi, CURLSH *share,
   curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L);
   curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, http_version);
   curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_tse_cb);
-  curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL);
+  curl_easy_setopt(easy, CURLOPT_WRITEDATA, easy);
   curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L);
   curl_easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L);
   if(resolve)
@@ -63,9 +87,9 @@ static int add_transfer(CURLM *multi, CURLSH *share,
     curl_mfprintf(stderr, "curl_multi_add_handle: %s\n",
                   curl_multi_strerror(mc));
     curl_easy_cleanup(easy);
-    return 1;
+    return NULL;
   }
-  return 0;
+  return easy;
 }
 
 static int test_tls_session_reuse(int argc, char *argv[])
@@ -132,7 +156,7 @@ static int test_tls_session_reuse(int argc, char *argv[])
   curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
 
 
-  if(add_transfer(multi, share, resolve, url, http_version))
+  if(!tse_add_transfer(multi, share, resolve, url, http_version))
     goto cleanup;
   ++ongoing;
   add_more = 6;
@@ -159,7 +183,7 @@ static int test_tls_session_reuse(int argc, char *argv[])
     }
     else {
       while(add_more) {
-        if(add_transfer(multi, share, resolve, url, http_version))
+        if(!tse_add_transfer(multi, share, resolve, url, http_version))
           goto cleanup;
         ++ongoing;
         --add_more;
@@ -203,6 +227,12 @@ static int test_tls_session_reuse(int argc, char *argv[])
 
   } while(ongoing || add_more);
 
+  if(!tse_found_tls_session) {
+    curl_mfprintf(stderr, "CURLINFO_TLS_SSL_PTR not found during run\n");
+    exitcode = CURLE_FAILED_INIT;
+    goto cleanup;
+  }
+
   curl_mfprintf(stderr, "exiting\n");
   exitcode = 0;