Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package curl for openSUSE:Factory checked in 
at 2025-11-21 16:54:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/curl (Old)
 and      /work/SRC/openSUSE:Factory/.curl.new.2061 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "curl"

Fri Nov 21 16:54:21 2025 rev:220 rq:1318709 version:8.17.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/curl/curl.changes        2025-10-01 
18:55:32.618853662 +0200
+++ /work/SRC/openSUSE:Factory/.curl.new.2061/curl.changes      2025-11-21 
16:54:59.122079825 +0100
@@ -1,0 +2,83 @@
+Wed Nov 19 13:07:46 UTC 2025 - Pedro Monreal <[email protected]>
+
+- Fix a regression in curl 8.17.0: [bsc#1253116]
+  * Builds with no CURL_CA_PATH ignore CURLOPT_CAPATH
+  * vtls: fix CURLOPT_CAPATH use [gh#curl/curl#19401]
+  * Add upstream curl-vtls-fix-CURLOPT_CAPATH-use.patch
+
+-------------------------------------------------------------------
+Wed Nov  5 08:45:52 UTC 2025 - Pedro Monreal <[email protected]>
+
+- Update to 8.17.0:
+  * Security fixes:
+    - [bsc#1252859, CVE-2025-10966] curl: missing SFTP host
+      verification with wolfSSH
+    - [bsc#1253757, CVE-2025-11563] curl: wcurl path traversal with
+      percent-encoded slashes
+  * Changes:
+    - krb5: drop support for Kerberos FTP
+    - multi: add notifications API
+    - ssl: support Apple SecTrust configurations
+    - tool_getparam: add --knownhosts
+    - vssh: drop support for wolfSSH
+    - wcurl: import v2025.11.04
+  * Bugfixes:
+    - ares: fix leak in tracing
+    - base64: accept zero length argument to base64_encode
+    - c-ares: when resolving failed, persist error
+    - cf-socket: set FD_CLOEXEC on all sockets opened
+    - cf-socket: use the right byte order for ports in bindlocal
+    - conn: fix hostname move on connection reuse
+    - conncache: prevent integer overflow in maxconnects calculation
+    - cookie: avoid saving a cookie file if no transfer was done
+    - curl_easy_getinfo: error code on NULL arg
+    - curl_path: make sure just whitespace is illegal
+    - digest_sspi: fix two memory leaks in error branches
+    - ftp: add extra buffer length check
+    - ftp: check errors on remote ip for data connection
+    - gnutls: check conversion of peer cert chain
+    - gnutls: fix re-handshake comments
+    - gssapi: make channel binding conditional on GSS_C_CHANNEL_BOUND_FLAG
+    - gtls: check the return value of gnutls_pubkey_init()
+    - hmac: free memory properly on errors
+    - HTTP3: clarify the status for "old" OpenSSL, not current
+    - kerberos: bump minimum to 1.3 (2003-07-08), drop legacy logic
+    - krb5_gssapi: fix memory leak on error path
+    - krb5_sspi: the chlg argument is NOT optional
+    - ldap: avoid null ptr deref on failure
+    - ldap: do not base64 encode zero length string
+    - lib: SSL connection reuse
+    - libssh/libssh2: reject quote command lines with too much data
+    - libssh/sftp: fix resume corruption by avoiding O_APPEND with rresume
+    - libssh: acknowledge SSH_AGAIN in the SFTP state machine
+    - nghttp3: return NGHTTP3_ERR_CALLBACK_FAILURE from recv_header
+    - ngtcp2: close just-opened QUIC stream when submit_request fails
+    - ngtcp2: compare idle timeout in ms to avoid overflow
+    - noproxy: fix the IPV6 network mask pattern match
+    - NTLM: disable if DES support missing from OpenSSL or mbedTLS
+    - openldap: limit max incoming size
+    - openssl: call SSL_get_error() with proper error
+    - openssl: check CURL_SSLVERSION_MAX_DEFAULT properly
+    - openssl: fail if more than MAX_ALLOWED_CERT_AMOUNT certs
+    - openssl: fail the transfer if ossl_certchain() fails
+    - openssl: fix peer certificate leak in channel binding
+    - openssl: fix resource leak in provider error path
+    - openssl: free UI_METHOD on exit path
+    - openssl: only try engine/provider if a cert file/name is provided
+    - openssl: set io_need always
+    - openssl: skip session resumption when verifystatus is set
+    - pop3: fix CAPA response termination detection
+    - quic: fix min TLS version handling
+    - quic: ignore EMSGSIZE on receive
+    - schannel: properly close the certfile on error
+    - schannel_verify: fix mem-leak in Curl_verify_host
+    - socks: avoid UAF risk in error path
+    - socks: deny server basic-auth if not configured
+    - socks_gssapi: reject too long tokens
+    - socks_gssapi: remove the forced "no protection"
+    - thread: errno on thread creation
+    - ws: reject curl_ws_recv called with NULL buffer with a buflen
+  * Rebase libcurl-ocloexec.patch
+  * Remove curl-handle_user-defined_connection_headers.patch upstream
+
+-------------------------------------------------------------------

Old:
----
  curl-8.16.0.tar.xz
  curl-8.16.0.tar.xz.asc
  curl-handle_user-defined_connection_headers.patch

New:
----
  curl-8.17.0.tar.xz
  curl-8.17.0.tar.xz.asc
  curl-vtls-fix-CURLOPT_CAPATH-use.patch

----------(Old B)----------
  Old:  * Rebase libcurl-ocloexec.patch
  * Remove curl-handle_user-defined_connection_headers.patch upstream
----------(Old E)----------

----------(New B)----------
  New:  * vtls: fix CURLOPT_CAPATH use [gh#curl/curl#19401]
  * Add upstream curl-vtls-fix-CURLOPT_CAPATH-use.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ curl.spec ++++++
--- /var/tmp/diff_new_pack.w3P9Qv/_old  2025-11-21 16:55:00.342131237 +0100
+++ /var/tmp/diff_new_pack.w3P9Qv/_new  2025-11-21 16:55:00.346131406 +0100
@@ -36,7 +36,7 @@
 %endif
 
 Name:           curl%{?psuffix}
-Version:        8.16.0
+Version:        8.17.0
 Release:        0
 Summary:        A Tool for Transferring Data from URLs
 License:        curl
@@ -51,8 +51,8 @@
 Patch2:         curl-secure-getenv.patch
 # PATCH-FIX-OPENSUSE bsc#1076446 protocol redirection not supported or disabled
 Patch3:         curl-disabled-redirect-protocol-message.patch
-# PATCH-FIX-UPSTREAM bsc#1249448 http: handle user-defined connection headers
-Patch4:         curl-handle_user-defined_connection_headers.patch
+# PATCH-FIX-UPSTREAM vtls: fix CURLOPT_CAPATH use
+Patch4:         curl-vtls-fix-CURLOPT_CAPATH-use.patch
 BuildRequires:  groff
 BuildRequires:  libtool
 BuildRequires:  pkgconfig

++++++ curl-8.16.0.tar.xz -> curl-8.17.0.tar.xz ++++++
++++ 160226 lines of diff (skipped)

++++++ curl-vtls-fix-CURLOPT_CAPATH-use.patch ++++++
>From f55974c139d88582a9c503c9a35840f3b9fae458 Mon Sep 17 00:00:00 2001
From: Stefan Eissing <[email protected]>
Date: Sat, 8 Nov 2025 14:28:38 +0100
Subject: [PATCH 326/500] vtls: fix CURLOPT_CAPATH use

A regression in curl 8.17.0 led to a customer CAPATH set by the
application (or the curl command) to be ignored unless licurl was built
with a default CAPATH.

Add test cases using `--capath` on the custom pytest CA, generated with
the help of the openssl command when available.

Fixes #19401
Reported-by: Brad King
Closes #19308

diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 3b7a095c8b..3858cad983 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -310,7 +310,6 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy 
*data)
       if(result)
         return result;
     }
-    sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH];
 #endif
 #ifdef CURL_CA_BUNDLE
     if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE]) {
@@ -322,6 +321,7 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy 
*data)
   }
   sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE];
   sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
+  sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH];
   sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
   sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
   sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
@@ -358,7 +358,6 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy 
*data)
       if(result)
         return result;
     }
-    sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
 #endif
 #ifdef CURL_CA_BUNDLE
     if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE_PROXY]) {
@@ -370,6 +369,7 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy 
*data)
 #endif
   }
   sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
+  sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
   sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
   sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
   sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py
index 57e1c01404..615658f06c 100644
--- a/tests/http/test_17_ssl_use.py
+++ b/tests/http/test_17_ssl_use.py
@@ -597,3 +597,29 @@ class TestSSLUse:
         ])
         # expect NOT_IMPLEMENTED or OK
         assert r.exit_code in [0, 2], f'{r.dump_logs()}'
+
+    @pytest.mark.skipif(condition=not Env.have_openssl(), reason="needs 
openssl command")
+    def test_17_21_capath_valid(self, env: Env, httpd):
+        if env.curl_uses_lib('rustls-ffi'):
+            pytest.skip('rustls does not support CURLOPT_CAPATH')
+        proto = 'http/1.1'
+        curl = CurlClient(env=env)
+        url = f'https://{env.authority_for(env.domain1, 
proto)}/curltest/sslinfo'
+        r = curl.http_get(url=url, alpn_proto=proto, extra_args=[
+            '--capath', env.ca.hashdir
+        ])
+        assert r.exit_code == 0, f'{r.dump_logs()}'
+        assert r.json['HTTPS'] == 'on', f'{r.json}'
+
+    @pytest.mark.skipif(condition=not Env.have_openssl(), reason="needs 
openssl command")
+    def test_17_22_capath_invalid(self, env: Env, httpd):
+        # we can test all TLS backends here. the ones not supporting CAPATH
+        # need to fail as well as the ones which do, but get an invalid path.
+        proto = 'http/1.1'
+        curl = CurlClient(env=env)
+        url = f'https://{env.authority_for(env.domain1, 
proto)}/curltest/sslinfo'
+        r = curl.http_get(url=url, alpn_proto=proto, extra_args=[
+            '--capath', os.path.join(env.gen_dir, 'ca/invalid')
+        ])
+        # CURLE_PEER_FAILED_VERIFICATION or CURLE_SSL_CACERT_BADFILE
+        assert r.exit_code in [60, 77], f'{r.dump_logs()}'
diff --git a/tests/http/testenv/certs.py b/tests/http/testenv/certs.py
index e59b1ea147..c9a30aaac0 100644
--- a/tests/http/testenv/certs.py
+++ b/tests/http/testenv/certs.py
@@ -28,6 +28,8 @@ import base64
 import ipaddress
 import os
 import re
+import shutil
+import subprocess
 from datetime import timedelta, datetime, timezone
 from typing import List, Any, Optional
 
@@ -200,6 +202,10 @@ class Credentials:
     def combined_file(self) -> Optional[str]:
         return self._combined_file
 
+    @property
+    def hashdir(self) -> Optional[str]:
+        return os.path.join(self._store.path, 'hashdir')
+
     def get_first(self, name) -> Optional['Credentials']:
         creds = self._store.get_credentials_for_name(name) if self._store else 
[]
         return creds[0] if len(creds) else None
@@ -236,6 +242,16 @@ class Credentials:
             creds.issue_certs(spec.sub_specs, chain=subchain)
         return creds
 
+    def create_hashdir(self, openssl):
+        os.makedirs(self.hashdir, exist_ok=True)
+        p = subprocess.run(args=[
+            openssl, 'x509', '-hash', '-noout', '-in', self.cert_file
+        ], capture_output=True, text=True)
+        if p.returncode != 0:
+            raise Exception(f'openssl failed to compute cert hash: {p}')
+        cert_hname = f'{p.stdout.strip()}.0'
+        shutil.copy(self.cert_file, os.path.join(self.hashdir, cert_hname))
+
 
 class CertStore:
 
diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py
index dc885ab8cb..a92e4f681f 100644
--- a/tests/http/testenv/curl.py
+++ b/tests/http/testenv/curl.py
@@ -987,7 +987,8 @@ class CurlClient:
                 pass
             elif insecure:
                 args.append('--insecure')
-            elif active_options and "--cacert" in active_options:
+            elif active_options and ("--cacert" in active_options or \
+                    "--capath" in active_options):
                 pass
             elif u.hostname:
                 args.extend(["--cacert", self.env.ca.cert_file])
diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py
index ff8741530b..859b704a35 100644
--- a/tests/http/testenv/env.py
+++ b/tests/http/testenv/env.py
@@ -199,6 +199,16 @@ class EnvConfig:
             ]),
         ]
 
+        self.openssl = 'openssl'
+        p = subprocess.run(args=[self.openssl, 'version'],
+                           capture_output=True, text=True)
+        if p.returncode != 0:
+            # no openssl in path
+            self.openssl = None
+            self.openssl_version = None
+        else:
+            self.openssl_version = p.stdout.strip()
+
         self.nghttpx = self.config['nghttpx']['nghttpx']
         if len(self.nghttpx.strip()) == 0:
             self.nghttpx = None
@@ -372,6 +382,10 @@ class Env:
     def incomplete_reason() -> Optional[str]:
         return Env.CONFIG.get_incomplete_reason()
 
+    @staticmethod
+    def have_openssl() -> bool:
+        return Env.CONFIG.openssl is not None
+
     @staticmethod
     def have_nghttpx() -> bool:
         return Env.CONFIG.nghttpx is not None
@@ -548,6 +562,8 @@ class Env:
                                               store_dir=ca_dir,
                                               key_type="rsa2048")
                 self._ca.issue_certs(self.CONFIG.cert_specs)
+                if self.have_openssl():
+                    self._ca.create_hashdir(self.openssl)
 
     def setup(self):
         os.makedirs(self.gen_dir, exist_ok=True)
@@ -703,6 +719,10 @@ class Env:
     def curl(self) -> str:
         return self.CONFIG.curl
 
+    @property
+    def openssl(self) -> Optional[str]:
+        return self.CONFIG.openssl
+
     @property
     def httpd(self) -> str:
         return self.CONFIG.httpd
-- 
2.51.1



++++++ libcurl-ocloexec.patch ++++++
--- /var/tmp/diff_new_pack.w3P9Qv/_old  2025-11-21 16:55:04.098289520 +0100
+++ /var/tmp/diff_new_pack.w3P9Qv/_new  2025-11-21 16:55:04.098289520 +0100
@@ -7,49 +7,49 @@
 compile time is not enough.
 
 
-Index: curl-8.16.0/lib/file.c
+Index: curl-8.17.0/lib/file.c
 ===================================================================
---- curl-8.16.0.orig/lib/file.c
-+++ curl-8.16.0/lib/file.c
-@@ -270,7 +270,7 @@ static CURLcode file_connect(struct Curl
+--- curl-8.17.0.orig/lib/file.c
++++ curl-8.17.0/lib/file.c
+@@ -266,7 +266,7 @@ static CURLcode file_connect(struct Curl
      }
    }
    #else
--  fd = open(real_path, O_RDONLY);
-+  fd = open(real_path, O_RDONLY|O_CLOEXEC);
+-  fd = curlx_open(real_path, O_RDONLY);
++  fd = curlx_open(real_path, O_RDONLY|O_CLOEXEC);
    file->path = real_path;
    #endif
  #endif
-@@ -349,9 +349,9 @@ static CURLcode file_upload(struct Curl_
+@@ -345,9 +345,9 @@ static CURLcode file_upload(struct Curl_
  
  #if (defined(ANDROID) || defined(__ANDROID__)) && \
    (defined(__i386__) || defined(__arm__))
--  fd = open(file->path, mode, (mode_t)data->set.new_file_perms);
-+  fd = open(file->path, mode|O_CLOEXEC, (mode_t)data->set.new_file_perms);
+-  fd = curlx_open(file->path, mode, (mode_t)data->set.new_file_perms);
++  fd = curlx_open(file->path, mode|O_CLOEXEC, 
(mode_t)data->set.new_file_perms);
  #else
--  fd = open(file->path, mode, data->set.new_file_perms);
-+  fd = open(file->path, mode|O_CLOEXEC, data->set.new_file_perms);
+-  fd = curlx_open(file->path, mode, data->set.new_file_perms);
++  fd = curlx_open(file->path, mode|O_CLOEXEC, data->set.new_file_perms);
  #endif
    if(fd < 0) {
      failf(data, "cannot open %s for writing", file->path);
-Index: curl-8.16.0/lib/if2ip.c
+Index: curl-8.17.0/lib/if2ip.c
 ===================================================================
---- curl-8.16.0.orig/lib/if2ip.c
-+++ curl-8.16.0/lib/if2ip.c
+--- curl-8.17.0.orig/lib/if2ip.c
++++ curl-8.17.0/lib/if2ip.c
 @@ -208,7 +208,7 @@ if2ip_result_t Curl_if2ip(int af,
    if(len >= sizeof(req.ifr_name))
      return IF2IP_NOT_FOUND;
  
--  dummy = socket(AF_INET, SOCK_STREAM, 0);
-+  dummy = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0);
+-  dummy = CURL_SOCKET(AF_INET, SOCK_STREAM, 0);
++  dummy = CURL_SOCKET(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0);
    if(CURL_SOCKET_BAD == dummy)
      return IF2IP_NOT_FOUND;
  
-Index: curl-8.16.0/configure.ac
+Index: curl-8.17.0/configure.ac
 ===================================================================
---- curl-8.16.0.orig/configure.ac
-+++ curl-8.16.0/configure.ac
-@@ -456,6 +456,8 @@ AC_DEFINE_UNQUOTED(CURL_OS, "${host}", [
+--- curl-8.17.0.orig/configure.ac
++++ curl-8.17.0/configure.ac
+@@ -459,6 +459,8 @@ AC_DEFINE_UNQUOTED(CURL_OS, "${host}", [
  # Silence warning: ar: 'u' modifier ignored since 'D' is the default
  AC_SUBST(AR_FLAGS, [cr])
  
@@ -58,10 +58,10 @@
  dnl This defines _ALL_SOURCE for AIX
  CURL_CHECK_AIX_ALL_SOURCE
  
-Index: curl-8.16.0/lib/hostip.c
+Index: curl-8.17.0/lib/hostip.c
 ===================================================================
---- curl-8.16.0.orig/lib/hostip.c
-+++ curl-8.16.0/lib/hostip.c
+--- curl-8.17.0.orig/lib/hostip.c
++++ curl-8.17.0/lib/hostip.c
 @@ -46,6 +46,7 @@
  #include <signal.h>
  #endif
@@ -70,28 +70,27 @@
  #include "urldata.h"
  #include "sendf.h"
  #include "connect.h"
-@@ -709,7 +710,7 @@ bool Curl_ipv6works(struct Curl_easy *da
+@@ -704,7 +705,7 @@ bool Curl_ipv6works(struct Curl_easy *da
    else {
      int ipv6_works = -1;
      /* probe to see if we have a working IPv6 stack */
--    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
-+    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+-    curl_socket_t s = CURL_SOCKET(PF_INET6, SOCK_DGRAM, 0);
++    curl_socket_t s = CURL_SOCKET(PF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, 0);
      if(s == CURL_SOCKET_BAD)
        /* an IPv6 address was requested but we cannot get/use one */
        ipv6_works = 0;
-Index: curl-8.16.0/lib/cf-socket.c
+Index: curl-8.17.0/lib/cf-socket.c
 ===================================================================
---- curl-8.16.0.orig/lib/cf-socket.c
-+++ curl-8.16.0/lib/cf-socket.c
-@@ -369,7 +369,9 @@ static CURLcode socket_open(struct Curl_
+--- curl-8.17.0.orig/lib/cf-socket.c
++++ curl-8.17.0/lib/cf-socket.c
+@@ -366,7 +366,8 @@ static CURLcode socket_open(struct Curl_
    }
    else {
      /* opensocket callback not set, so simply create the socket now */
--    *sockfd = socket(addr->family, addr->socktype, addr->protocol);
-+    *sockfd = socket(addr->family,
-+                   addr->socktype|SOCK_CLOEXEC,
-+                   addr->protocol);
+-    *sockfd = CURL_SOCKET(addr->family, addr->socktype, addr->protocol);
++    *sockfd = CURL_SOCKET(addr->family, addr->socktype|SOCK_CLOEXEC,
++                          addr->protocol);
    }
  
-   if(*sockfd == CURL_SOCKET_BAD)
+   if(*sockfd == CURL_SOCKET_BAD) {
 

Reply via email to