]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
vtls: init ssl peer only once
authorStefan Eissing <stefan@eissing.org>
Thu, 11 Jul 2024 10:44:15 +0000 (12:44 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 3 Aug 2024 17:52:21 +0000 (19:52 +0200)
- check that `struct ssl_peer` is only initialized once
- fix vtls peer init to run only once
- check in peer init that hostname is not empty, fail otherwise

Closes #14152

lib/urldata.h
lib/vtls/vtls.c

index 117167c2dc5e7a7292dea0d715093cbb595c87ff..bd97f6ae5ed900b38459583af6f97e8a21e67a2b 100644 (file)
@@ -272,7 +272,7 @@ struct ssl_peer {
   char *sni;             /* SNI version of hostname or NULL if not usable */
   ssl_peer_type type;    /* type of the peer information */
   int port;              /* port we are talking to */
-  int transport;         /* TCP or QUIC */
+  int transport;         /* one of TRNSPRT_* defines */
 };
 
 struct ssl_primary_config {
index 6d3bad63c18a670c0568b4e631c4fee66f50ec6f..32cdddf6d23e679d8f71352b508fa689f4040b99 100644 (file)
@@ -1566,69 +1566,70 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
                             int transport)
 {
   const char *ehostname, *edispname;
-  int eport;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
 
+  /* We expect a clean struct, e.g. called only ONCE */
+  DEBUGASSERT(peer);
+  DEBUGASSERT(!peer->hostname);
+  DEBUGASSERT(!peer->dispname);
+  DEBUGASSERT(!peer->sni);
   /* We need the hostname for SNI negotiation. Once handshaked, this remains
    * the SNI hostname for the TLS connection. When the connection is reused,
    * the settings in cf->conn might change. We keep a copy of the hostname we
    * use for SNI.
    */
+  peer->transport = transport;
 #ifndef CURL_DISABLE_PROXY
   if(Curl_ssl_cf_is_proxy(cf)) {
     ehostname = cf->conn->http_proxy.host.name;
     edispname = cf->conn->http_proxy.host.dispname;
-    eport = cf->conn->http_proxy.port;
+    peer->port = cf->conn->http_proxy.port;
   }
   else
 #endif
   {
     ehostname = cf->conn->host.name;
     edispname = cf->conn->host.dispname;
-    eport = cf->conn->remote_port;
+    peer->port = cf->conn->remote_port;
   }
 
-  /* change if ehostname changed */
-  DEBUGASSERT(!ehostname || ehostname[0]);
-  if(ehostname && (!peer->hostname
-                   || strcmp(ehostname, peer->hostname))) {
-    Curl_ssl_peer_cleanup(peer);
-    peer->hostname = strdup(ehostname);
-    if(!peer->hostname) {
-      Curl_ssl_peer_cleanup(peer);
-      return CURLE_OUT_OF_MEMORY;
-    }
-    if(!edispname || !strcmp(ehostname, edispname))
-      peer->dispname = peer->hostname;
-    else {
-      peer->dispname = strdup(edispname);
-      if(!peer->dispname) {
-        Curl_ssl_peer_cleanup(peer);
-        return CURLE_OUT_OF_MEMORY;
-      }
-    }
+  /* hostname MUST exist and not be empty */
+  if(!ehostname || !ehostname[0]) {
+    result = CURLE_FAILED_INIT;
+    goto out;
+  }
 
-    peer->type = get_peer_type(peer->hostname);
-    if(peer->type == CURL_SSL_PEER_DNS && peer->hostname[0]) {
-      /* not an IP address, normalize according to RCC 6066 ch. 3,
-       * max len of SNI is 2^16-1, no trailing dot */
-      size_t len = strlen(peer->hostname);
-      if(len && (peer->hostname[len-1] == '.'))
-        len--;
-      if(len < USHRT_MAX) {
-        peer->sni = calloc(1, len + 1);
-        if(!peer->sni) {
-          Curl_ssl_peer_cleanup(peer);
-          return CURLE_OUT_OF_MEMORY;
-        }
-        Curl_strntolower(peer->sni, peer->hostname, len);
-        peer->sni[len] = 0;
-      }
+  peer->hostname = strdup(ehostname);
+  if(!peer->hostname)
+    goto out;
+  if(!edispname || !strcmp(ehostname, edispname))
+    peer->dispname = peer->hostname;
+  else {
+    peer->dispname = strdup(edispname);
+    if(!peer->dispname)
+      goto out;
+  }
+  peer->type = get_peer_type(peer->hostname);
+  if(peer->type == CURL_SSL_PEER_DNS) {
+    /* not an IP address, normalize according to RCC 6066 ch. 3,
+     * max len of SNI is 2^16-1, no trailing dot */
+    size_t len = strlen(peer->hostname);
+    if(len && (peer->hostname[len-1] == '.'))
+      len--;
+    if(len < USHRT_MAX) {
+      peer->sni = calloc(1, len + 1);
+      if(!peer->sni)
+        goto out;
+      Curl_strntolower(peer->sni, peer->hostname, len);
+      peer->sni[len] = 0;
     }
-
   }
-  peer->port = eport;
-  peer->transport = transport;
-  return CURLE_OK;
+  result = CURLE_OK;
+
+out:
+  if(result)
+    Curl_ssl_peer_cleanup(peer);
+  return result;
 }
 
 static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1667,22 +1668,29 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
     return CURLE_OK;
   }
 
+  if(!cf->next) {
+    *done = FALSE;
+    return CURLE_FAILED_INIT;
+  }
+
+  if(!cf->next->connected) {
+    result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+    if(result || !*done)
+      return result;
+  }
+
   CF_DATA_SAVE(save, cf, data);
   CURL_TRC_CF(data, cf, "cf_connect()");
-  (void)connssl;
   DEBUGASSERT(data->conn);
   DEBUGASSERT(data->conn == cf->conn);
   DEBUGASSERT(connssl);
-  DEBUGASSERT(cf->conn->host.name);
-
-  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
-  if(result || !*done)
-    goto out;
 
   *done = FALSE;
-  result = Curl_ssl_peer_init(&connssl->peer, cf, TRNSPRT_TCP);
-  if(result)
-    goto out;
+  if(!connssl->peer.hostname) {
+    result = Curl_ssl_peer_init(&connssl->peer, cf, TRNSPRT_TCP);
+    if(result)
+      goto out;
+  }
 
   if(blocking) {
     result = ssl_connect(cf, data);