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