]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
windows: add build option to use the native CA store
authorViktor Szakats <commit@vsz.me>
Wed, 13 Aug 2025 22:48:00 +0000 (00:48 +0200)
committerViktor Szakats <commit@vsz.me>
Sat, 17 Jan 2026 18:18:52 +0000 (19:18 +0100)
With the same semantics as Apple SecTrust, in both libcurl and the curl
tool, when using non-Schannel TLS backends. In practice it means that
it makes TLS work without manually or implicitly configuring a CA bundle
`.crt` file, such as `curl-ca-bundle.crt`.

To enable:
- autotools: `--enable-ca-native`
- cmake: `-DCURL_CA_NATIVE=ON`
- CPPFLAGS: `-DCURL_CA_NATIVE`

When enabled:
- enables `CURLSSLOPT_NATIVE_CA` (libcurl) / `--ca-native`
  and `--proxy-ca-native` (curl tool) options by default.
- unsafe search for an on-disk CA bundle gets disabled by default.
  Equivalent to `--disable-ca-search` with autotools,
  `-DCURL_DISABLE_CA_SEARCH=ON` with CMake.
- build-time detection of CA bundle and CA path gets disabled. As with
  Apple SecTrust. This was already the default for Windows.
- native CA can be disabled at run-time with the `--no-ca-native`
  and/or `--no-proxy-ca-native` command-line options.

Rationale: This build option:
- has a repeat and active interest from packagers and users.
- helps integrating curl with Windows for those who need this.
- it also applies to macOS: #17525
  Shipped in curl 8.17.0.
- makes it trivial to use custom certs configured on the OS.
- frees applications/packagers/users from the task of securely
  distributing, and keeping up-to-date, a CA bundle.
- frees potentially many curl tool from configuring a CA bundle manually
  to access HTTPS (and other TLS) URLs. This is traditionally difficult
  on Windows because there is no concept of a universal, protected,
  non-world-writable, location on the file system to securely store
  a CA bundle.
- allows using modern features regardless of Windows version. Some of
  these features are not supported with Schannel (e.g. HTTP/3, ECH) on
  any Windows version.
- is necessary for HTTP/3 builds, where bootstrapping a CA bundle is not
  possible with Schannel, because MultiSSL is not an option, and HTTP/3
  is not supported with Schannel.

Ref: #16181 (previous attempt)
Ref: https://github.com/curl/curl/discussions/9348
Ref: https://github.com/curl/curl/issues/9350
Ref: https://github.com/curl/curl/pull/13111
Ref: https://github.com/microsoft/vcpkg/pull/46459#issuecomment-3162068701
Ref: 22652a5a4cb6a4cc1c0f4ff3ebc4f9768f6663cd #14582
Ref: eefd03c572996e5de4dec4fe295ad6f103e0eefc #18703

Closes #18279

.github/workflows/windows.yml
CMakeLists.txt
acinclude.m4
configure.ac
docs/INSTALL-CMAKE.md
docs/libcurl/curl_version_info.md
lib/curl_config-cmake.h.in
lib/version.c
lib/vtls/vtls.c

index 65f4190e91f908a8a85bb26659c34bb3ae5736f3..16abc5ae17a2c71825c7c7510cbb50b23f91f926 100644 (file)
@@ -200,7 +200,7 @@ jobs:
           - { build: 'autotools', sys: 'msys'      , env: 'x86_64'       , tflags: ''          , config: '--with-openssl', install: 'openssl-devel libssh2-devel', name: 'default R' }
           # MinGW
           - { build: 'autotools', sys: 'mingw64'   , env: 'x86_64'       , tflags: 'skiprun'   , config: '--enable-debug --with-openssl --disable-threaded-resolver --disable-curldebug --enable-static --without-zlib', install: 'mingw-w64-x86_64-openssl mingw-w64-x86_64-libssh2', name: 'default' }
-          - { build: 'autotools', sys: 'mingw64'   , env: 'x86_64'       , tflags: ''          , config: '--enable-debug --with-openssl --enable-windows-unicode --enable-ares --with-openssl-quic --enable-static --disable-shared', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-openssl mingw-w64-x86_64-nghttp3 mingw-w64-x86_64-libssh2', name: 'c-ares U' }
+          - { build: 'autotools', sys: 'mingw64'   , env: 'x86_64'       , tflags: ''          , config: '--enable-debug --with-openssl --enable-windows-unicode --enable-ares --with-openssl-quic --enable-static --disable-shared --enable-ca-native', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-openssl mingw-w64-x86_64-nghttp3 mingw-w64-x86_64-libssh2', name: 'c-ares U' }
           - { build: 'cmake'    , sys: 'mingw64'   , env: 'x86_64'       , tflags: '--min=1650', config: '-DENABLE_DEBUG=ON  -DBUILD_SHARED_LIBS=OFF -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON -DENABLE_ARES=ON', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-libssh2', type: 'Debug', name: 'schannel c-ares U' }
           # MinGW torture
           - { build: 'cmake'    , sys: 'mingw64'   , env: 'x86_64'       , tflags: '-t --shallow=13 --min=700 1 to 950'   , config: '-DENABLE_DEBUG=ON  -DBUILD_SHARED_LIBS=OFF -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON -DENABLE_ARES=ON', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-libssh2', type: 'Debug', name: 'schannel U torture 1' }
@@ -764,6 +764,7 @@ jobs:
               -DNGTCP2_INCLUDE_DIR=/ucrt64/include
               -DNGTCP2_LIBRARY=/ucrt64/lib/libngtcp2.dll.a
               -DNGTCP2_CRYPTO_OSSL_LIBRARY=/ucrt64/lib/libngtcp2_crypto_ossl.dll.a
+              -DCURL_CA_NATIVE=ON
 
           - name: 'schannel U'
             install-vcpkg: 'zlib libssh2[core,zlib]'
index c3da4790652d3b6a179329ba628f74835f51ebf8..32bc5c326fa3f72054496ba07da65454eab13868 100644 (file)
@@ -1325,6 +1325,13 @@ endif()
 #
 # CA handling
 #
+option(CURL_CA_NATIVE "Use native CA store" OFF)
+if(CURL_CA_NATIVE)
+  set(_curl_disable_ca_search_default ON)
+else()
+  set(_curl_disable_ca_search_default OFF)
+endif()
+
 if(_curl_ca_bundle_supported)
   set(_ca_opt_desc "Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
 
@@ -1347,7 +1354,7 @@ if(_curl_ca_bundle_supported)
     unset(CURL_CA_BUNDLE CACHE)
   elseif(CURL_CA_BUNDLE STREQUAL "auto")
     unset(CURL_CA_BUNDLE CACHE)
-    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32 AND NOT USE_APPLE_SECTRUST)
+    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32 AND NOT USE_APPLE_SECTRUST AND NOT CURL_CA_NATIVE)
       set(_curl_ca_bundle_autodetect TRUE)
     endif()
   else()
@@ -1361,7 +1368,7 @@ if(_curl_ca_bundle_supported)
     unset(CURL_CA_PATH CACHE)
   elseif(CURL_CA_PATH STREQUAL "auto")
     unset(CURL_CA_PATH CACHE)
-    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32 AND NOT USE_APPLE_SECTRUST)
+    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32 AND NOT USE_APPLE_SECTRUST AND NOT CURL_CA_NATIVE)
       set(_curl_ca_path_autodetect TRUE)
     endif()
   else()
@@ -1418,7 +1425,7 @@ if(_curl_ca_bundle_supported)
 endif()
 
 if(WIN32)
-  option(CURL_DISABLE_CA_SEARCH "Disable unsafe CA bundle search in PATH on Windows" OFF)
+  option(CURL_DISABLE_CA_SEARCH "Disable unsafe CA bundle search in PATH on Windows" ${_curl_disable_ca_search_default})
   option(CURL_CA_SEARCH_SAFE "Enable safe CA bundle search (within the curl tool directory) on Windows" OFF)
 endif()
 
@@ -1998,6 +2005,7 @@ curl_add_if("PSL"           USE_LIBPSL)
 curl_add_if("CAcert"        CURL_CA_EMBED_SET)
 curl_add_if("SSLS-EXPORT"   _ssl_enabled AND USE_SSLS_EXPORT)
 curl_add_if("AppleSecTrust" USE_APPLE_SECTRUST AND _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS))
+curl_add_if("NativeCA"      NOT USE_APPLE_SECTRUST AND _ssl_enabled AND CURL_CA_NATIVE)
 if(_items)
   if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
     list(SORT _items CASE INSENSITIVE)
index 775102033cdb12146244c675ac6f9a22e5028cf3..638b04adf687a155e8f7aa3b9a4609e1edf589b9 100644 (file)
@@ -1151,6 +1151,8 @@ AS_HELP_STRING([--without-ca-path], [Do not use a default CA path]),
 
   if test "$APPLE_SECTRUST_ENABLED" = "1"; then
     ca_native="Apple SecTrust"
+  elif test "$ca_native_opt" = "1"; then
+    ca_native="yes"
   else
     ca_native="no"
   fi
index 24b64f66b81eed6337cf069d106ca0000a6755e9..5135cdda546c42aa65a8893943bc9cc2057d6966 100644 (file)
@@ -2093,6 +2093,28 @@ elif test "$VALID_DEFAULT_SSL_BACKEND" = "yes"; then
   AC_DEFINE_UNQUOTED([CURL_DEFAULT_SSL_BACKEND], ["$DEFAULT_SSL_BACKEND"], [Default SSL backend])
 fi
 
+dnl ---------------------
+dnl check native CA store
+dnl ---------------------
+
+ca_native_opt=0
+AC_MSG_CHECKING([whether to use native CA store])
+AC_ARG_ENABLE(ca-native,
+AS_HELP_STRING([--enable-ca-native],[Enable native CA store])
+AS_HELP_STRING([--disable-ca-native],[Disable native CA store (default)]),
+[ case "$enableval" in
+  yes)
+    AC_MSG_RESULT([yes])
+    AC_DEFINE(CURL_CA_NATIVE, 1, [If native CA store is enabled])
+    ca_native_opt=1
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac ],
+    AC_MSG_RESULT([no])
+)
+
 dnl **********************************************************************
 dnl Check for the CA bundle
 dnl **********************************************************************
@@ -2109,21 +2131,38 @@ dnl check unsafe CA search
 dnl ----------------------
 
 if test "$curl_cv_native_windows" = "yes"; then
+  ca_search=1
   AC_MSG_CHECKING([whether to enable unsafe CA bundle search in PATH on Windows])
   AC_ARG_ENABLE(ca-search,
-AS_HELP_STRING([--enable-ca-search],[Enable unsafe CA bundle search in PATH on Windows (default)])
+AS_HELP_STRING([--enable-ca-search],[Enable unsafe CA bundle search in PATH on Windows])
 AS_HELP_STRING([--disable-ca-search],[Disable unsafe CA bundle search in PATH on Windows]),
   [ case "$enableval" in
     no)
       AC_MSG_RESULT([no])
-      AC_DEFINE(CURL_DISABLE_CA_SEARCH, 1, [If unsafe CA bundle search in PATH on Windows is disabled])
+      ca_search=0
       ;;
-    *)
+    yes)
       AC_MSG_RESULT([yes])
       ;;
+    *)
+      if test "$ca_native_opt" = "1"; then
+        AC_MSG_RESULT([no])
+        ca_search=0
+      else
+        AC_MSG_RESULT([yes])
+      fi
+      ;;
     esac ],
-      AC_MSG_RESULT([yes])
+      if test "$ca_native_opt" = "1"; then
+        AC_MSG_RESULT([no])
+        ca_search=0
+      else
+        AC_MSG_RESULT([yes])
+      fi
   )
+  if test "$ca_search" = "0"; then
+    AC_DEFINE(CURL_DISABLE_CA_SEARCH, 1, [If unsafe CA bundle search in PATH on Windows is disabled])
+  fi
 fi
 
 dnl --------------------
@@ -5286,8 +5325,12 @@ if test "$OPENSSL_ENABLED" = "1" || test -n "$SSL_ENABLED"; then
   fi
 fi
 
-if test "$APPLE_SECTRUST_ENABLED" = "1"; then
-  SUPPORT_FEATURES="$SUPPORT_FEATURES AppleSecTrust"
+if test -n "$SSL_ENABLED"; then
+  if test "$APPLE_SECTRUST_ENABLED" = "1"; then
+    SUPPORT_FEATURES="$SUPPORT_FEATURES AppleSecTrust"
+  elif test "$ca_native_opt" = "1"; then
+    SUPPORT_FEATURES="$SUPPORT_FEATURES NativeCA"
+  fi
 fi
 
 if test "$want_httpsrr" != "no"; then
index 0023adb27fabe99608762fa6dbcfaf97e10ca7a7..8ff3f30146878b6ed2a7f78c563ef182db752e71 100644 (file)
@@ -260,6 +260,8 @@ target_link_libraries(my_target PRIVATE CURL::libcurl)
 - `CURL_CA_BUNDLE`:                         Absolute path to the CA bundle. Set `none` to disable or `auto` for auto-detection. Default: `auto`
 - `CURL_CA_EMBED`:                          Absolute path to the CA bundle to embed in the curl tool. Default: (disabled)
 - `CURL_CA_FALLBACK`:                       Use built-in CA store of OpenSSL. Default: `OFF`
+- `CURL_CA_NATIVE`:                         Use native CA store. Default: `OFF`
+                                            Supported by GnuTLS, OpenSSL (including forks) on Windows, wolfSSL.
 - `CURL_CA_PATH`:                           Absolute path to a directory containing CA certificates stored individually. Set `none` to disable or `auto` for auto-detection. Default: `auto`
 - `CURL_CA_SEARCH_SAFE`:                    Enable safe CA bundle search (within the curl tool directory) on Windows. Default: `OFF`
 
@@ -283,7 +285,7 @@ target_link_libraries(my_target PRIVATE CURL::libcurl)
 - `CURL_DISABLE_BASIC_AUTH`:                Disable Basic authentication. Default: `OFF`
 - `CURL_DISABLE_BEARER_AUTH`:               Disable Bearer authentication. Default: `OFF`
 - `CURL_DISABLE_BINDLOCAL`:                 Disable local binding support. Default: `OFF`
-- `CURL_DISABLE_CA_SEARCH`:                 Disable unsafe CA bundle search in PATH on Windows. Default: `OFF`
+- `CURL_DISABLE_CA_SEARCH`:                 Disable unsafe CA bundle search in PATH on Windows. Default: `OFF` (turns to `ON`, when `CURL_CA_NATIVE=ON`)
 - `CURL_DISABLE_COOKIES`:                   Disable cookies support. Default: `OFF`
 - `CURL_DISABLE_DICT`:                      Disable DICT. Default: `OFF`
 - `CURL_DISABLE_DIGEST_AUTH`:               Disable Digest authentication. Default: `OFF`
index b9c4d4748beae53b0c6e76d0a356d8a268889454..98b9f2bc783e813e90a2058a0c6aef1a5879520f 100644 (file)
@@ -286,6 +286,13 @@ supports HTTP deflate using libz
 libcurl was built with multiple SSL backends. For details, see
 curl_global_sslset(3).
 
+## `NativeCA`
+
+*features* mask bit: non-existent
+
+libcurl was built to enable native CA store, to verify server certificates
+(Added in 8.19.0).
+
 ## `NTLM`
 
 *features* mask bit: CURL_VERSION_NTLM
index 3889e7183f4b579b90f68dda498dc95b3626b37c..dbbe7e353aafb1d9a9815f723644a5dfa54b388e 100644 (file)
@@ -34,6 +34,9 @@
 /* Default SSL backend */
 #cmakedefine CURL_DEFAULT_SSL_BACKEND "${CURL_DEFAULT_SSL_BACKEND}"
 
+/* Use native CA store */
+#cmakedefine CURL_CA_NATIVE 1
+
 /* disables alt-svc */
 #cmakedefine CURL_DISABLE_ALTSVC 1
 
index 697d9ea96d8faa46aa5b5d4f8f944c780bfd1832..83e519810b81223305763557b5223f7c14dad2e5 100644 (file)
@@ -513,9 +513,13 @@ static const struct feat features_table[] = {
 #ifdef USE_LIBPSL
   FEATURE("PSL",         NULL,                CURL_VERSION_PSL),
 #endif
+#ifdef USE_SSL
 #ifdef USE_APPLE_SECTRUST
   FEATURE("AppleSecTrust", NULL,              0),
+#elif defined(CURL_CA_NATIVE)
+  FEATURE("NativeCA",    NULL,              0),
 #endif
+#endif /* USE_SSL */
 #ifdef USE_SPNEGO
   FEATURE("SPNEGO",      NULL,                CURL_VERSION_SPNEGO),
 #endif
index 6e336b0b8d812ab16ba0e4bef27a84859b9a35d5..aef51830876c0ff045c900d3858958a08541260b 100644 (file)
@@ -295,7 +295,7 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
 #endif
 
   if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
-#ifdef USE_APPLE_SECTRUST
+#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
     if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
       sslc->native_ca_store = TRUE;
 #endif
@@ -341,7 +341,7 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
 #ifndef CURL_DISABLE_PROXY
   sslc = &data->set.proxy_ssl;
   if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
-#ifdef USE_APPLE_SECTRUST
+#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
     if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
       sslc->native_ca_store = TRUE;
 #endif