]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
transfer: enhance secure check
authorStefan Eissing <stefan@eissing.org>
Tue, 17 Mar 2026 10:40:13 +0000 (11:40 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 17 Mar 2026 14:56:02 +0000 (15:56 +0100)
Introduce `Curl_xfer_is_secure(data)` that returns TRUE for transfers
that happen(ed) over a end-to-end secured connection, e.g. SSL.

Add test1586 to verify behaviour for http: transfers via a https: proxy.

Reported-by: lg_oled77c5pua on hackerone
Closes #20951

lib/http.c
lib/imap.c
lib/transfer.c
lib/transfer.h
tests/data/Makefile.am
tests/data/test1586 [new file with mode: 0644]

index 37a7aa98b7c53ff8b37348b610134d62636db5f0..6083c2c4baed734719c4973295a7055c13a35a3e 100644 (file)
@@ -3219,7 +3219,7 @@ static CURLcode http_header_a(struct Curl_easy *data,
   const char *v;
   struct connectdata *conn = data->conn;
   v = (data->asi &&
-       (Curl_conn_is_ssl(data->conn, FIRSTSOCKET) ||
+       (Curl_xfer_is_secure(data) ||
 #ifdef DEBUGBUILD
         /* allow debug builds to circumvent the HTTPS restriction */
         getenv("CURL_ALTSVC_HTTP")
@@ -3573,7 +3573,7 @@ static CURLcode http_header_s(struct Curl_easy *data,
 #ifndef CURL_DISABLE_HSTS
   /* If enabled, the header is incoming and this is over HTTPS */
   v = (data->hsts &&
-       (Curl_conn_is_ssl(conn, FIRSTSOCKET) ||
+       (Curl_xfer_is_secure(data) ||
 #ifdef DEBUGBUILD
         /* allow debug builds to circumvent the HTTPS restriction */
         getenv("CURL_HSTS_HTTP")
@@ -4906,7 +4906,7 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
       infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
     }
     else {
-      scheme = Curl_conn_is_ssl(data->conn, FIRSTSOCKET) ? "https" : "http";
+      scheme = Curl_xfer_is_secure(data) ? "https" : "http";
     }
   }
 
index 8b224d4b53bd22c6f7e83278ef2519ff3636b9c7..7bd58c0004fc48160bcf8d95953c1da18bc0272f 100644 (file)
@@ -1024,7 +1024,6 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
                                            imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct connectdata *conn = data->conn;
   const char *line = curlx_dyn_ptr(&imapc->pp.recvbuf);
 
   (void)instate;
@@ -1076,7 +1075,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
       line += wordlen;
     }
   }
-  else if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+  else if(data->set.use_ssl && !Curl_xfer_is_secure(data)) {
     /* PREAUTH is not compatible with STARTTLS. */
     if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
       /* Switch to TLS connection now */
index 82eaf10b86a0c9cb19baa532920d6c8630a2b16e..63c8fcd4dbaac3a390b80abaf77b574411d9efb2 100644 (file)
@@ -903,3 +903,25 @@ CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable)
   Curl_pgrsRecvPause(data, enable);
   return result;
 }
+
+bool Curl_xfer_is_secure(struct Curl_easy *data)
+{
+  const struct Curl_scheme *scheme = NULL;
+
+  if(data->conn) {
+    scheme = data->conn->scheme;
+    /* if we are connected, but not use SSL, the transfer is not secure.
+     * This covers an insecure http:// proxy that is not tunneling.
+     * We enforce tunneling for such cases, but better be sure here. */
+    if(Curl_conn_is_connected(data->conn, FIRSTSOCKET) &&
+       !Curl_conn_is_ssl(data->conn, FIRSTSOCKET))
+      return FALSE;
+  }
+  else if(data->info.conn_scheme) { /* was connected once */
+    scheme = Curl_get_scheme(data->info.conn_scheme);
+  }
+  else { /* never connected (yet?) */
+    DEBUGASSERT(0); /* not implemented, would need to parse URL */
+  }
+  return scheme ? (scheme->flags & PROTOPT_SSL) : FALSE;
+}
index b9d7c79bc05d28508c94391abc858a3663a8bf5e..41ec0357f681be5f4f1382ca3d7fa9a32c745acb 100644 (file)
@@ -143,4 +143,8 @@ bool Curl_xfer_recv_is_paused(struct Curl_easy *data);
 CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable);
 CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable);
 
+/* TRUE if the transfer is secure (e.g. TLS) from libcurl to the
+ * URL's host. */
+bool Curl_xfer_is_secure(struct Curl_easy *data);
+
 #endif /* HEADER_CURL_TRANSFER_H */
index 81fcbdc6ff07ea29394bf93de238c712ff4b0205..fe74ef6e2f7ccfb25360c93514c65bfbe514dfdf 100644 (file)
@@ -208,7 +208,7 @@ test1548 test1549 test1550 test1551 test1552 test1553 test1554 test1555 \
 test1556 test1557 test1558 test1559 test1560 test1561 test1562 test1563 \
 test1564 test1565 test1566 test1567 test1568 test1569 test1570 test1571 \
 test1572 test1573 test1574 test1575 test1576 test1577 test1578 test1579 \
-test1580 test1581 test1582 test1583 test1584 test1585 \
+test1580 test1581 test1582 test1583 test1584 test1585 test1586 \
 \
 test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
 test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \
diff --git a/tests/data/test1586 b/tests/data/test1586
new file mode 100644 (file)
index 0000000..2ce2471
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTPS proxy
+HSTS
+trailing-dot
+</keywords>
+</info>
+
+<reply>
+<data crlf="headers">
+HTTP/1.1 200 OK
+Content-Length: 6
+Strict-Transport-Security: max-age=604800
+
+-foo-
+</data>
+<data2 crlf="headers">
+HTTP/1.1 200 OK
+Content-Length: 6
+Strict-Transport-Security: max-age=6048000
+
+-baa-
+</data2>
+</reply>
+
+<client>
+<server>
+http
+https-proxy
+</server>
+<features>
+HSTS
+proxy
+http
+</features>
+<setenv>
+</setenv>
+
+<name>
+HSTS via https: proxy ignored for http: URLs
+</name>
+<command>
+-x https://%HOSTIP:%HTTPSPROXYPORT --proxy-insecure --hsts %LOGDIR/hsts%TESTNUMBER http://this.hsts.example./%TESTNUMBER http://another.example.com/%TESTNUMBER0002
+</command>
+</client>
+
+<verify>
+<proxy crlf="headers">
+GET http://this.hsts.example./%TESTNUMBER HTTP/1.1
+Host: this.hsts.example.
+User-Agent: curl/%VERSION
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+GET http://another.example.com/%TESTNUMBER0002 HTTP/1.1
+Host: another.example.com
+User-Agent: curl/%VERSION
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+</proxy>
+
+# The saved HSTS file must be empty as the HSTS headers were not secured
+<file name="%LOGDIR/hsts%TESTNUMBER" mode="text">
+# Your HSTS cache. https://curl.se/docs/hsts.html
+# This file was generated by libcurl! Edit at your own risk.
+</file>
+
+</verify>
+</testcase>