1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsslsocket_openssl_symbols_p.h"
5#include "qtlsbackend_openssl_p.h"
6#include "qtlskey_openssl_p.h"
7#include "qx509_openssl_p.h"
8#include "qtls_openssl_p.h"
9
10#if QT_CONFIG(dtls)
11#include "qdtls_openssl_p.h"
12#endif // QT_CONFIG(dtls)
13
14#include <QtNetwork/private/qsslcipher_p.h>
15
16#include <QtNetwork/qsslcipher.h>
17#include <QtNetwork/qssl.h>
18
19#include <QtCore/qdir.h>
20#include <QtCore/qdiriterator.h>
21#include <QtCore/qlist.h>
22#include <QtCore/qmutex.h>
23#include <QtCore/qscopeguard.h>
24#include <QtCore/qset.h>
25
26#include "qopenssl_p.h"
27
28#include <algorithm>
29
30QT_BEGIN_NAMESPACE
31
32using namespace Qt::StringLiterals;
33
34#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
35constexpr auto DefaultWarningLevel = QtCriticalMsg;
36#else
37constexpr auto DefaultWarningLevel = QtDebugMsg;
38#endif
39
40Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl", DefaultWarningLevel);
41
42static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphers,
43 QList<QSslCipher> &defaultCiphers)
44{
45 Q_ASSERT(connection);
46
47 STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(a: connection);
48 for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
49 if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
50 const auto ciph = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
51 if (!ciph.isNull()) {
52 // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
53 if (!ciph.name().toLower().startsWith(s: "adh"_L1) &&
54 !ciph.name().toLower().startsWith(s: "exp-adh"_L1) &&
55 !ciph.name().toLower().startsWith(s: "aecdh"_L1)) {
56 ciphers << ciph;
57
58 if (ciph.usedBits() >= 128)
59 defaultCiphers << ciph;
60 }
61 }
62 }
63 }
64}
65
66int QTlsBackendOpenSSL::s_indexForSSLExtraData = -1;
67
68QString QTlsBackendOpenSSL::getErrorsFromOpenSsl()
69{
70 QString errorString;
71 char buf[256] = {}; // OpenSSL docs claim both 120 and 256; use the larger.
72 unsigned long errNum;
73 while ((errNum = q_ERR_get_error())) {
74 if (!errorString.isEmpty())
75 errorString.append(s: ", "_L1);
76 q_ERR_error_string_n(e: errNum, buf, len: sizeof buf);
77 errorString.append(s: QLatin1StringView(buf)); // error is ascii according to man ERR_error_string
78 }
79 return errorString;
80}
81
82void QTlsBackendOpenSSL::logAndClearErrorQueue()
83{
84 const auto errors = getErrorsFromOpenSsl();
85 if (errors.size())
86 qCWarning(lcTlsBackend) << "Discarding errors:" << errors;
87}
88
89void QTlsBackendOpenSSL::clearErrorQueue()
90{
91 while (q_ERR_get_error())
92 ;
93}
94
95bool QTlsBackendOpenSSL::ensureLibraryLoaded()
96{
97 static bool libraryLoaded = []() {
98 if (!q_resolveOpenSslSymbols())
99 return false;
100
101 // Initialize OpenSSL.
102 if (q_OPENSSL_init_ssl(opts: 0, settings: nullptr) != 1)
103 return false;
104
105 if (q_OpenSSL_version_num() < 0x10101000L) {
106 qCWarning(lcTlsBackend, "QSslSocket: OpenSSL >= 1.1.1 is required; %s was found instead", q_OpenSSL_version(OPENSSL_VERSION));
107 return false;
108 }
109
110 q_SSL_load_error_strings();
111 q_OpenSSL_add_all_algorithms();
112
113 s_indexForSSLExtraData = q_CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl: 0L, argp: nullptr, new_func: nullptr,
114 dup_func: nullptr, free_func: nullptr);
115
116 // Initialize OpenSSL's random seed.
117 if (!q_RAND_status()) {
118 qWarning(msg: "Random number generator not seeded, disabling SSL support");
119 return false;
120 }
121
122 return true;
123 }();
124
125 return libraryLoaded;
126}
127
128QString QTlsBackendOpenSSL::backendName() const
129{
130 return builtinBackendNames[nameIndexOpenSSL];
131}
132
133bool QTlsBackendOpenSSL::isValid() const
134{
135 return ensureLibraryLoaded();
136}
137
138long QTlsBackendOpenSSL::tlsLibraryVersionNumber() const
139{
140 return q_OpenSSL_version_num();
141}
142
143QString QTlsBackendOpenSSL::tlsLibraryVersionString() const
144{
145 const char *versionString = q_OpenSSL_version(OPENSSL_VERSION);
146 if (!versionString)
147 return QString();
148
149 return QString::fromLatin1(ba: versionString);
150}
151
152long QTlsBackendOpenSSL::tlsLibraryBuildVersionNumber() const
153{
154 return OPENSSL_VERSION_NUMBER;
155}
156
157QString QTlsBackendOpenSSL::tlsLibraryBuildVersionString() const
158{
159 // Using QStringLiteral to store the version string as unicode and
160 // avoid false positives from Google searching the playstore for old
161 // SSL versions. See QTBUG-46265
162 return QStringLiteral(OPENSSL_VERSION_TEXT);
163}
164
165void QTlsBackendOpenSSL::ensureInitialized() const
166{
167 // Old qsslsocket_openssl calls supportsSsl() (which means
168 // library found and symbols resolved, this already assured
169 // by the fact we end up in this function (isValid() returned
170 // true for the backend, see its code). The qsslsocket_openssl
171 // proceedes with loading certificate, ciphers and elliptic
172 // curves.
173 ensureCiphersAndCertsLoaded();
174}
175
176void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded() const
177{
178 Q_CONSTINIT static bool initializationStarted = false;
179 Q_CONSTINIT static QAtomicInt initialized = Q_BASIC_ATOMIC_INITIALIZER(0);
180 Q_CONSTINIT static QRecursiveMutex initMutex;
181
182 if (initialized.loadAcquire())
183 return;
184
185 const QMutexLocker locker(&initMutex);
186
187 if (initializationStarted || initialized.loadAcquire())
188 return;
189
190 // Indicate that the initialization has already started in the current
191 // thread in case of recursive calls. The atomic variable cannot be used
192 // for this because it is checked without holding the init mutex.
193 initializationStarted = true;
194
195 auto guard = qScopeGuard(f: [] { initialized.storeRelease(newValue: 1); });
196
197 resetDefaultCiphers();
198 resetDefaultEllipticCurves();
199
200#if QT_CONFIG(library)
201 //load symbols needed to receive certificates from system store
202#if defined(Q_OS_QNX)
203 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
204#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
205 // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
206 const QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
207 QStringList symLinkFilter;
208 symLinkFilter << "[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]"_L1;
209 for (const auto &dir : dirs) {
210 QDirIterator iterator(QLatin1StringView(dir), symLinkFilter, QDir::Files);
211 if (iterator.hasNext()) {
212 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
213 break;
214 }
215 }
216#endif
217#endif // QT_CONFIG(library)
218 // if on-demand loading was not enabled, load the certs now
219 if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
220 setDefaultCaCertificates(systemCaCertificates());
221#ifdef Q_OS_WIN
222 //Enabled for fetching additional root certs from windows update on windows.
223 //This flag is set false by setDefaultCaCertificates() indicating the app uses
224 //its own cert bundle rather than the system one.
225 //Same logic that disables the unix on demand cert loading.
226 //Unlike unix, we do preload the certificates from the cert store.
227 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
228#endif
229}
230
231void QTlsBackendOpenSSL::resetDefaultCiphers()
232{
233 SSL_CTX *myCtx = q_SSL_CTX_new(a: q_TLS_client_method());
234 // Note, we assert, not just silently return/bail out early:
235 // this should never happen and problems with OpenSSL's initialization
236 // must be caught before this (see supportsSsl()).
237 Q_ASSERT(myCtx);
238 SSL *mySsl = q_SSL_new(a: myCtx);
239 Q_ASSERT(mySsl);
240
241 QList<QSslCipher> ciphers;
242 QList<QSslCipher> defaultCiphers;
243
244 q_loadCiphersForConnection(connection: mySsl, ciphers, defaultCiphers);
245
246 q_SSL_CTX_free(a: myCtx);
247 q_SSL_free(a: mySsl);
248
249 setDefaultSupportedCiphers(ciphers);
250 setDefaultCiphers(defaultCiphers);
251
252#if QT_CONFIG(dtls)
253 ciphers.clear();
254 defaultCiphers.clear();
255 myCtx = q_SSL_CTX_new(a: q_DTLS_client_method());
256 if (myCtx) {
257 mySsl = q_SSL_new(a: myCtx);
258 if (mySsl) {
259 q_loadCiphersForConnection(connection: mySsl, ciphers, defaultCiphers);
260 setDefaultDtlsCiphers(defaultCiphers);
261 q_SSL_free(a: mySsl);
262 }
263 q_SSL_CTX_free(a: myCtx);
264 }
265#endif // dtls
266}
267
268QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
269{
270 QList<QSsl::SslProtocol> protocols;
271
272 protocols << QSsl::AnyProtocol;
273 protocols << QSsl::SecureProtocols;
274QT_WARNING_PUSH
275QT_WARNING_DISABLE_DEPRECATED
276 protocols << QSsl::TlsV1_0;
277 protocols << QSsl::TlsV1_0OrLater;
278 protocols << QSsl::TlsV1_1;
279 protocols << QSsl::TlsV1_1OrLater;
280QT_WARNING_POP
281 protocols << QSsl::TlsV1_2;
282 protocols << QSsl::TlsV1_2OrLater;
283
284#ifdef TLS1_3_VERSION
285 protocols << QSsl::TlsV1_3;
286 protocols << QSsl::TlsV1_3OrLater;
287#endif // TLS1_3_VERSION
288
289#if QT_CONFIG(dtls)
290QT_WARNING_PUSH
291QT_WARNING_DISABLE_DEPRECATED
292 protocols << QSsl::DtlsV1_0;
293 protocols << QSsl::DtlsV1_0OrLater;
294QT_WARNING_POP
295 protocols << QSsl::DtlsV1_2;
296 protocols << QSsl::DtlsV1_2OrLater;
297#endif // dtls
298
299 return protocols;
300}
301
302QList<QSsl::SupportedFeature> QTlsBackendOpenSSL::supportedFeatures() const
303{
304 QList<QSsl::SupportedFeature> features;
305
306 features << QSsl::SupportedFeature::CertificateVerification;
307
308#if !defined(OPENSSL_NO_TLSEXT)
309 features << QSsl::SupportedFeature::ClientSideAlpn;
310 features << QSsl::SupportedFeature::ServerSideAlpn;
311#endif // !OPENSSL_NO_TLSEXT
312
313 features << QSsl::SupportedFeature::Ocsp;
314 features << QSsl::SupportedFeature::Psk;
315 features << QSsl::SupportedFeature::SessionTicket;
316 features << QSsl::SupportedFeature::Alerts;
317
318 return features;
319}
320
321QList<QSsl::ImplementedClass> QTlsBackendOpenSSL::implementedClasses() const
322{
323 QList<QSsl::ImplementedClass> classes;
324
325 classes << QSsl::ImplementedClass::Key;
326 classes << QSsl::ImplementedClass::Certificate;
327 classes << QSsl::ImplementedClass::Socket;
328#if QT_CONFIG(dtls)
329 classes << QSsl::ImplementedClass::Dtls;
330 classes << QSsl::ImplementedClass::DtlsCookie;
331#endif
332 classes << QSsl::ImplementedClass::EllipticCurve;
333 classes << QSsl::ImplementedClass::DiffieHellman;
334
335 return classes;
336}
337
338QTlsPrivate::TlsKey *QTlsBackendOpenSSL::createKey() const
339{
340 return new QTlsPrivate::TlsKeyOpenSSL;
341}
342
343QTlsPrivate::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
344{
345 return new QTlsPrivate::X509CertificateOpenSSL;
346}
347
348namespace QTlsPrivate {
349
350#ifdef Q_OS_ANDROID
351QList<QByteArray> fetchSslCertificateData();
352#endif
353
354QList<QSslCertificate> systemCaCertificates();
355
356#ifndef Q_OS_DARWIN
357QList<QSslCertificate> systemCaCertificates()
358{
359#ifdef QSSLSOCKET_DEBUG
360 QElapsedTimer timer;
361 timer.start();
362#endif
363 QList<QSslCertificate> systemCerts;
364#if defined(Q_OS_WIN)
365 HCERTSTORE hSystemStore;
366 hSystemStore = CertOpenSystemStoreW(0, L"ROOT");
367 if (hSystemStore) {
368 PCCERT_CONTEXT pc = nullptr;
369 while (1) {
370 pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc);
371 if (!pc)
372 break;
373 QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded),
374 static_cast<int>(pc->cbCertEncoded));
375 QSslCertificate cert(der, QSsl::Der);
376 systemCerts.append(cert);
377 }
378 CertCloseStore(hSystemStore, 0);
379 }
380#elif defined(Q_OS_ANDROID)
381 const QList<QByteArray> certData = fetchSslCertificateData();
382 for (auto certDatum : certData)
383 systemCerts.append(QSslCertificate::fromData(certDatum, QSsl::Der));
384#elif defined(Q_OS_UNIX)
385 {
386 const QList<QByteArray> directories = QSslSocketPrivate::unixRootCertDirectories();
387 QSet<QString> certFiles = {
388 QStringLiteral("/etc/pki/tls/certs/ca-bundle.crt"), // Fedora, Mandriva
389 QStringLiteral("/usr/local/share/certs/ca-root-nss.crt") // FreeBSD's ca_root_nss
390 };
391 QDir currentDir;
392 currentDir.setNameFilters(QStringList{QStringLiteral("*.pem"), QStringLiteral("*.crt")});
393 for (const auto &directory : directories) {
394 currentDir.setPath(QLatin1StringView(directory));
395 QDirIterator it(currentDir);
396 while (it.hasNext()) {
397 // use canonical path here to not load the same certificate twice if symlinked
398 certFiles.insert(value: it.nextFileInfo().canonicalFilePath());
399 }
400 }
401 for (const QString& file : std::as_const(t&: certFiles))
402 systemCerts.append(other: QSslCertificate::fromPath(path: file, format: QSsl::Pem));
403 }
404#endif // platform
405#ifdef QSSLSOCKET_DEBUG
406 qCDebug(lcTlsBackend) << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
407 qCDebug(lcTlsBackend) << "imported " << systemCerts.count() << " certificates";
408#endif
409
410 return systemCerts;
411}
412#endif // !Q_OS_DARWIN
413} // namespace QTlsPrivate
414
415QList<QSslCertificate> QTlsBackendOpenSSL::systemCaCertificates() const
416{
417 return QTlsPrivate::systemCaCertificates();
418}
419
420QTlsPrivate::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier() const
421{
422#if QT_CONFIG(dtls)
423 return new QDtlsClientVerifierOpenSSL;
424#else
425 qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot verify DTLS cookies");
426 return nullptr;
427#endif // QT_CONFIG(dtls)
428}
429
430QTlsPrivate::TlsCryptograph *QTlsBackendOpenSSL::createTlsCryptograph() const
431{
432 return new QTlsPrivate::TlsCryptographOpenSSL;
433}
434
435QTlsPrivate::DtlsCryptograph *QTlsBackendOpenSSL::createDtlsCryptograph(QDtls *q, int mode) const
436{
437#if QT_CONFIG(dtls)
438 return new QDtlsPrivateOpenSSL(q, QSslSocket::SslMode(mode));
439#else
440 Q_UNUSED(q);
441 Q_UNUSED(mode);
442 qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot encrypt UDP datagrams");
443 return nullptr;
444#endif // QT_CONFIG(dtls)
445}
446
447QTlsPrivate::X509ChainVerifyPtr QTlsBackendOpenSSL::X509Verifier() const
448{
449 return QTlsPrivate::X509CertificateOpenSSL::verify;
450}
451
452QTlsPrivate::X509PemReaderPtr QTlsBackendOpenSSL::X509PemReader() const
453{
454 return QTlsPrivate::X509CertificateOpenSSL::certificatesFromPem;
455}
456
457QTlsPrivate::X509DerReaderPtr QTlsBackendOpenSSL::X509DerReader() const
458{
459 return QTlsPrivate::X509CertificateOpenSSL::certificatesFromDer;
460}
461
462QTlsPrivate::X509Pkcs12ReaderPtr QTlsBackendOpenSSL::X509Pkcs12Reader() const
463{
464 return QTlsPrivate::X509CertificateOpenSSL::importPkcs12;
465}
466
467QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
468{
469 QList<int> ids;
470
471#ifndef OPENSSL_NO_EC
472 const size_t curveCount = q_EC_get_builtin_curves(r: nullptr, nitems: 0);
473 QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount));
474
475 if (q_EC_get_builtin_curves(r: builtinCurves.data(), nitems: curveCount) == curveCount) {
476 ids.reserve(asize: curveCount);
477 for (const auto &ec : builtinCurves)
478 ids.push_back(t: ec.nid);
479 }
480#endif // OPENSSL_NO_EC
481
482 return ids;
483}
484
485 int QTlsBackendOpenSSL::curveIdFromShortName(const QString &name) const
486 {
487 int nid = 0;
488 if (name.isEmpty())
489 return nid;
490
491 ensureInitialized(); // TLSTODO: check if it's needed!
492#ifndef OPENSSL_NO_EC
493 const QByteArray curveNameLatin1 = name.toLatin1();
494 nid = q_OBJ_sn2nid(s: curveNameLatin1.data());
495
496 if (nid == 0)
497 nid = q_EC_curve_nist2nid(name: curveNameLatin1.data());
498#endif // !OPENSSL_NO_EC
499
500 return nid;
501 }
502
503 int QTlsBackendOpenSSL::curveIdFromLongName(const QString &name) const
504 {
505 int nid = 0;
506 if (name.isEmpty())
507 return nid;
508
509 ensureInitialized();
510
511#ifndef OPENSSL_NO_EC
512 const QByteArray curveNameLatin1 = name.toLatin1();
513 nid = q_OBJ_ln2nid(s: curveNameLatin1.data());
514#endif
515
516 return nid;
517 }
518
519 QString QTlsBackendOpenSSL::shortNameForId(int id) const
520 {
521 QString result;
522
523#ifndef OPENSSL_NO_EC
524 if (id != 0)
525 result = QString::fromLatin1(ba: q_OBJ_nid2sn(a: id));
526#endif
527
528 return result;
529 }
530
531QString QTlsBackendOpenSSL::longNameForId(int id) const
532{
533 QString result;
534
535#ifndef OPENSSL_NO_EC
536 if (id != 0)
537 result = QString::fromLatin1(ba: q_OBJ_nid2ln(a: id));
538#endif
539
540 return result;
541}
542
543// NIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
544// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
545static const int tlsNamedCurveNIDs[] = {
546 // RFC 4492
547 NID_sect163k1,
548 NID_sect163r1,
549 NID_sect163r2,
550 NID_sect193r1,
551 NID_sect193r2,
552 NID_sect233k1,
553 NID_sect233r1,
554 NID_sect239k1,
555 NID_sect283k1,
556 NID_sect283r1,
557 NID_sect409k1,
558 NID_sect409r1,
559 NID_sect571k1,
560 NID_sect571r1,
561
562 NID_secp160k1,
563 NID_secp160r1,
564 NID_secp160r2,
565 NID_secp192k1,
566 NID_X9_62_prime192v1, // secp192r1
567 NID_secp224k1,
568 NID_secp224r1,
569 NID_secp256k1,
570 NID_X9_62_prime256v1, // secp256r1
571 NID_secp384r1,
572 NID_secp521r1,
573
574 // RFC 7027
575 NID_brainpoolP256r1,
576 NID_brainpoolP384r1,
577 NID_brainpoolP512r1
578};
579
580const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
581
582bool QTlsBackendOpenSSL::isTlsNamedCurve(int id) const
583{
584 const int *const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
585 return std::find(first: tlsNamedCurveNIDs, last: tlsNamedCurveNIDsEnd, val: id) != tlsNamedCurveNIDsEnd;
586}
587
588QString QTlsBackendOpenSSL::msgErrorsDuringHandshake()
589{
590 return QSslSocket::tr(s: "Error during SSL handshake: %1").arg(a: getErrorsFromOpenSsl());
591}
592
593QSslCipher QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher)
594{
595 Q_ASSERT(cipher);
596 char buf [256] = {};
597 const QString desc = QString::fromLatin1(ba: q_SSL_CIPHER_description(a: cipher, b: buf, c: sizeof(buf)));
598 int supportedBits = 0;
599 const int bits = q_SSL_CIPHER_get_bits(a: cipher, b: &supportedBits);
600 return createCiphersuite(description: desc, bits, supportedBits);
601}
602
603void QTlsBackendOpenSSL::forceAutotestSecurityLevel()
604{
605 QSslContext::forceAutoTestSecurityLevel();
606}
607
608QT_END_NAMESPACE
609
610#include "moc_qtlsbackend_openssl_p.cpp"
611

source code of qtbase/src/plugins/tls/openssl/qtlsbackend_openssl.cpp