aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2024-04-04 13:50:53 +0300
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2024-04-04 18:46:53 +0300
commit3604266e924459651b85e1b4393d3ebccfa823b8 (patch)
treeac30c1d81e7b0f5c1b9dc971cb2b0096d29b5480
parent06700cf272cf3d9417f7e879e63635ecf94763d4 (diff)
Linux: fix wrong CA bundle path in prebuilt binaries
Libcurl determines the CA bundle path during build time. This may differ between Linux distributions like Debian and RHEL, causing network requests to fail when libcurl attempts to use a non-existent certificate file. Add possibility to configure the CA bundle file location during runtime, with either automatic detection (using the paths from libcurl configure) or with a manual value. This option only has effect on Linux. Task-number: QLS-883 Pick-to: 3.0 Change-Id: Id746b3f1f265be45e9911b22960d8282b8271eb6 Reviewed-by: Iikka Eklund <iikka.eklund@qt.io> (cherry picked from commit 4802bd0c49a23d9eee1cbda69844e53cfc69b512)
-rw-r--r--CHANGELOG1
-rw-r--r--INSTALL_unix.txt1
-rw-r--r--README.md8
-rw-r--r--dist/qtlicd.ini8
-rw-r--r--src/libs/qlicensecore/constants.h14
-rw-r--r--src/libs/qlicenseservice/httpclient.cpp37
-rw-r--r--src/libs/qlicenseservice/httpclient.h4
-rw-r--r--src/libs/qlicenseservice/licenser.cpp3
8 files changed, 76 insertions, 0 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 61c3644..c6c5986 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@ Qt License Service changelog
####################
Changes in 3.0.1
+- [QLS-883] Linux: fix wrong CA bundle path in prebuilt binaries
- [QLS-860] Build License Service against static openssl and curl
- [QLS-857] Fix CIP launching on-demand service in a new console window on Windows
- [QLS-852] Fix wrong application data path on macOS
diff --git a/INSTALL_unix.txt b/INSTALL_unix.txt
index 1f84658..52dc99f 100644
--- a/INSTALL_unix.txt
+++ b/INSTALL_unix.txt
@@ -54,6 +54,7 @@ The Qt License Service can operate in the following modes:
- server_addr # The address and port of the Qt License Server. The default one
# is the cloud instance hosted by Qt. If using on-prem server then
# set the address accordingly.
+ - ca_bundle_path # Set the absolute path to CA bundle file, or "auto" for automatic detection.
- tcp_listening_port # Change if the default value is not suitable when using the
# on-prem server
diff --git a/README.md b/README.md
index f608acf..23dc67f 100644
--- a/README.md
+++ b/README.md
@@ -280,3 +280,11 @@ seems to grow too big.
Linux: /home/<user>/.local/share/Qt/qtlicd/port.ini
macOS: $HOME/Library/Application Support/Qt/qtlicd/port.ini
Windows: C:\Users\<user>\AppData\Roaming\Qt\qtlicd\port.ini
+
+3. Q: I'm getting a "Problem with the SSL CA cert (path? access rights?)" error message from license service?
+
+ A: This is likely due to invalid CA bundle path. By default the path is attempted to be resolved
+ automatically on Linux. If this fails, an absolute path value can be set manually in the qtlicd.ini
+ configuration file, for example on Ubuntu 22.04:
+
+ ca_bundle_path=/etc/ssl/certs/ca-certificates.crt
diff --git a/dist/qtlicd.ini b/dist/qtlicd.ini
index fe4c4c2..8b9efb6 100644
--- a/dist/qtlicd.ini
+++ b/dist/qtlicd.ini
@@ -14,6 +14,14 @@
server_addr=
###################
+# ca_bundle_path
+# Path to CA bundle file containing root and intermediate certificates. Either set an
+# absolute path or "auto" to attempt autodetection of the CA bundle path.
+# This setting will only have effect on Linux.
+# Type: string
+ca_bundle_path="auto"
+
+###################
# reservation_access_point
# License server REST access point for normal license reservation requests
# Type: string
diff --git a/src/libs/qlicensecore/constants.h b/src/libs/qlicensecore/constants.h
index d23504c..1e96caf 100644
--- a/src/libs/qlicensecore/constants.h
+++ b/src/libs/qlicensecore/constants.h
@@ -5,6 +5,9 @@
#pragma once
+#include <vector>
+#include <string>
+
namespace QLicenseCore {
// Constants used through the LicdSetup and consuming classes
@@ -17,6 +20,8 @@ constexpr char sc_loginAccessPoint[] = "login_access_point";
constexpr char sc_serverAddr[] = "server_addr";
constexpr char sc_tcpListeningPort[] = "tcp_listening_port";
+constexpr char sc_caBundlePath[] = "ca_bundle_path";
+
constexpr char sc_hwId[] = "hw_id";
constexpr char sc_hostOs[] = "host_os";
constexpr char sc_email[] = "email";
@@ -28,6 +33,15 @@ constexpr char sc_queueMaxRetryInterval[] = "queue_max_retry_interval";
constexpr char sc_queueMaxWaitingTime[] = "queue_max_waiting_time";
constexpr char sc_onDemandShutdownTimeout[] = "on_demand_shutdown_timeout";
+static const std::vector<std::string> sc_caBundleSearchPaths {
+ // from SEARCH_CA_BUNDLE_PATHS in 3rdparty/curl/CMakeList.txt
+ "/etc/ssl/certs/ca-certificates.crt",
+ "/etc/pki/tls/certs/ca-bundle.crt",
+ "/usr/share/ssl/certs/ca-bundle.crt",
+ "/usr/local/share/certs/ca-root-nss.crt",
+ "/etc/ssl/cert.pem"
+};
+
// Other
} // namespace QLicenseCore
diff --git a/src/libs/qlicenseservice/httpclient.cpp b/src/libs/qlicenseservice/httpclient.cpp
index a8bfc09..1bf5bde 100644
--- a/src/libs/qlicenseservice/httpclient.cpp
+++ b/src/libs/qlicenseservice/httpclient.cpp
@@ -5,6 +5,7 @@
#include "httpclient.h"
+#include "constants.h"
#include "version.h"
#include "commonsetup.h"
@@ -120,6 +121,9 @@ HttpResult *HttpRequest::doRequest(const std::string &payload)
if (m_forceHttps)
curl_easy_setopt(m_curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
+ if (!m_caBundlePath.empty())
+ curl_easy_setopt(m_curl, CURLOPT_CAINFO, m_caBundlePath.c_str());
+
curl_easy_setopt(m_curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_3);
if (!payload.empty()) {
@@ -175,6 +179,11 @@ void HttpRequest::setForceHttps(bool https)
m_forceHttps = https;
}
+void HttpRequest::setCaBundlePath(const std::string &path)
+{
+ m_caBundlePath = path;
+}
+
size_t HttpRequest::writeCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
//std::cout << "Reading data\n";
@@ -222,6 +231,7 @@ void HttpClient::send(uint16_t &requestId, const std::string &payload, const std
HttpRequest *request = new HttpRequest(requestUrl, authKey);
request->setDelay(delay);
request->setForceHttps(m_forceHttps);
+ request->setCaBundlePath(m_caBundlePath);
request->onResultReady = sendFinished;
request->onError = sendFinished;
@@ -238,6 +248,7 @@ bool HttpClient::sendReceive(std::string &reply, const std::string &payload, con
HttpRequest request(requestUrl, authKey);
request.setForceHttps(m_forceHttps);
+ request.setCaBundlePath(m_caBundlePath);
std::unique_ptr<HttpResult> result(request.doRequest(payload));
if (result->error() != CURLE_OK) {
@@ -282,4 +293,30 @@ void HttpClient::setForceHttps(bool https)
m_forceHttps = https;
}
+/*
+ Set the absolute path to CA bundle or empty string to detect the path automatically.
+ This has only effect on linux.
+*/
+void HttpClient::setCABundlePath(const std::string &path)
+{
+#if __linux__
+ if (!path.empty()) {
+ m_caBundlePath = path;
+ logDebug("Manually set CA bundle: %s", path.c_str());
+ return;
+ }
+ // else we search for known paths
+ for (const auto &bundlePath : sc_caBundleSearchPaths) {
+ if (utils::fileExists(bundlePath)) {
+ logDebug("Found CA bundle: %s", bundlePath.c_str());
+ m_caBundlePath = bundlePath;
+ break;
+ }
+ }
+
+ if (m_caBundlePath.empty())
+ logWarn("CA bundle path was not set!");
+#endif
+}
+
} // namespace QLicenseService
diff --git a/src/libs/qlicenseservice/httpclient.h b/src/libs/qlicenseservice/httpclient.h
index 285e576..f237a0f 100644
--- a/src/libs/qlicenseservice/httpclient.h
+++ b/src/libs/qlicenseservice/httpclient.h
@@ -64,6 +64,7 @@ public:
HttpResult *doRequest(const std::string &payload);
void setDelay(uint32_t msecs);
void setForceHttps(bool https);
+ void setCaBundlePath(const std::string &path);
public: // event handlers / callbacks
std::function<void(std::string)> onResultReady;
@@ -76,6 +77,7 @@ private:
const std::string m_url;
uint32_t m_delay;
bool m_forceHttps;
+ std::string m_caBundlePath;
CURL *m_curl;
curl_slist *m_headers;
@@ -95,9 +97,11 @@ public:
QLicenseCore::Status receive(uint16_t &clientId, std::string &reply);
void setForceHttps(bool https);
+ void setCABundlePath(const std::string &path);
private:
bool m_forceHttps;
+ std::string m_caBundlePath;
std::string m_serverUrl;
std::unordered_map<uint16_t, std::future<HttpResult *>> m_futures;
diff --git a/src/libs/qlicenseservice/licenser.cpp b/src/libs/qlicenseservice/licenser.cpp
index 033ac46..65c321e 100644
--- a/src/libs/qlicenseservice/licenser.cpp
+++ b/src/libs/qlicenseservice/licenser.cpp
@@ -46,6 +46,9 @@ Licenser::Licenser(DaemonRunMode runMode, uint16_t tcpPort, const std::string &w
// Start the HTTP client
m_http = new HttpClient(serverAddr);
+ std::string caBundle = m_settings->get(sc_caBundlePath);
+ m_http->setCABundlePath((caBundle == "auto") ? std::string() : caBundle);
+
// Get server version as HTTP should be up now
if ((m_state != DaemonState::Offline) && getServerVersion())
logInfo("%s", m_serverVersion.c_str());