1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
3// Copyright (C) 2014 Governikus GmbH & Co. KG.
4// Copyright (C) 2016 Richard J. Moore <rich@kde.org>
5// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
6// Qt-Security score:critical reason:cryptography
7
8#include <QtNetwork/qsslsocket.h>
9#include <QtNetwork/qssldiffiehellmanparameters.h>
10
11#include "qsslsocket_openssl_symbols_p.h"
12#include "qsslcontext_openssl_p.h"
13#include "qtlsbackend_openssl_p.h"
14#include "qtlskey_openssl_p.h"
15#include "qopenssl_p.h"
16
17#include <QtNetwork/private/qssl_p.h>
18#include <QtNetwork/private/qsslsocket_p.h>
19#include <QtNetwork/private/qtlsbackend_p.h>
20
21#include <QtNetwork/private/qssldiffiehellmanparameters_p.h>
22
23#include <vector>
24
25QT_BEGIN_NAMESPACE
26
27Q_GLOBAL_STATIC(bool, forceSecurityLevel)
28
29namespace QTlsPrivate
30{
31// These callback functions are defined in qtls_openssl.cpp.
32int q_X509Callback(int ok, X509_STORE_CTX *ctx);
33int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
34
35#if QT_CONFIG(ocsp)
36int qt_OCSP_status_server_callback(SSL *ssl, void *);
37#endif // ocsp
38
39#ifdef TLS1_3_VERSION
40int q_ssl_sess_set_new_cb(SSL *context, SSL_SESSION *session);
41#endif // TLS1_3_VERSION
42
43} // namespace QTlsPrivate
44
45#if QT_CONFIG(dtls)
46// defined in qdtls_openssl.cpp:
47namespace dtlscallbacks
48{
49int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx);
50int q_generate_cookie_callback(SSL *ssl, unsigned char *dst, unsigned *cookieLength);
51int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie, unsigned cookieLength);
52} // namespace dtlscallbacks
53#endif // dtls
54
55static inline QString msgErrorSettingBackendConfig(const QString &why)
56{
57 return QSslSocket::tr(s: "Error when setting the OpenSSL configuration (%1)").arg(a: why);
58}
59
60static inline QString msgErrorSettingEllipticCurves(const QString &why)
61{
62 return QSslSocket::tr(s: "Error when setting the elliptic curves (%1)").arg(a: why);
63}
64
65qssloptions QSslContext::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
66{
67 qssloptions options;
68 switch (protocol) {
69QT_WARNING_PUSH
70QT_WARNING_DISABLE_DEPRECATED
71 case QSsl::TlsV1_0OrLater:
72 options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
73 break;
74 case QSsl::TlsV1_1OrLater:
75 options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
76 break;
77QT_WARNING_POP
78 case QSsl::SecureProtocols:
79 case QSsl::TlsV1_2OrLater:
80 options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
81 break;
82 case QSsl::TlsV1_3OrLater:
83 options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
84 break;
85 default:
86 options = SSL_OP_ALL;
87 }
88
89 // This option is disabled by default, so we need to be able to clear it
90 if (sslOptions & QSsl::SslOptionDisableEmptyFragments)
91 options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
92 else
93 options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
94
95#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
96 // This option is disabled by default, so we need to be able to clear it
97 if (sslOptions & QSsl::SslOptionDisableLegacyRenegotiation)
98 options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
99 else
100 options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
101#endif
102
103#ifdef SSL_OP_NO_TICKET
104 if (sslOptions & QSsl::SslOptionDisableSessionTickets)
105 options |= SSL_OP_NO_TICKET;
106#endif
107#ifdef SSL_OP_NO_COMPRESSION
108 if (sslOptions & QSsl::SslOptionDisableCompression)
109 options |= SSL_OP_NO_COMPRESSION;
110#endif
111
112 if (!(sslOptions & QSsl::SslOptionDisableServerCipherPreference))
113 options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
114
115 return options;
116}
117
118QSslContext::QSslContext()
119 : ctx(nullptr),
120 pkey(nullptr),
121 session(nullptr),
122 m_sessionTicketLifeTimeHint(-1)
123{
124}
125
126QSslContext::~QSslContext()
127{
128 if (ctx)
129 // This will decrement the reference count by 1 and free the context eventually when possible
130 q_SSL_CTX_free(a: ctx);
131
132 if (pkey)
133 q_EVP_PKEY_free(a: pkey);
134
135 if (session)
136 q_SSL_SESSION_free(ses: session);
137}
138
139std::shared_ptr<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
140{
141 struct AccessToPrivateCtor : QSslContext {};
142 std::shared_ptr<QSslContext> sslContext = std::make_shared<AccessToPrivateCtor>();
143 initSslContext(sslContext: sslContext.get(), mode, configuration, allowRootCertOnDemandLoading);
144 return sslContext;
145}
146
147std::shared_ptr<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
148 bool allowRootCertOnDemandLoading)
149{
150 return sharedFromConfiguration(mode, configuration: privConfiguration, allowRootCertOnDemandLoading);
151}
152
153#ifndef OPENSSL_NO_NEXTPROTONEG
154
155static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
156 const unsigned char *in, unsigned int inlen, void *arg)
157{
158 QSslContext::NPNContext *ctx = reinterpret_cast<QSslContext::NPNContext *>(arg);
159
160 // comment out to debug:
161// QList<QByteArray> supportedVersions;
162// for (unsigned int i = 0; i < inlen; ) {
163// QByteArray version(reinterpret_cast<const char *>(&in[i+1]), in[i]);
164// supportedVersions << version;
165// i += in[i] + 1;
166// }
167
168 int proto = q_SSL_select_next_proto(out, outlen, in, inlen, client: ctx->data, client_len: ctx->len);
169 switch (proto) {
170 case OPENSSL_NPN_UNSUPPORTED:
171 ctx->status = QSslConfiguration::NextProtocolNegotiationNone;
172 break;
173 case OPENSSL_NPN_NEGOTIATED:
174 ctx->status = QSslConfiguration::NextProtocolNegotiationNegotiated;
175 break;
176 case OPENSSL_NPN_NO_OVERLAP:
177 ctx->status = QSslConfiguration::NextProtocolNegotiationUnsupported;
178 break;
179 default:
180 qCWarning(lcTlsBackend, "OpenSSL sent unknown NPN status");
181 }
182
183 return SSL_TLSEXT_ERR_OK;
184}
185
186QSslContext::NPNContext QSslContext::npnContext() const
187{
188 return m_npnContext;
189}
190#endif // !OPENSSL_NO_NEXTPROTONEG
191
192
193
194// Needs to be deleted by caller
195SSL* QSslContext::createSsl()
196{
197 SSL* ssl = q_SSL_new(a: ctx);
198 q_SSL_clear(a: ssl);
199
200 if (!session && !sessionASN1().isEmpty()
201 && !sslConfiguration.testSslOption(option: QSsl::SslOptionDisableSessionPersistence)) {
202 const unsigned char *data = reinterpret_cast<const unsigned char *>(m_sessionASN1.constData());
203 session = q_d2i_SSL_SESSION(a: nullptr, pp: &data, length: m_sessionASN1.size());
204 // 'session' has refcount 1 already, set by the function above
205 }
206
207 if (session) {
208 // Try to resume the last session we cached
209 if (!q_SSL_set_session(to: ssl, session)) {
210 qCWarning(lcTlsBackend, "could not set SSL session");
211 q_SSL_SESSION_free(ses: session);
212 session = nullptr;
213 }
214 }
215
216#ifndef OPENSSL_NO_NEXTPROTONEG
217 QList<QByteArray> protocols = sslConfiguration.d.constData()->nextAllowedProtocols;
218 if (!protocols.isEmpty()) {
219 m_supportedNPNVersions.clear();
220 for (int a = 0; a < protocols.size(); ++a) {
221 if (protocols.at(i: a).size() > 255) {
222 qCWarning(lcTlsBackend) << "TLS NPN extension" << protocols.at(i: a)
223 << "is too long and will be ignored.";
224 continue;
225 } else if (protocols.at(i: a).isEmpty()) {
226 continue;
227 }
228 m_supportedNPNVersions.append(c: protocols.at(i: a).size()).append(a: protocols.at(i: a));
229 }
230 if (m_supportedNPNVersions.size()) {
231 m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data());
232 m_npnContext.len = m_supportedNPNVersions.size();
233 m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
234 // Callback's type has a parameter 'const unsigned char ** out'
235 // since it was introduced in 1.0.2. Internally, OpenSSL's own code
236 // (tests/examples) cast it to unsigned char * (since it's 'out').
237 // We just re-use our NPN callback and cast here:
238 typedef int (*alpn_callback_t) (SSL *, const unsigned char **, unsigned char *,
239 const unsigned char *, unsigned int, void *);
240 // With ALPN callback is for a server side only, for a client m_npnContext.status
241 // will stay in NextProtocolNegotiationNone.
242 q_SSL_CTX_set_alpn_select_cb(ctx, cb: alpn_callback_t(next_proto_cb), arg: &m_npnContext);
243 // Client:
244 q_SSL_set_alpn_protos(ssl, protos: m_npnContext.data, protos_len: m_npnContext.len);
245 // And in case our peer does not support ALPN, but supports NPN:
246 q_SSL_CTX_set_next_proto_select_cb(s: ctx, cb: next_proto_cb, arg: &m_npnContext);
247 }
248 }
249#endif // !OPENSSL_NO_NEXTPROTONEG
250
251 return ssl;
252}
253
254// We cache exactly one session here
255bool QSslContext::cacheSession(SSL* ssl)
256{
257 // don't cache the same session again
258 if (session && session == q_SSL_get_session(ssl))
259 return true;
260
261 // decrease refcount of currently stored session
262 // (this might happen if there are several concurrent handshakes in flight)
263 if (session)
264 q_SSL_SESSION_free(ses: session);
265
266 // cache the session the caller gave us and increase reference count
267 session = q_SSL_get1_session(ssl);
268
269 if (session && !sslConfiguration.testSslOption(option: QSsl::SslOptionDisableSessionPersistence)) {
270 int sessionSize = q_i2d_SSL_SESSION(in: session, pp: nullptr);
271 if (sessionSize > 0) {
272 m_sessionASN1.resize(size: sessionSize);
273 unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data());
274 if (!q_i2d_SSL_SESSION(in: session, pp: &data))
275 qCWarning(lcTlsBackend, "could not store persistent version of SSL session");
276 m_sessionTicketLifeTimeHint = q_SSL_SESSION_get_ticket_lifetime_hint(session);
277 }
278 }
279
280 return (session != nullptr);
281}
282
283QByteArray QSslContext::sessionASN1() const
284{
285 return m_sessionASN1;
286}
287
288void QSslContext::setSessionASN1(const QByteArray &session)
289{
290 m_sessionASN1 = session;
291}
292
293int QSslContext::sessionTicketLifeTimeHint() const
294{
295 return m_sessionTicketLifeTimeHint;
296}
297
298void QSslContext::forceAutoTestSecurityLevel()
299{
300 *forceSecurityLevel() = true;
301}
302
303QSslError::SslError QSslContext::error() const
304{
305 return errorCode;
306}
307
308QString QSslContext::errorString() const
309{
310 return errorStr;
311}
312
313void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode,
314 const QSslConfiguration &configuration,
315 bool allowRootCertOnDemandLoading)
316{
317 sslContext->sslConfiguration = configuration;
318 sslContext->errorCode = QSslError::NoError;
319
320 bool client = (mode == QSslSocket::SslClientMode);
321
322 bool reinitialized = false;
323 bool unsupportedProtocol = false;
324 bool isDtls = false;
325init_context:
326 switch (sslContext->sslConfiguration.protocol()) {
327QT_WARNING_PUSH
328QT_WARNING_DISABLE_DEPRECATED
329 case QSsl::DtlsV1_0:
330 case QSsl::DtlsV1_0OrLater:
331QT_WARNING_POP
332 case QSsl::DtlsV1_2:
333 case QSsl::DtlsV1_2OrLater:
334#if QT_CONFIG(dtls)
335 isDtls = true;
336 sslContext->ctx = q_SSL_CTX_new(a: client ? q_DTLS_client_method() : q_DTLS_server_method());
337#else // dtls
338 sslContext->ctx = nullptr;
339 unsupportedProtocol = true;
340 qCWarning(lcTlsBackend, "DTLS protocol requested, but feature 'dtls' is disabled");
341#endif // dtls
342 break;
343 case QSsl::TlsV1_3:
344 case QSsl::TlsV1_3OrLater:
345#if !defined(TLS1_3_VERSION)
346 qCWarning(lcTlsBackend, "TLS 1.3 is not supported");
347 sslContext->ctx = nullptr;
348 unsupportedProtocol = true;
349 break;
350#endif // TLS1_3_VERSION
351 default:
352 // The ssl options will actually control the supported methods
353 sslContext->ctx = q_SSL_CTX_new(a: client ? q_TLS_client_method() : q_TLS_server_method());
354 }
355
356 if (!sslContext->ctx) {
357 // After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them
358 // by re-initializing the library.
359 if (!reinitialized) {
360 reinitialized = true;
361 if (q_OPENSSL_init_ssl(opts: 0, settings: nullptr) == 1)
362 goto init_context;
363 }
364
365 sslContext->errorStr = QSslSocket::tr(s: "Error creating SSL context (%1)").arg(
366 a: unsupportedProtocol ? QSslSocket::tr(s: "unsupported protocol") : QTlsBackendOpenSSL::getErrorsFromOpenSsl()
367 );
368 sslContext->errorCode = QSslError::UnspecifiedError;
369 return;
370 }
371
372 // A nasty hacked OpenSSL using a level that will make our auto-tests fail:
373 if (q_SSL_CTX_get_security_level(ctx: sslContext->ctx) > 1 && *forceSecurityLevel())
374 q_SSL_CTX_set_security_level(ctx: sslContext->ctx, level: 1);
375
376 const long anyVersion =
377#if QT_CONFIG(dtls)
378 isDtls ? DTLS_ANY_VERSION : TLS_ANY_VERSION;
379#else
380 TLS_ANY_VERSION;
381#endif // dtls
382 long minVersion = anyVersion;
383 long maxVersion = anyVersion;
384
385 switch (sslContext->sslConfiguration.protocol()) {
386QT_WARNING_PUSH
387QT_WARNING_DISABLE_DEPRECATED
388 case QSsl::TlsV1_0:
389 minVersion = TLS1_VERSION;
390 maxVersion = TLS1_VERSION;
391 break;
392 case QSsl::TlsV1_1:
393 minVersion = TLS1_1_VERSION;
394 maxVersion = TLS1_1_VERSION;
395 break;
396QT_WARNING_POP
397 case QSsl::TlsV1_2:
398 minVersion = TLS1_2_VERSION;
399 maxVersion = TLS1_2_VERSION;
400 break;
401 case QSsl::TlsV1_3:
402#ifdef TLS1_3_VERSION
403 minVersion = TLS1_3_VERSION;
404 maxVersion = TLS1_3_VERSION;
405#else
406 // This protocol is not supported by OpenSSL 1.1 and we handle
407 // it as an error (see the code above).
408 Q_UNREACHABLE();
409#endif // TLS1_3_VERSION
410 break;
411 // Ranges:
412 case QSsl::AnyProtocol:
413QT_WARNING_PUSH
414QT_WARNING_DISABLE_DEPRECATED
415 case QSsl::TlsV1_0OrLater:
416 minVersion = TLS1_VERSION;
417 maxVersion = 0;
418 break;
419 case QSsl::TlsV1_1OrLater:
420 minVersion = TLS1_1_VERSION;
421 maxVersion = 0;
422 break;
423QT_WARNING_POP
424 case QSsl::SecureProtocols:
425 case QSsl::TlsV1_2OrLater:
426 minVersion = TLS1_2_VERSION;
427 maxVersion = 0;
428 break;
429QT_WARNING_PUSH
430QT_WARNING_DISABLE_DEPRECATED
431 case QSsl::DtlsV1_0:
432 minVersion = DTLS1_VERSION;
433 maxVersion = DTLS1_VERSION;
434 break;
435 case QSsl::DtlsV1_0OrLater:
436 minVersion = DTLS1_VERSION;
437 maxVersion = 0;
438 break;
439QT_WARNING_POP
440 case QSsl::DtlsV1_2:
441 minVersion = DTLS1_2_VERSION;
442 maxVersion = DTLS1_2_VERSION;
443 break;
444 case QSsl::DtlsV1_2OrLater:
445 minVersion = DTLS1_2_VERSION;
446 maxVersion = 0;
447 break;
448 case QSsl::TlsV1_3OrLater:
449#ifdef TLS1_3_VERSION
450 minVersion = TLS1_3_VERSION;
451 maxVersion = 0;
452 break;
453#else
454 // This protocol is not supported by OpenSSL 1.1 and we handle
455 // it as an error (see the code above).
456 Q_UNREACHABLE();
457 break;
458#endif // TLS1_3_VERSION
459 case QSsl::UnknownProtocol:
460 break;
461 }
462
463 if (minVersion != anyVersion
464 && !q_SSL_CTX_set_min_proto_version(sslContext->ctx, minVersion)) {
465 sslContext->errorStr = QSslSocket::tr(s: "Error while setting the minimal protocol version");
466 sslContext->errorCode = QSslError::UnspecifiedError;
467 return;
468 }
469
470 if (maxVersion != anyVersion
471 && !q_SSL_CTX_set_max_proto_version(sslContext->ctx, maxVersion)) {
472 sslContext->errorStr = QSslSocket::tr(s: "Error while setting the maximum protocol version");
473 sslContext->errorCode = QSslError::UnspecifiedError;
474 return;
475 }
476
477 // Enable bug workarounds.
478 const qssloptions options = setupOpenSslOptions(protocol: configuration.protocol(), sslOptions: configuration.d->sslOptions);
479 q_SSL_CTX_set_options(ctx: sslContext->ctx, op: options);
480
481 // Tell OpenSSL to release memory early
482 // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
483 q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
484
485 auto filterCiphers = [](const QList<QSslCipher> &ciphers, bool selectTls13)
486 {
487 QByteArray cipherString;
488
489 for (const QSslCipher &cipher : ciphers) {
490 const bool isTls13Cipher = cipher.protocol() == QSsl::TlsV1_3 || cipher.protocol() == QSsl::TlsV1_3OrLater;
491 if (selectTls13 != isTls13Cipher)
492 continue;
493
494 if (cipherString.size())
495 cipherString.append(c: ':');
496 cipherString.append(a: cipher.name().toLatin1());
497 }
498 return cipherString;
499 };
500
501 // Initialize ciphers
502 QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
503 if (ciphers.isEmpty())
504 ciphers = isDtls ? QTlsBackend::defaultDtlsCiphers() : QTlsBackend::defaultCiphers();
505
506 const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
507
508 if (preTls13Ciphers.size()) {
509 if (!q_SSL_CTX_set_cipher_list(a: sslContext->ctx, b: preTls13Ciphers.data())) {
510 sslContext->errorStr = QSslSocket::tr(s: "Invalid or empty cipher list (%1)").arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl());
511 sslContext->errorCode = QSslError::UnspecifiedError;
512 return;
513 }
514 }
515
516 const QByteArray tls13Ciphers = filterCiphers(ciphers, true);
517#ifdef TLS1_3_VERSION
518 if (tls13Ciphers.size()) {
519 if (!q_SSL_CTX_set_ciphersuites(ctx: sslContext->ctx, str: tls13Ciphers.data())) {
520 sslContext->errorStr = QSslSocket::tr(s: "Invalid or empty cipher list (%1)").arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl());
521 sslContext->errorCode = QSslError::UnspecifiedError;
522 return;
523 }
524 }
525#endif // TLS1_3_VERSION
526 if (!preTls13Ciphers.size() && !tls13Ciphers.size()) {
527 sslContext->errorStr = QSslSocket::tr(s: "Invalid or empty cipher list (%1)").arg(QStringLiteral(""));
528 sslContext->errorCode = QSslError::UnspecifiedError;
529 return;
530 }
531
532 const QDateTime now = QDateTime::currentDateTimeUtc();
533
534 // Add all our CAs to this store.
535 const auto caCertificates = sslContext->sslConfiguration.caCertificates();
536 for (const QSslCertificate &caCertificate : caCertificates) {
537 // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
538 //
539 // If several CA certificates matching the name, key identifier, and
540 // serial number condition are available, only the first one will be
541 // examined. This may lead to unexpected results if the same CA
542 // certificate is available with different expiration dates. If a
543 // ``certificate expired'' verification error occurs, no other
544 // certificate will be searched. Make sure to not have expired
545 // certificates mixed with valid ones.
546 //
547 // See also: QSslSocketBackendPrivate::verify()
548 if (caCertificate.expiryDate() >= now) {
549 q_X509_STORE_add_cert(ctx: q_SSL_CTX_get_cert_store(a: sslContext->ctx), x: (X509 *)caCertificate.handle());
550 }
551 }
552
553 if (QSslSocketPrivate::rootCertOnDemandLoadingSupported() && allowRootCertOnDemandLoading) {
554 // tell OpenSSL the directories where to look up the root certs on demand
555 const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
556 int success = 1;
557#if OPENSSL_VERSION_MAJOR < 3
558 for (const QByteArray &unixDir : unixDirs) {
559 if ((success = q_SSL_CTX_load_verify_locations(sslContext->ctx, nullptr, unixDir.constData())) != 1)
560 break;
561 }
562#else
563 for (const QByteArray &unixDir : unixDirs) {
564 if ((success = q_SSL_CTX_load_verify_dir(ctx: sslContext->ctx, CApath: unixDir.constData())) != 1)
565 break;
566 }
567#endif // OPENSSL_VERSION_MAJOR
568 if (success != 1) {
569 const auto qtErrors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
570 qCWarning(lcTlsBackend) << "An error encountered while to set root certificates location:"
571 << qtErrors;
572 }
573 }
574
575 if (!sslContext->sslConfiguration.localCertificate().isNull()) {
576 // Require a private key as well.
577 if (sslContext->sslConfiguration.privateKey().isNull()) {
578 sslContext->errorStr = QSslSocket::tr(s: "Cannot provide a certificate with no key");
579 sslContext->errorCode = QSslError::UnspecifiedError;
580 return;
581 }
582
583 // Load certificate
584 if (!q_SSL_CTX_use_certificate(a: sslContext->ctx, b: (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
585 sslContext->errorStr = QSslSocket::tr(s: "Error loading local certificate, %1").arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl());
586 sslContext->errorCode = QSslError::UnspecifiedError;
587 return;
588 }
589
590 if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
591 sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
592 } else {
593#ifdef OPENSSL_NO_DEPRECATED_3_0
594 auto qtKey = QTlsBackend::backend<QTlsPrivate::TlsKeyOpenSSL>(configuration.d->privateKey);
595 Q_ASSERT(qtKey);
596 sslContext->pkey = qtKey->genericKey;
597 Q_ASSERT(sslContext->pkey);
598 q_EVP_PKEY_up_ref(sslContext->pkey);
599#else
600 // Load private key
601 sslContext->pkey = q_EVP_PKEY_new();
602 // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
603 // this lead to a memory leak. Now we use the *_set1_* functions which do not
604 // take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
605 if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
606 q_EVP_PKEY_set1_RSA(a: sslContext->pkey, b: reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
607 else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
608 q_EVP_PKEY_set1_DSA(a: sslContext->pkey, b: reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
609#ifndef OPENSSL_NO_EC
610 else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
611 q_EVP_PKEY_set1_EC_KEY(a: sslContext->pkey, b: reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
612#endif // OPENSSL_NO_EC
613#endif // OPENSSL_NO_DEPRECATED_3_0
614 }
615 auto pkey = sslContext->pkey;
616 if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
617 sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
618
619 if (!q_SSL_CTX_use_PrivateKey(a: sslContext->ctx, b: pkey)) {
620 sslContext->errorStr = QSslSocket::tr(s: "Error loading private key, %1").arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl());
621 sslContext->errorCode = QSslError::UnspecifiedError;
622 return;
623 }
624
625 // Check if the certificate matches the private key.
626 if (!q_SSL_CTX_check_private_key(a: sslContext->ctx)) {
627 sslContext->errorStr = QSslSocket::tr(s: "Private key does not certify public key, %1").arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl());
628 sslContext->errorCode = QSslError::UnspecifiedError;
629 return;
630 }
631
632 // If we have any intermediate certificates then we need to add them to our chain
633 bool first = true;
634 for (const QSslCertificate &cert : std::as_const(t: configuration.d->localCertificateChain)) {
635 if (first) {
636 first = false;
637 continue;
638 }
639 q_SSL_CTX_ctrl(a: sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, c: 0,
640 d: q_X509_dup(a: reinterpret_cast<X509 *>(cert.handle())));
641 }
642 }
643
644 // Initialize peer verification, different callbacks, TLS/DTLS verification first
645 // (note, all these set_some_callback do not have return value):
646 if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
647 q_SSL_CTX_set_verify(a: sslContext->ctx, SSL_VERIFY_NONE, c: nullptr);
648 } else {
649 auto verificationCallback =
650 #if QT_CONFIG(dtls)
651 isDtls ? dtlscallbacks::q_X509DtlsCallback :
652 #endif // dtls
653 QTlsPrivate::q_X509Callback;
654
655 if (!isDtls && configuration.handshakeMustInterruptOnError())
656 verificationCallback = QTlsPrivate::q_X509CallbackDirect;
657
658 auto verificationMode = SSL_VERIFY_PEER;
659 if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
660 verificationMode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
661
662 q_SSL_CTX_set_verify(a: sslContext->ctx, b: verificationMode, c: verificationCallback);
663 }
664
665#ifdef TLS1_3_VERSION
666 // NewSessionTicket callback:
667 if (mode == QSslSocket::SslClientMode && !isDtls) {
668 q_SSL_CTX_sess_set_new_cb(ctx: sslContext->ctx, cb: QTlsPrivate::q_ssl_sess_set_new_cb);
669 q_SSL_CTX_set_session_cache_mode(sslContext->ctx, SSL_SESS_CACHE_CLIENT);
670 }
671
672#endif // TLS1_3_VERSION
673
674#if QT_CONFIG(dtls)
675 // DTLS cookies:
676 if (mode == QSslSocket::SslServerMode && isDtls && configuration.dtlsCookieVerificationEnabled()) {
677 q_SSL_CTX_set_cookie_generate_cb(ctx: sslContext->ctx, cb: dtlscallbacks::q_generate_cookie_callback);
678 q_SSL_CTX_set_cookie_verify_cb(ctx: sslContext->ctx, cb: dtlscallbacks::q_verify_cookie_callback);
679 }
680#endif // dtls
681
682 // Set verification depth.
683 if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
684 q_SSL_CTX_set_verify_depth(a: sslContext->ctx, b: sslContext->sslConfiguration.peerVerifyDepth());
685
686 // set persisted session if the user set it
687 if (!configuration.sessionTicket().isEmpty())
688 sslContext->setSessionASN1(configuration.sessionTicket());
689
690 // Set temp DH params
691 QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
692
693 if (!dhparams.isValid()) {
694 sslContext->errorStr = QSslSocket::tr(s: "Diffie-Hellman parameters are not valid");
695 sslContext->errorCode = QSslError::UnspecifiedError;
696 return;
697 }
698
699 if (dhparams.isEmpty()) {
700 q_SSL_CTX_set_dh_auto(sslContext->ctx, 1);
701 } else {
702#ifndef OPENSSL_NO_DEPRECATED_3_0
703 const QByteArray &params = dhparams.d->derData;
704 const char *ptr = params.constData();
705 DH *dh = q_d2i_DHparams(a: nullptr, pp: reinterpret_cast<const unsigned char **>(&ptr),
706 length: params.size());
707 if (dh == nullptr)
708 qFatal(msg: "q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
709 q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
710 q_DH_free(dh);
711#else
712 qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed");
713#endif
714 }
715
716#ifndef OPENSSL_NO_PSK
717 if (!client)
718 q_SSL_CTX_use_psk_identity_hint(ctx: sslContext->ctx, hint: sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
719#endif // !OPENSSL_NO_PSK
720
721 const auto qcurves = sslContext->sslConfiguration.ellipticCurves();
722 if (!qcurves.isEmpty()) {
723#ifdef OPENSSL_NO_EC
724 sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves"));
725 sslContext->errorCode = QSslError::UnspecifiedError;
726 return;
727#else
728 // Set the curves to be used.
729 std::vector<int> curves;
730 curves.reserve(n: qcurves.size());
731 for (const auto &sslCurve : qcurves)
732 curves.push_back(x: sslCurve.id);
733 if (!q_SSL_CTX_ctrl(a: sslContext->ctx, SSL_CTRL_SET_CURVES, c: long(curves.size()), d: &curves[0])) {
734 sslContext->errorStr = msgErrorSettingEllipticCurves(why: QTlsBackendOpenSSL::getErrorsFromOpenSsl());
735 sslContext->errorCode = QSslError::UnspecifiedError;
736 return;
737 }
738#endif
739 }
740
741 applyBackendConfig(sslContext);
742}
743
744void QSslContext::applyBackendConfig(QSslContext *sslContext)
745{
746 const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
747 if (conf.isEmpty())
748 return;
749
750#if QT_CONFIG(ocsp)
751 auto ocspResponsePos = conf.find(key: "Qt-OCSP-response");
752 if (ocspResponsePos != conf.end()) {
753 // This is our private, undocumented configuration option, existing only for
754 // the purpose of testing OCSP status responses. We don't even check this
755 // callback was set. If no - the test must fail.
756 q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, QTlsPrivate::qt_OCSP_status_server_callback);
757 if (conf.size() == 1)
758 return;
759 }
760#endif // ocsp
761
762 QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free);
763 if (cctx) {
764 q_SSL_CONF_CTX_set_ssl_ctx(a: cctx.data(), b: sslContext->ctx);
765 q_SSL_CONF_CTX_set_flags(a: cctx.data(), SSL_CONF_FLAG_FILE);
766
767 for (auto i = conf.constBegin(); i != conf.constEnd(); ++i) {
768 if (i.key() == "Qt-OCSP-response") // This never goes to SSL_CONF_cmd().
769 continue;
770
771 if (!i.value().canConvert(targetType: QMetaType(QMetaType::QByteArray))) {
772 sslContext->errorCode = QSslError::UnspecifiedError;
773 sslContext->errorStr = msgErrorSettingBackendConfig(
774 why: QSslSocket::tr(s: "Expecting QByteArray for %1").arg(a: i.key()));
775 return;
776 }
777
778 const QByteArray &value = i.value().toByteArray();
779 const int result = q_SSL_CONF_cmd(a: cctx.data(), b: i.key().constData(), c: value.constData());
780 if (result == 2)
781 continue;
782
783 sslContext->errorCode = QSslError::UnspecifiedError;
784 switch (result) {
785 case 0:
786 sslContext->errorStr = msgErrorSettingBackendConfig(
787 why: QSslSocket::tr(s: "An error occurred attempting to set %1 to %2")
788 .arg(args: i.key(), args: value));
789 return;
790 case 1:
791 sslContext->errorStr = msgErrorSettingBackendConfig(
792 why: QSslSocket::tr(s: "Wrong value for %1 (%2)").arg(args: i.key(), args: value));
793 return;
794 default:
795 sslContext->errorStr = msgErrorSettingBackendConfig(
796 why: QSslSocket::tr(s: "Unrecognized command %1 = %2").arg(args: i.key(), args: value));
797 return;
798 }
799 }
800
801 if (q_SSL_CONF_CTX_finish(a: cctx.data()) == 0) {
802 sslContext->errorStr = msgErrorSettingBackendConfig(why: QSslSocket::tr(s: "SSL_CONF_finish() failed"));
803 sslContext->errorCode = QSslError::UnspecifiedError;
804 }
805 } else {
806 sslContext->errorStr = msgErrorSettingBackendConfig(why: QSslSocket::tr(s: "SSL_CONF_CTX_new() failed"));
807 sslContext->errorCode = QSslError::UnspecifiedError;
808 }
809}
810
811QT_END_NAMESPACE
812

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