Kaynağa Gözat

file(DOWNLOAD|UPLOAD): Add TLS_VERSION option for https connections

Add an option to specify the minimum allowed TLS version for https
connections.

Issue: #25701
Brad King 1 yıl önce
ebeveyn
işleme
8e6776b9f3
27 değiştirilmiş dosya ile 122 ekleme ve 0 silme
  1. 1 0
      .gitlab/ci/configure_debian12_aarch64_ninja.cmake
  2. 1 0
      .gitlab/ci/configure_debian12_ninja_common.cmake
  3. 1 0
      .gitlab/ci/configure_fedora39_makefiles.cmake
  4. 1 0
      .gitlab/ci/configure_fedora39_ninja.cmake
  5. 1 0
      .gitlab/ci/configure_macos_arm64_ninja.cmake
  6. 1 0
      .gitlab/ci/configure_macos_x86_64_makefiles.cmake
  7. 1 0
      .gitlab/ci/configure_macos_x86_64_ninja.cmake
  8. 1 0
      .gitlab/ci/configure_windows_arm64_vs2022_ninja.cmake
  9. 1 0
      .gitlab/ci/configure_windows_vs2022_x64_ninja.cmake
  10. 5 0
      Help/command/file.rst
  11. 6 0
      Help/release/dev/curl-tls-version.rst
  12. 23 0
      Source/cmCurl.cxx
  13. 3 0
      Source/cmCurl.h
  14. 44 0
      Source/cmFileCommand.cxx
  15. 1 0
      Tests/RunCMake/CMakeLists.txt
  16. 6 0
      Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake
  17. 1 0
      Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-bad-result.txt
  18. 4 0
      Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-bad-stderr.txt
  19. 1 0
      Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-bad.cmake
  20. 6 0
      Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-good.cmake
  21. 1 0
      Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-missing-result.txt
  22. 4 0
      Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-missing-stderr.txt
  23. 1 0
      Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-missing.cmake
  24. 1 0
      Tests/RunCMake/file/RunCMakeTest.cmake
  25. 1 0
      Tests/RunCMake/file/UPLOAD-TLS_VERSION-missing-result.txt
  26. 4 0
      Tests/RunCMake/file/UPLOAD-TLS_VERSION-missing-stderr.txt
  27. 1 0
      Tests/RunCMake/file/UPLOAD-TLS_VERSION-missing.cmake

+ 1 - 0
.gitlab/ci/configure_debian12_aarch64_ninja.cmake

@@ -92,6 +92,7 @@ set(CMake_TEST_IPO_WORKS_Fortran "ON" CACHE BOOL "")
 set(CMake_TEST_JQ "/usr/bin/jq" CACHE PATH "")
 set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
 set(CMake_TEST_UseSWIG "ON" CACHE BOOL "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 1 - 0
.gitlab/ci/configure_debian12_ninja_common.cmake

@@ -97,6 +97,7 @@ set(CMake_TEST_IPO_WORKS_Fortran "ON" CACHE BOOL "")
 set(CMake_TEST_JQ "/usr/bin/jq" CACHE PATH "")
 set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
 
 if (NOT "$ENV{SWIFTC}" STREQUAL "")
   set(CMAKE_Swift_COMPILER "$ENV{SWIFTC}" CACHE FILEPATH "")

+ 1 - 0
.gitlab/ci/configure_fedora39_makefiles.cmake

@@ -98,6 +98,7 @@ if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
 endif()
 set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
 set(CMake_TEST_UseSWIG "ON" CACHE BOOL "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 1 - 0
.gitlab/ci/configure_fedora39_ninja.cmake

@@ -3,6 +3,7 @@ if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
 
 # "Release" flags without "-DNDEBUG" so we get assertions.
 set(CMAKE_C_FLAGS_RELEASE "-O3" CACHE STRING "")

+ 1 - 0
.gitlab/ci/configure_macos_arm64_ninja.cmake

@@ -4,5 +4,6 @@ set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
 set(CMake_TEST_GUI "ON" CACHE BOOL "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")

+ 1 - 0
.gitlab/ci/configure_macos_x86_64_makefiles.cmake

@@ -7,6 +7,7 @@ if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")

+ 1 - 0
.gitlab/ci/configure_macos_x86_64_ninja.cmake

@@ -7,6 +7,7 @@ if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")

+ 1 - 0
.gitlab/ci/configure_windows_arm64_vs2022_ninja.cmake

@@ -1,6 +1,7 @@
 # Qt host tools are not yet available natively on windows-arm64.
 set(CMake_TEST_GUI "OFF" CACHE BOOL "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.2" CACHE STRING "")
 set(BUILD_QtDialog "OFF" CACHE BOOL "")
 set(CMAKE_PREFIX_PATH "" CACHE STRING "")
 

+ 1 - 0
.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake

@@ -4,6 +4,7 @@ if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_Swift "ON" CACHE STRING "")
 endif()
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(CMake_TEST_TLS_VERSION "1.2" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_msvc_cxx_modules_common.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_vs_common_ninja.cmake")

+ 5 - 0
Help/command/file.rst

@@ -1097,6 +1097,11 @@ Transfer
       is not specified, the value of the :variable:`CMAKE_NETRC_FILE` variable
       will be used instead.
 
+    ``TLS_VERSION <min>``
+      .. versionadded:: 3.30
+
+      Specify minimum TLS version for ``https://`` URLs.
+
     ``TLS_VERIFY <ON|OFF>``
       Specify whether to verify the server certificate for ``https://`` URLs.
       The default is to *not* verify. If this option is not specified, the

+ 6 - 0
Help/release/dev/curl-tls-version.rst

@@ -0,0 +1,6 @@
+curl-tls-version
+----------------
+
+* The :command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands
+  gained a ``TLS_VERSION <min>`` option to specify the minimum TLS
+  version for connections to ``https://`` URLs.

+ 23 - 0
Source/cmCurl.cxx

@@ -2,6 +2,9 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCurl.h"
 
+#include <cm/string_view>
+#include <cmext/string_view>
+
 #if !defined(CMAKE_USE_SYSTEM_CURL) && !defined(_WIN32) &&                    \
   !defined(__APPLE__) && !defined(CURL_CA_BUNDLE) && !defined(CURL_CA_PATH)
 #  define CMAKE_FIND_CAFILE
@@ -31,6 +34,26 @@
     }                                                                         \
   } while (false)
 
+cm::optional<int> cmCurlParseTLSVersion(std::string const& tls_version)
+{
+  cm::optional<int> v;
+  if (tls_version == "1.0"_s) {
+    v = CURL_SSLVERSION_TLSv1_0;
+  } else if (tls_version == "1.1"_s) {
+    v = CURL_SSLVERSION_TLSv1_1;
+  } else if (tls_version == "1.2"_s) {
+    v = CURL_SSLVERSION_TLSv1_2;
+  } else if (tls_version == "1.3"_s) {
+    // curl version 7.52.0 introduced TLS 1.3 support
+#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM >= 0x073400
+    v = CURL_SSLVERSION_TLSv1_3;
+#else
+    v = CURL_SSLVERSION_LAST;
+#endif
+  }
+  return v;
+}
+
 std::string cmCurlSetCAInfo(::CURL* curl, const std::string& cafile)
 {
   std::string e;

+ 3 - 0
Source/cmCurl.h

@@ -6,8 +6,11 @@
 
 #include <string>
 
+#include <cm/optional>
+
 #include <cm3p/curl/curl.h>
 
+cm::optional<int> cmCurlParseTLSVersion(std::string const& tls_version);
 std::string cmCurlSetCAInfo(::CURL* curl, const std::string& cafile = {});
 std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level,
                                  const std::string& netrc_file);

+ 44 - 0
Source/cmFileCommand.cxx

@@ -1859,6 +1859,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
   long inactivity_timeout = 0;
   std::string logVar;
   std::string statusVar;
+  cm::optional<std::string> tls_version;
   bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY");
   cmValue cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
   std::string netrc_level =
@@ -1905,6 +1906,14 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
         return false;
       }
       statusVar = *i;
+    } else if (*i == "TLS_VERSION") {
+      ++i;
+      if (i != args.end()) {
+        tls_version = *i;
+      } else {
+        status.SetError("DOWNLOAD missing value for TLS_VERSION.");
+        return false;
+      }
     } else if (*i == "TLS_VERIFY") {
       ++i;
       if (i != args.end()) {
@@ -2092,6 +2101,19 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
                            cmFileCommandCurlDebugCallback);
   check_curl_result(res, "DOWNLOAD cannot set debug function: ");
 
+  if (tls_version) {
+    if (cm::optional<int> v = cmCurlParseTLSVersion(*tls_version)) {
+      res = ::curl_easy_setopt(curl, CURLOPT_SSLVERSION, *v);
+      check_curl_result(
+        res,
+        cmStrCat("DOWNLOAD cannot set TLS/SSL version ", *tls_version, ": "));
+    } else {
+      status.SetError(
+        cmStrCat("DOWNLOAD given unknown TLS/SSL version ", *tls_version));
+      return false;
+    }
+  }
+
   // check to see if TLS verification is requested
   if (tls_verify) {
     res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
@@ -2281,6 +2303,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
   std::string logVar;
   std::string statusVar;
   bool showProgress = false;
+  cm::optional<std::string> tls_version;
   bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY");
   cmValue cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
   std::string userpwd;
@@ -2324,6 +2347,14 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
       statusVar = *i;
     } else if (*i == "SHOW_PROGRESS") {
       showProgress = true;
+    } else if (*i == "TLS_VERSION") {
+      ++i;
+      if (i != args.end()) {
+        tls_version = *i;
+      } else {
+        status.SetError("UPLOAD missing value for TLS_VERSION.");
+        return false;
+      }
     } else if (*i == "TLS_VERIFY") {
       ++i;
       if (i != args.end()) {
@@ -2423,6 +2454,19 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
                            cmFileCommandCurlDebugCallback);
   check_curl_result(res, "UPLOAD cannot set debug function: ");
 
+  if (tls_version) {
+    if (cm::optional<int> v = cmCurlParseTLSVersion(*tls_version)) {
+      res = ::curl_easy_setopt(curl, CURLOPT_SSLVERSION, *v);
+      check_curl_result(
+        res,
+        cmStrCat("UPLOAD cannot set TLS/SSL version ", *tls_version, ": "));
+    } else {
+      status.SetError(
+        cmStrCat("UPLOAD given unknown TLS/SSL version ", *tls_version));
+      return false;
+    }
+  }
+
   // check to see if TLS verification is requested
   if (tls_verify) {
     res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -553,6 +553,7 @@ add_RunCMake_test(file-CHMOD -DMSYS=${MSYS})
 foreach(var
     CMake_TEST_NO_NETWORK
     CMake_TEST_TLS_VERIFY_URL
+    CMake_TEST_TLS_VERSION
     )
   if(DEFINED ${var})
     list(APPEND file-DOWNLOAD_ARGS -D${var}=${${var}})

+ 6 - 0
Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake

@@ -11,6 +11,7 @@ run_cmake(httpheader-not-set)
 run_cmake(netrc-bad)
 run_cmake(tls-cainfo-not-set)
 run_cmake(tls-verify-not-set)
+run_cmake(TLS_VERSION-missing)
 run_cmake(pass-not-set)
 run_cmake(no-save-hash)
 
@@ -25,7 +26,12 @@ if(NOT CMake_TEST_NO_NETWORK)
   run_cmake(bad-hostname)
 endif()
 
+run_cmake_with_options(TLS_VERSION-bad)
+
 if(CMake_TEST_TLS_VERIFY_URL)
   run_cmake(TLS_VERIFY-bad)
   run_cmake_with_options(TLS_VERIFY-good -Durl=${CMake_TEST_TLS_VERIFY_URL})
+  if(CMake_TEST_TLS_VERSION)
+    run_cmake_with_options(TLS_VERSION-good -Durl=${CMake_TEST_TLS_VERIFY_URL} -Dtls_version=${CMake_TEST_TLS_VERSION})
+  endif()
 endif()

+ 1 - 0
Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-bad-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-bad-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at TLS_VERSION-bad\.cmake:[0-9]+ \(file\):
+  file DOWNLOAD given unknown TLS/SSL version bad-arg
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$

+ 1 - 0
Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-bad.cmake

@@ -0,0 +1 @@
+file(DOWNLOAD "" TLS_VERSION bad-arg TLS_VERIFY 1 STATUS status LOG log)

+ 6 - 0
Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-good.cmake

@@ -0,0 +1,6 @@
+file(DOWNLOAD ${url} TLS_VERSION "${tls_version}" TLS_VERIFY 1 STATUS status LOG log)
+message(STATUS "${status}")
+list(GET status 0 code)
+if(NOT code EQUAL 0)
+  message("${log}")
+endif()

+ 1 - 0
Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-missing-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-missing-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at TLS_VERSION-missing\.cmake:[0-9]+ \(file\):
+  file DOWNLOAD missing value for TLS_VERSION\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$

+ 1 - 0
Tests/RunCMake/file-DOWNLOAD/TLS_VERSION-missing.cmake

@@ -0,0 +1 @@
+file(DOWNLOAD "" "" TLS_VERSION)

+ 1 - 0
Tests/RunCMake/file/RunCMakeTest.cmake

@@ -12,6 +12,7 @@ run_cmake(UPLOAD-httpheader-not-set)
 run_cmake(UPLOAD-netrc-bad)
 run_cmake(UPLOAD-tls-cainfo-not-set)
 run_cmake(UPLOAD-tls-verify-not-set)
+run_cmake(UPLOAD-TLS_VERSION-missing)
 run_cmake(UPLOAD-pass-not-set)
 run_cmake(INSTALL-DIRECTORY)
 run_cmake(INSTALL-FILES_FROM_DIR)

+ 1 - 0
Tests/RunCMake/file/UPLOAD-TLS_VERSION-missing-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/file/UPLOAD-TLS_VERSION-missing-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at UPLOAD-TLS_VERSION-missing\.cmake:[0-9]+ \(file\):
+  file UPLOAD missing value for TLS_VERSION\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$

+ 1 - 0
Tests/RunCMake/file/UPLOAD-TLS_VERSION-missing.cmake

@@ -0,0 +1 @@
+file(UPLOAD "" "" TLS_VERSION)