12#include "qdtls_openssl_p.h"
15#include <QtNetwork/private/qsslcipher_p.h>
17#include <QtNetwork/qsslcipher.h>
18#include <QtNetwork/qssl.h>
20#include <QtCore/qdir.h>
21#include <QtCore/qdirlisting.h>
22#include <QtCore/qlist.h>
23#include <QtCore/qmutex.h>
24#include <QtCore/qscopeguard.h>
25#include <QtCore/qset.h>
33using namespace Qt::StringLiterals;
35#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
36constexpr auto DefaultWarningLevel = QtCriticalMsg;
44 QList<QSslCipher> &defaultCiphers)
48 STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
51 const auto ciph = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
54 if (!ciph.name().toLower().startsWith(
"adh"_L1) &&
55 !ciph.name().toLower().startsWith(
"exp-adh"_L1) &&
56 !ciph.name().toLower().startsWith(
"aecdh"_L1)) {
59 if (ciph.usedBits() >= 128)
60 defaultCiphers << ciph;
69QString QTlsBackendOpenSSL::getErrorsFromOpenSsl()
75 if (!errorString.isEmpty())
76 errorString.append(
", "_L1);
78 errorString.append(QLatin1StringView(buf));
85 const auto errors = getErrorsFromOpenSsl();
87 qCWarning(lcTlsBackend) <<
"Discarding errors:" << errors;
96bool QTlsBackendOpenSSL::ensureLibraryLoaded()
98 static bool libraryLoaded = []() {
107 qCWarning(lcTlsBackend,
"QSslSocket: OpenSSL >= 1.1.1 is required; %s was found instead",
q_OpenSSL_version(OPENSSL_VERSION
));
119 qWarning(
"Random number generator not seeded, disabling SSL support");
126 return libraryLoaded;
131 return builtinBackendNames[nameIndexOpenSSL];
136 return ensureLibraryLoaded();
150 return QString::fromLatin1(versionString);
155 return OPENSSL_VERSION_NUMBER;
163 return QStringLiteral(OPENSSL_VERSION_TEXT);
174 ensureCiphersAndCertsLoaded();
177void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded()
const
179 Q_CONSTINIT
static bool initializationStarted =
false;
180 Q_CONSTINIT
static QAtomicInt initialized = Q_BASIC_ATOMIC_INITIALIZER(0);
181 Q_CONSTINIT
static QRecursiveMutex initMutex;
183 if (initialized.loadAcquire())
186 const QMutexLocker locker(&initMutex);
188 if (initializationStarted || initialized.loadAcquire())
194 initializationStarted =
true;
196 auto guard = qScopeGuard([] { initialized.storeRelease(1); });
198 resetDefaultCiphers();
199 resetDefaultEllipticCurves();
201#if QT_CONFIG(library)
204 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(
true);
205#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
207 const QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
208 const QStringList symLinkFilter{
209 u"[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]"_s};
210 for (
const auto &dir : dirs) {
211 QDirListing dirList(QString::fromLatin1(dir), symLinkFilter,
212 QDirListing::IteratorFlag::FilesOnly);
213 if (dirList.cbegin() != dirList.cend()) {
214 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(
true);
221 if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
222 setDefaultCaCertificates(systemCaCertificates());
229 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(
true);
233void QTlsBackendOpenSSL::resetDefaultCiphers()
243 QList<QSslCipher> ciphers;
244 QList<QSslCipher> defaultCiphers;
246 q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
251 setDefaultSupportedCiphers(ciphers);
252 setDefaultCiphers(defaultCiphers);
256 defaultCiphers.clear();
257 myCtx = q_SSL_CTX_new(q_DTLS_client_method());
259 mySsl = q_SSL_new(myCtx);
261 q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
262 setDefaultDtlsCiphers(defaultCiphers);
265 q_SSL_CTX_free(myCtx);
272 QList<QSsl::SslProtocol> protocols;
274 protocols << QSsl::AnyProtocol;
275 protocols << QSsl::SecureProtocols;
277QT_WARNING_DISABLE_DEPRECATED
278 protocols << QSsl::TlsV1_0;
279 protocols << QSsl::TlsV1_0OrLater;
280 protocols << QSsl::TlsV1_1;
281 protocols << QSsl::TlsV1_1OrLater;
283 protocols << QSsl::TlsV1_2;
284 protocols << QSsl::TlsV1_2OrLater;
287 protocols << QSsl::TlsV1_3;
288 protocols << QSsl::TlsV1_3OrLater;
293QT_WARNING_DISABLE_DEPRECATED
294 protocols << QSsl::DtlsV1_0;
295 protocols << QSsl::DtlsV1_0OrLater;
297 protocols << QSsl::DtlsV1_2;
298 protocols << QSsl::DtlsV1_2OrLater;
306 QList<QSsl::SupportedFeature> features;
308 features << QSsl::SupportedFeature::CertificateVerification;
310#if !defined(OPENSSL_NO_TLSEXT)
311 features << QSsl::SupportedFeature::ClientSideAlpn;
312 features << QSsl::SupportedFeature::ServerSideAlpn;
315 features << QSsl::SupportedFeature::Ocsp;
316 features << QSsl::SupportedFeature::Psk;
317 features << QSsl::SupportedFeature::SessionTicket;
318 features << QSsl::SupportedFeature::Alerts;
325 QList<QSsl::ImplementedClass> classes;
327 classes << QSsl::ImplementedClass::Key;
328 classes << QSsl::ImplementedClass::Certificate;
329 classes << QSsl::ImplementedClass::Socket;
331 classes << QSsl::ImplementedClass::Dtls;
332 classes << QSsl::ImplementedClass::DtlsCookie;
334 classes << QSsl::ImplementedClass::EllipticCurve;
335 classes << QSsl::ImplementedClass::DiffieHellman;
361#ifdef QSSLSOCKET_DEBUG
365 QList<QSslCertificate> systemCerts;
367 HCERTSTORE hSystemStore;
369 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
370 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT");
372 PCCERT_CONTEXT pc =
nullptr;
374 pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY,
nullptr, pc);
377 QByteArray der(
reinterpret_cast<
const char *>(pc->pbCertEncoded),
378 static_cast<
int>(pc->cbCertEncoded));
379 QSslCertificate cert(der, QSsl::Der);
380 systemCerts.append(cert);
382 CertCloseStore(hSystemStore, 0);
384#elif defined(Q_OS_ANDROID)
385 const QList<QByteArray> certData = fetchSslCertificateData();
386 for (
auto certDatum : certData)
387 systemCerts.append(QSslCertificate::fromData(certDatum, QSsl::Der));
388#elif defined(Q_OS_UNIX)
390 const QList<QByteArray> directories = QSslSocketPrivate::unixRootCertDirectories();
391 QSet<QString> certFiles = {
392 QStringLiteral(
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"),
393 QStringLiteral(
"/etc/pki/tls/certs/ca-bundle.crt"),
394 QStringLiteral(
"/usr/local/share/certs/ca-root-nss.crt")
397 static const size_t extLen = strlen(
".pem");
398 auto hasMatchingExtension = [](
const QString &fileName) {
399 if (size_t(fileName.size()) < extLen + 1)
401 auto ext = QStringView{fileName}.last(extLen);
402 return ext ==
".pem"_L1 || ext ==
".crt"_L1;
405 using F = QDirListing::IteratorFlag;
406 constexpr auto flags = F::FilesOnly | F::ResolveSymlinks;
407 for (
const QByteArray &directory : directories) {
408 for (
const auto &dirEntry : QDirListing(QFile::decodeName(directory), flags)) {
410 if (hasMatchingExtension(dirEntry.fileName()))
411 certFiles.insert(dirEntry.canonicalFilePath());
414 for (
const QString& file : std::as_const(certFiles))
415 systemCerts.append(QSslCertificate::fromFile(file, QSsl::Pem));
418#ifdef QSSLSOCKET_DEBUG
419 qCDebug(lcTlsBackend) <<
"systemCaCertificates retrieval time " << timer.elapsed() <<
"ms";
420 qCDebug(lcTlsBackend) <<
"imported " << systemCerts.count() <<
" certificates";
430 return QTlsPrivate::systemCaCertificates();
436 return new QDtlsClientVerifierOpenSSL;
438 qCWarning(lcTlsBackend,
"Feature 'dtls' is disabled, cannot verify DTLS cookies");
451 return new QDtlsPrivateOpenSSL(q, QSslSocket::SslMode(mode));
455 qCWarning(lcTlsBackend,
"Feature 'dtls' is disabled, cannot encrypt UDP datagrams");
462 return QTlsPrivate::X509CertificateOpenSSL::verify;
467 return QTlsPrivate::X509CertificateOpenSSL::certificatesFromPem;
472 return QTlsPrivate::X509CertificateOpenSSL::certificatesFromDer;
477 return QTlsPrivate::X509CertificateOpenSSL::importPkcs12;
485 const size_t curveCount = q_EC_get_builtin_curves(
nullptr, 0);
486 QVarLengthArray<EC_builtin_curve> builtinCurves(
static_cast<
int>(curveCount));
488 if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
489 ids.reserve(curveCount);
490 for (
const auto &ec : builtinCurves)
491 ids.push_back(ec.nid);
506 const QByteArray curveNameLatin1 = name.toLatin1();
507 nid = q_OBJ_sn2nid(curveNameLatin1.data());
510 nid = q_EC_curve_nist2nid(curveNameLatin1.data());
525 const QByteArray curveNameLatin1 = name.toLatin1();
526 nid = q_OBJ_ln2nid(curveNameLatin1.data());
538 result = QString::fromLatin1(q_OBJ_nid2sn(id));
550 result = QString::fromLatin1(q_OBJ_nid2ln(id));
579 NID_X9_62_prime192v1,
583 NID_X9_62_prime256v1,
597 const int *
const tlsNamedCurveNIDsEnd =
tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
601QString QTlsBackendOpenSSL::msgErrorsDuringHandshake()
603 return QSslSocket::tr(
"Error during SSL handshake: %1").arg(getErrorsFromOpenSsl());
606QSslCipher QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(
const SSL_CIPHER *cipher)
610 const QString desc = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf,
sizeof(buf)));
611 int supportedBits = 0;
613 return createCiphersuite(desc, bits, supportedBits);
623#include "moc_qtlsbackend_openssl_p.cpp"
static void forceAutoTestSecurityLevel()
QTlsPrivate::X509DerReaderPtr X509DerReader() const override
QString tlsLibraryBuildVersionString() const override
QList< QSsl::SslProtocol > supportedProtocols() const override
QTlsPrivate::X509ChainVerifyPtr X509Verifier() const override
bool isTlsNamedCurve(int cid) const override
long tlsLibraryVersionNumber() const override
long tlsLibraryBuildVersionNumber() const override
QTlsPrivate::DtlsCryptograph * createDtlsCryptograph(QDtls *q, int mode) const override
static void logAndClearErrorQueue()
int curveIdFromShortName(const QString &name) const override
QTlsPrivate::X509PemReaderPtr X509PemReader() const override
int curveIdFromLongName(const QString &name) const override
bool isValid() const override
QList< int > ellipticCurvesIds() const override
static void clearErrorQueue()
QString shortNameForId(int cid) const override
QTlsPrivate::X509Certificate * createCertificate() const override
void forceAutotestSecurityLevel() override
QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override
QString longNameForId(int cid) const override
QList< QSslCertificate > systemCaCertificates() const override
QList< QSsl::SupportedFeature > supportedFeatures() const override
QList< QSsl::ImplementedClass > implementedClasses() const override
QTlsPrivate::DtlsCookieVerifier * createDtlsCookieVerifier() const override
void ensureInitialized() const override
QTlsPrivate::TlsKey * createKey() const override
QTlsPrivate::TlsCryptograph * createTlsCryptograph() const override
QString backendName() const override
QString tlsLibraryVersionString() const override
static int s_indexForSSLExtraData
Namespace containing onternal types that TLS backends implement.
QList< QSslCertificate > systemCaCertificates()
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
void q_SSL_CTX_free(SSL_CTX *a)
const char * q_OpenSSL_version(int type)
bool q_resolveOpenSslSymbols()
#define q_SSL_load_error_strings()
unsigned long q_ERR_get_error()
void q_ERR_error_string_n(unsigned long e, char *buf, size_t len)
#define q_OpenSSL_add_all_algorithms()
SSL_CTX * q_SSL_CTX_new(const SSL_METHOD *a)
#define q_sk_SSL_CIPHER_num(st)
const SSL_METHOD * q_TLS_client_method()
SSL * q_SSL_new(SSL_CTX *a)
int q_SSL_CIPHER_get_bits(const SSL_CIPHER *a, int *b)
long q_OpenSSL_version_num()
int q_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
#define q_sk_SSL_CIPHER_value(st, i)
int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
constexpr auto DefaultWarningLevel
const size_t tlsNamedCurveNIDCount
static const int tlsNamedCurveNIDs[]
static void q_loadCiphersForConnection(SSL *connection, QList< QSslCipher > &ciphers, QList< QSslCipher > &defaultCiphers)