11#include "qdtls_openssl_p.h"
14#include <QtNetwork/private/qsslcipher_p.h>
16#include <QtNetwork/qsslcipher.h>
17#include <QtNetwork/qssl.h>
19#include <QtCore/qdir.h>
20#include <QtCore/qdirlisting.h>
21#include <QtCore/qlist.h>
22#include <QtCore/qmutex.h>
23#include <QtCore/qscopeguard.h>
24#include <QtCore/qset.h>
32using namespace Qt::StringLiterals;
34#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
35constexpr auto DefaultWarningLevel = QtCriticalMsg;
43 QList<QSslCipher> &defaultCiphers)
47 STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
50 const auto ciph = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
53 if (!ciph.name().toLower().startsWith(
"adh"_L1) &&
54 !ciph.name().toLower().startsWith(
"exp-adh"_L1) &&
55 !ciph.name().toLower().startsWith(
"aecdh"_L1)) {
58 if (ciph.usedBits() >= 128)
59 defaultCiphers << ciph;
74 if (!errorString.isEmpty())
75 errorString.append(
", "_L1);
77 errorString.append(QLatin1StringView(buf));
84 const auto errors = getErrorsFromOpenSsl();
86 qCWarning(lcTlsBackend) <<
"Discarding errors:" << errors;
97 static bool libraryLoaded = []() {
106 qCWarning(lcTlsBackend,
"QSslSocket: OpenSSL >= 1.1.1 is required; %s was found instead",
q_OpenSSL_version(OPENSSL_VERSION
));
118 qWarning(
"Random number generator not seeded, disabling SSL support");
125 return libraryLoaded;
130 return builtinBackendNames[nameIndexOpenSSL];
135 return ensureLibraryLoaded();
149 return QString::fromLatin1(versionString);
154 return OPENSSL_VERSION_NUMBER;
162 return QStringLiteral(OPENSSL_VERSION_TEXT);
173 ensureCiphersAndCertsLoaded();
178 Q_CONSTINIT
static bool initializationStarted =
false;
179 Q_CONSTINIT
static QAtomicInt initialized = Q_BASIC_ATOMIC_INITIALIZER(0);
180 Q_CONSTINIT
static QRecursiveMutex initMutex;
182 if (initialized.loadAcquire())
185 const QMutexLocker locker(&initMutex);
187 if (initializationStarted || initialized.loadAcquire())
193 initializationStarted =
true;
195 auto guard = qScopeGuard([] { initialized.storeRelease(1); });
197 resetDefaultCiphers();
198 resetDefaultEllipticCurves();
200#if QT_CONFIG(library)
203 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(
true);
204#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
206 const QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
207 const QStringList symLinkFilter{
208 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};
209 for (
const auto &dir : dirs) {
210 QDirListing dirList(QString::fromLatin1(dir), symLinkFilter,
211 QDirListing::IteratorFlag::FilesOnly);
212 if (dirList.cbegin() != dirList.cend()) {
213 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(
true);
220 if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
221 setDefaultCaCertificates(systemCaCertificates());
228 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(
true);
242 QList<QSslCipher> ciphers;
243 QList<QSslCipher> defaultCiphers;
245 q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
250 setDefaultSupportedCiphers(ciphers);
251 setDefaultCiphers(defaultCiphers);
255 defaultCiphers.clear();
256 myCtx = q_SSL_CTX_new(q_DTLS_client_method());
258 mySsl = q_SSL_new(myCtx);
260 q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
261 setDefaultDtlsCiphers(defaultCiphers);
264 q_SSL_CTX_free(myCtx);
271 QList<QSsl::SslProtocol> protocols;
273 protocols << QSsl::AnyProtocol;
274 protocols << QSsl::SecureProtocols;
276QT_WARNING_DISABLE_DEPRECATED
277 protocols << QSsl::TlsV1_0;
278 protocols << QSsl::TlsV1_0OrLater;
279 protocols << QSsl::TlsV1_1;
280 protocols << QSsl::TlsV1_1OrLater;
282 protocols << QSsl::TlsV1_2;
283 protocols << QSsl::TlsV1_2OrLater;
286 protocols << QSsl::TlsV1_3;
287 protocols << QSsl::TlsV1_3OrLater;
292QT_WARNING_DISABLE_DEPRECATED
293 protocols << QSsl::DtlsV1_0;
294 protocols << QSsl::DtlsV1_0OrLater;
296 protocols << QSsl::DtlsV1_2;
297 protocols << QSsl::DtlsV1_2OrLater;
305 QList<QSsl::SupportedFeature> features;
307 features << QSsl::SupportedFeature::CertificateVerification;
309#if !defined(OPENSSL_NO_TLSEXT)
310 features << QSsl::SupportedFeature::ClientSideAlpn;
311 features << QSsl::SupportedFeature::ServerSideAlpn;
314 features << QSsl::SupportedFeature::Ocsp;
315 features << QSsl::SupportedFeature::Psk;
316 features << QSsl::SupportedFeature::SessionTicket;
317 features << QSsl::SupportedFeature::Alerts;
324 QList<QSsl::ImplementedClass> classes;
326 classes << QSsl::ImplementedClass::Key;
327 classes << QSsl::ImplementedClass::Certificate;
328 classes << QSsl::ImplementedClass::Socket;
330 classes << QSsl::ImplementedClass::Dtls;
331 classes << QSsl::ImplementedClass::DtlsCookie;
333 classes << QSsl::ImplementedClass::EllipticCurve;
334 classes << QSsl::ImplementedClass::DiffieHellman;
360#ifdef QSSLSOCKET_DEBUG
364 QList<QSslCertificate> systemCerts;
366 HCERTSTORE hSystemStore;
368 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
369 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT");
371 PCCERT_CONTEXT pc =
nullptr;
373 pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY,
nullptr, pc);
376 QByteArray der(
reinterpret_cast<
const char *>(pc->pbCertEncoded),
377 static_cast<
int>(pc->cbCertEncoded));
378 QSslCertificate cert(der, QSsl::Der);
379 systemCerts.append(cert);
381 CertCloseStore(hSystemStore, 0);
383#elif defined(Q_OS_ANDROID)
384 const QList<QByteArray> certData = fetchSslCertificateData();
385 for (
auto certDatum : certData)
386 systemCerts.append(QSslCertificate::fromData(certDatum, QSsl::Der));
387#elif defined(Q_OS_UNIX)
389 const QList<QByteArray> directories = QSslSocketPrivate::unixRootCertDirectories();
390 QSet<QString> certFiles = {
391 QStringLiteral(
"/etc/pki/tls/certs/ca-bundle.crt"),
392 QStringLiteral(
"/usr/local/share/certs/ca-root-nss.crt")
394 static const QStringList nameFilters = {u"*.pem"_s, u"*.crt"_s};
395 using F = QDirListing::IteratorFlag;
396 constexpr auto flags = F::FilesOnly | F::ResolveSymlinks;
397 for (
const auto &directory : directories) {
398 for (
const auto &dirEntry : QDirListing(directory, nameFilters, flags)) {
400 certFiles.insert(dirEntry.canonicalFilePath());
403 for (
const QString& file : std::as_const(certFiles))
404 systemCerts.append(QSslCertificate::fromPath(file, QSsl::Pem));
407#ifdef QSSLSOCKET_DEBUG
408 qCDebug(lcTlsBackend) <<
"systemCaCertificates retrieval time " << timer.elapsed() <<
"ms";
409 qCDebug(lcTlsBackend) <<
"imported " << systemCerts.count() <<
" certificates";
419 return QTlsPrivate::systemCaCertificates();
425 return new QDtlsClientVerifierOpenSSL;
427 qCWarning(lcTlsBackend,
"Feature 'dtls' is disabled, cannot verify DTLS cookies");
440 return new QDtlsPrivateOpenSSL(q, QSslSocket::SslMode(mode));
444 qCWarning(lcTlsBackend,
"Feature 'dtls' is disabled, cannot encrypt UDP datagrams");
451 return QTlsPrivate::X509CertificateOpenSSL::verify;
456 return QTlsPrivate::X509CertificateOpenSSL::certificatesFromPem;
461 return QTlsPrivate::X509CertificateOpenSSL::certificatesFromDer;
466 return QTlsPrivate::X509CertificateOpenSSL::importPkcs12;
474 const size_t curveCount = q_EC_get_builtin_curves(
nullptr, 0);
475 QVarLengthArray<EC_builtin_curve> builtinCurves(
static_cast<
int>(curveCount));
477 if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
478 ids.reserve(curveCount);
479 for (
const auto &ec : builtinCurves)
480 ids.push_back(ec.nid);
495 const QByteArray curveNameLatin1 = name.toLatin1();
496 nid = q_OBJ_sn2nid(curveNameLatin1.data());
499 nid = q_EC_curve_nist2nid(curveNameLatin1.data());
514 const QByteArray curveNameLatin1 = name.toLatin1();
515 nid = q_OBJ_ln2nid(curveNameLatin1.data());
527 result = QString::fromLatin1(q_OBJ_nid2sn(id));
539 result = QString::fromLatin1(q_OBJ_nid2ln(id));
568 NID_X9_62_prime192v1,
572 NID_X9_62_prime256v1,
586 const int *
const tlsNamedCurveNIDsEnd =
tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
592 return QSslSocket::tr(
"Error during SSL handshake: %1").arg(getErrorsFromOpenSsl());
599 const QString desc = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf,
sizeof(buf)));
600 int supportedBits = 0;
602 return createCiphersuite(desc, bits, supportedBits);
612#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
static QString getErrorsFromOpenSsl()
Combined button and popup list for selecting options.
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)