ctest: Add explicit options for TLS server verification

Add a dedicated `TLSVerify` ctest option and a `CTEST_TLS_VERIFY`
variable to control it.  Deprecate `CurlOptions` because it exposes
internal implementation details.
This commit is contained in:
Brad King 2024-03-01 10:56:03 -05:00
parent 51728a6dd3
commit 0aba13a2f3
28 changed files with 113 additions and 13 deletions

View File

@ -728,6 +728,7 @@ Variables for CTest
/variable/CTEST_SVN_UPDATE_OPTIONS /variable/CTEST_SVN_UPDATE_OPTIONS
/variable/CTEST_TEST_LOAD /variable/CTEST_TEST_LOAD
/variable/CTEST_TEST_TIMEOUT /variable/CTEST_TEST_TIMEOUT
/variable/CTEST_TLS_VERIFY
/variable/CTEST_UPDATE_COMMAND /variable/CTEST_UPDATE_COMMAND
/variable/CTEST_UPDATE_OPTIONS /variable/CTEST_UPDATE_OPTIONS
/variable/CTEST_UPDATE_VERSION_ONLY /variable/CTEST_UPDATE_VERSION_ONLY

View File

@ -1452,6 +1452,10 @@ Configuration settings include:
* :module:`CTest` module variable: ``CTEST_SUBMIT_RETRY_DELAY`` * :module:`CTest` module variable: ``CTEST_SUBMIT_RETRY_DELAY``
``CurlOptions`` ``CurlOptions``
.. deprecated:: 3.30
Use ``TLSVerify`` instead.
Specify a semicolon-separated list of options to control the Specify a semicolon-separated list of options to control the
Curl library that CTest uses internally to connect to the Curl library that CTest uses internally to connect to the
server. server.
@ -1547,6 +1551,15 @@ Configuration settings include:
* `CTest Script`_ variable: :variable:`CTEST_SUBMIT_INACTIVITY_TIMEOUT` * `CTest Script`_ variable: :variable:`CTEST_SUBMIT_INACTIVITY_TIMEOUT`
* :module:`CTest` module variable: ``CTEST_SUBMIT_INACTIVITY_TIMEOUT`` * :module:`CTest` module variable: ``CTEST_SUBMIT_INACTIVITY_TIMEOUT``
``TLSVerify``
.. versionadded:: 3.30
Specify a boolean value indicating whether to verify the server
certificate when submitting to a dashboard via ``https://`` URLs.
* `CTest Script`_ variable: :variable:`CTEST_TLS_VERIFY`
* :module:`CTest` module variable: ``CTEST_TLS_VERIFY``
``TriggerSite`` ``TriggerSite``
Legacy option. Not used. Legacy option. Not used.

View File

@ -15,3 +15,7 @@ curl-tls-version
:variable:`CMAKE_TLS_VERSION` variable and :envvar:`CMAKE_TLS_VERSION` :variable:`CMAKE_TLS_VERSION` variable and :envvar:`CMAKE_TLS_VERSION`
environment variable, to specify the minimum TLS version for connections environment variable, to specify the minimum TLS version for connections
to ``https://`` URLs. to ``https://`` URLs.
* The :command:`ctest_submit` command and :option:`ctest -T Submit <ctest -T>`
step gained a ``TLSVerify`` option to control negotiation with
``https://`` URLs. See the :variable:`CTEST_TLS_VERIFY` variable.

View File

@ -1,6 +1,10 @@
CTEST_CURL_OPTIONS CTEST_CURL_OPTIONS
------------------ ------------------
.. deprecated:: 3.30
Use the :variable:`CTEST_TLS_VERIFY` variable instead.
.. versionadded:: 3.1 .. versionadded:: 3.1
Specify the CTest ``CurlOptions`` setting Specify the CTest ``CurlOptions`` setting

View File

@ -0,0 +1,10 @@
CTEST_TLS_VERIFY
----------------
.. versionadded:: 3.30
Specify the CTest ``TLSVerify`` setting in a :manual:`ctest(1)`
:ref:`Dashboard Client` script or in project ``CMakeLists.txt`` code
before including the :module:`CTest` module. The value is a boolean
indicating whether to verify the server certificate when submitting
to a dashboard via ``https://`` URLs.

View File

@ -95,6 +95,8 @@ TimeOut: @DART_TESTING_TIMEOUT@
# so would cause the system load to exceed this value. # so would cause the system load to exceed this value.
TestLoad: @CTEST_TEST_LOAD@ TestLoad: @CTEST_TEST_LOAD@
TLSVerify: @CTEST_TLS_VERIFY@
UseLaunchers: @CTEST_USE_LAUNCHERS@ UseLaunchers: @CTEST_USE_LAUNCHERS@
CurlOptions: @CTEST_CURL_OPTIONS@ CurlOptions: @CTEST_CURL_OPTIONS@
# warning, if you add new options here that have to do with submit, # warning, if you add new options here that have to do with submit,

View File

@ -12,6 +12,7 @@
#include "cmList.h" #include "cmList.h"
#include "cmStringAlgorithms.h" #include "cmStringAlgorithms.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cmValue.h"
cmCTestCurl::cmCTestCurl(cmCTest* ctest) cmCTestCurl::cmCTestCurl(cmCTest* ctest)
: CTest(ctest) : CTest(ctest)
@ -57,13 +58,18 @@ size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/,
cmCTestCurlOpts::cmCTestCurlOpts(cmCTest* ctest) cmCTestCurlOpts::cmCTestCurlOpts(cmCTest* ctest)
{ {
cmList args{ ctest->GetCTestConfiguration("CurlOptions") }; std::string tlsVerify = ctest->GetCTestConfiguration("TLSVerify");
for (std::string const& arg : args) { if (!tlsVerify.empty()) {
if (arg == "CURLOPT_SSL_VERIFYPEER_OFF") { this->TLSVerifyOpt = cmIsOn(tlsVerify);
this->VerifyPeerOff = true; } else {
} cmList args{ ctest->GetCTestConfiguration("CurlOptions") };
if (arg == "CURLOPT_SSL_VERIFYHOST_OFF") { for (std::string const& arg : args) {
this->VerifyHostOff = true; if (arg == "CURLOPT_SSL_VERIFYPEER_OFF") {
this->TLSVerifyOpt = false;
}
if (arg == "CURLOPT_SSL_VERIFYHOST_OFF") {
this->VerifyHostOff = true;
}
} }
} }
} }
@ -74,8 +80,9 @@ bool cmCTestCurl::InitCurl()
return false; return false;
} }
cmCurlSetCAInfo(this->Curl); cmCurlSetCAInfo(this->Curl);
if (this->CurlOpts.VerifyPeerOff) { if (this->CurlOpts.TLSVerifyOpt) {
curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER,
*this->CurlOpts.TLSVerifyOpt ? 1 : 0);
} }
if (this->CurlOpts.VerifyHostOff) { if (this->CurlOpts.VerifyHostOff) {
curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);

View File

@ -7,6 +7,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <cm/optional>
#include <cm3p/curl/curl.h> #include <cm3p/curl/curl.h>
class cmCTest; class cmCTest;
@ -14,7 +16,7 @@ class cmCTest;
struct cmCTestCurlOpts struct cmCTestCurlOpts
{ {
cmCTestCurlOpts(cmCTest* ctest); cmCTestCurlOpts(cmCTest* ctest);
bool VerifyPeerOff = false; cm::optional<bool> TLSVerifyOpt;
bool VerifyHostOff = false; bool VerifyHostOff = false;
}; };

View File

@ -55,6 +55,8 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
this->Makefile, "DropLocation", "CTEST_DROP_LOCATION", this->Quiet); this->Makefile, "DropLocation", "CTEST_DROP_LOCATION", this->Quiet);
} }
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "TLSVerify", "CTEST_TLS_VERIFY", this->Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable( this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet); this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable( this->CTest->SetCTestConfigurationFromCMakeVariable(

View File

@ -8,6 +8,7 @@
#include <sstream> #include <sstream>
#include <cm/iomanip> #include <cm/iomanip>
#include <cm/optional>
#include <cmext/algorithm> #include <cmext/algorithm>
#include <cm3p/curl/curl.h> #include <cm3p/curl/curl.h>
@ -177,11 +178,14 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
curl = curl_easy_init(); curl = curl_easy_init();
if (curl) { if (curl) {
cmCurlSetCAInfo(curl); cmCurlSetCAInfo(curl);
if (curlOpts.VerifyPeerOff) { if (curlOpts.TLSVerifyOpt) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Set CURLOPT_SSL_VERIFYPEER to off\n", " Set CURLOPT_SSL_VERIFYPEER to "
<< (*curlOpts.TLSVerifyOpt ? "on" : "off")
<< "\n",
this->Quiet); this->Quiet);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,
*curlOpts.TLSVerifyOpt ? 1 : 0);
} }
if (curlOpts.VerifyHostOff) { if (curlOpts.VerifyHostOff) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,

View File

@ -0,0 +1,2 @@
Error message was: ([Cc]ould *n.t resolve host:? '?badhostname.invalid'?|The requested URL returned error:|Protocol "https" (not supported or disabled|not supported|disabled)|.* was built with SSL disabled).*
Problems when submitting via HTTP

View File

@ -0,0 +1 @@
Set CURLOPT_SSL_VERIFYPEER to off

View File

@ -0,0 +1 @@
include(FailDrop-common.cmake)

View File

@ -0,0 +1,2 @@
Error message was: ([Cc]ould *n.t resolve host:? '?badhostname.invalid'?|The requested URL returned error:|Protocol "https" (not supported or disabled|not supported|disabled)|.* was built with SSL disabled).*
Problems when submitting via HTTP

View File

@ -0,0 +1 @@
Set CURLOPT_SSL_VERIFYPEER to on

View File

@ -0,0 +1 @@
include(FailDrop-common.cmake)

View File

@ -0,0 +1,3 @@
set(SUBMIT_URL "https://badhostname.invalid")
set(CTEST_SUBMIT_RETRY_COUNT 0 CACHE STRING "")
include(CTest)

View File

@ -1,6 +1,10 @@
include(RunCMake) include(RunCMake)
include(RunCTest) include(RunCTest)
# Do not use any proxy for lookup of an invalid site.
# DNS failure by proxy looks different than DNS failure without proxy.
set(ENV{no_proxy} "$ENV{no_proxy},badhostname.invalid")
set(RunCMake_TEST_TIMEOUT 60) set(RunCMake_TEST_TIMEOUT 60)
run_cmake_command(repeat-opt-bad1 run_cmake_command(repeat-opt-bad1
@ -484,6 +488,17 @@ run_NoTests()
# Check the configuration type variable is passed # Check the configuration type variable is passed
run_ctest(check-configuration-type) run_ctest(check-configuration-type)
function(run_FailDrop case)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/FailDrop-${case}-build)
run_cmake_with_options(FailDrop-${case} ${ARGN})
set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(FailDrop-${case}-ctest
${CMAKE_CTEST_COMMAND} -M Experimental -T Submit -VV
)
endfunction()
run_FailDrop(TLSVerify-ON -DCTEST_TLS_VERIFY=ON)
run_FailDrop(TLSVerify-OFF -DCTEST_TLS_VERIFY=OFF)
run_cmake_command(EmptyDirCoverage-ctest run_cmake_command(EmptyDirCoverage-ctest
${CMAKE_CTEST_COMMAND} -C Debug -M Experimental -T Coverage ${CMAKE_CTEST_COMMAND} -C Debug -M Experimental -T Coverage
) )

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
Error message was: ([Cc]ould *n.t resolve host:? '?badhostname.invalid'?|The requested URL returned error:|Protocol "https" (not supported or disabled|not supported|disabled)|.* was built with SSL disabled).*
Problems when submitting via HTTP

View File

@ -0,0 +1,4 @@
SetCTestConfigurationFromCMakeVariable:TLSVerify:CTEST_TLS_VERIFY
SetCTestConfiguration:TLSVerify:OFF
.*
Set CURLOPT_SSL_VERIFYPEER to off

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
Error message was: ([Cc]ould *n.t resolve host:? '?badhostname.invalid'?|The requested URL returned error:|Protocol "https" (not supported or disabled|not supported|disabled)|.* was built with SSL disabled).*
Problems when submitting via HTTP

View File

@ -0,0 +1,4 @@
SetCTestConfigurationFromCMakeVariable:TLSVerify:CTEST_TLS_VERIFY
SetCTestConfiguration:TLSVerify:ON
.*
Set CURLOPT_SSL_VERIFYPEER to on

View File

@ -4,6 +4,7 @@ include(RunCTest)
set(CASE_DROP_METHOD "http") set(CASE_DROP_METHOD "http")
set(CASE_DROP_SITE "badhostname.invalid") set(CASE_DROP_SITE "badhostname.invalid")
set(CASE_CTEST_SUBMIT_ARGS "") set(CASE_CTEST_SUBMIT_ARGS "")
set(CASE_TEST_PREFIX_CODE "")
# Do not use any proxy for lookup of an invalid site. # Do not use any proxy for lookup of an invalid site.
# DNS failure by proxy looks different than DNS failure without proxy. # DNS failure by proxy looks different than DNS failure without proxy.
@ -54,3 +55,10 @@ endfunction()
run_ctest_submit_FailDrop(http) run_ctest_submit_FailDrop(http)
run_ctest_submit_FailDrop(https) run_ctest_submit_FailDrop(https)
block()
set(CASE_DROP_METHOD "https")
set(CASE_TEST_PREFIX_CODE "set(CTEST_TLS_VERIFY ON)")
run_ctest(FailDrop-TLSVerify-ON -VV)
set(CASE_TEST_PREFIX_CODE "set(CTEST_TLS_VERIFY OFF)")
run_ctest(FailDrop-TLSVerify-OFF -VV)
endblock()

View File

@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
@CASE_TEST_PREFIX_CODE@
set(CTEST_SITE "test-site") set(CTEST_SITE "test-site")
set(CTEST_BUILD_NAME "test-build-name") set(CTEST_BUILD_NAME "test-build-name")