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
10#include "qsslsocket_openssl_symbols_p.h"
11#include "qsslcontext_openssl_p.h"
12#include "qtlsbackend_openssl_p.h"
13#include "qtlskey_openssl_p.h"
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(s: "Error when setting the OpenSSL configuration (%1)").arg(a: why);
59}
60
61static inline QString msgErrorSettingEllipticCurves(const QString &why)
62{
63 return QSslSocket::tr(s: "Error when setting the elliptic curves (%1)").arg(a: 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
119QSslContext::QSslContext()
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
131 q_SSL_CTX_free(a: ctx);
132
133 if (pkey)
134 q_EVP_PKEY_free(a: pkey);
135
136 if (session)
137 q_SSL_SESSION_free(ses: 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: 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, configuration: 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, client: ctx->data, client_len: 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
187QSslContext::NPNContext QSslContext::npnContext() const
188{
189 return m_npnContext;
190}
191#endif // !OPENSSL_NO_NEXTPROTONEG
192
193
194
195// Needs to be deleted by caller
196SSL* QSslContext::createSsl()
197{
198 SSL* ssl = q_SSL_new(a: ctx);
199 q_SSL_clear(a: ssl);
200
201 if (!session && !sessionASN1().isEmpty()
202 && !sslConfiguration.testSslOption(option: QSsl::SslOptionDisableSessionPersistence)) {
203 const unsigned char *data = reinterpret_cast<const unsigned char *>(m_sessionASN1.constData());
204 session = q_d2i_SSL_SESSION(a: nullptr, pp: &data, length: 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(to: ssl, session)) {
211 qCWarning(lcTlsBackend, "could not set SSL session");
212 q_SSL_SESSION_free(ses: 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(i: a).size() > 255) {
223 qCWarning(lcTlsBackend) << "TLS NPN extension" << protocols.at(i: a)
224 << "is too long and will be ignored.";
225 continue;
226 } else if (protocols.at(i: a).isEmpty()) {
227 continue;
228 }
229 m_supportedNPNVersions.append(c: protocols.at(i: a).size()).append(a: protocols.at(i: 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, cb: alpn_callback_t(next_proto_cb), arg: &m_npnContext);
244 // Client:
245 q_SSL_set_alpn_protos(ssl, protos: m_npnContext.data, protos_len: 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(s: ctx, cb: next_proto_cb, arg: &m_npnContext);
248 }
249 }
250#endif // !OPENSSL_NO_NEXTPROTONEG
251
252 return ssl;
253}
254
255// We cache exactly one session here
256bool QSslContext::cacheSession(SSL* ssl)
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)
265 q_SSL_SESSION_free(ses: 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(option: QSsl::SslOptionDisableSessionPersistence)) {
271 int sessionSize = q_i2d_SSL_SESSION(in: session, pp: nullptr);
272 if (sessionSize > 0) {
273 m_sessionASN1.resize(size: sessionSize);
274 unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data());
275 if (!q_i2d_SSL_SESSION(in: session, pp: &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
284QByteArray QSslContext::sessionASN1() const
285{
286 return m_sessionASN1;
287}
288
289void QSslContext::setSessionASN1(const QByteArray &session)
290{
291 m_sessionASN1 = session;
292}
293
294int QSslContext::sessionTicketLifeTimeHint() const
295{
296 return m_sessionTicketLifeTimeHint;
297}
298
299void QSslContext::forceAutoTestSecurityLevel()
300{
301 *forceSecurityLevel() = true;
302}
303
304QSslError::SslError QSslContext::error() const
305{
306 return errorCode;
307}
308
309QString QSslContext::errorString() const
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(a: 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
354 sslContext->ctx = q_SSL_CTX_new(a: client ? q_TLS_client_method() : q_TLS_server_method());
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(opts: 0, settings: nullptr) == 1)
363 goto init_context;
364 }
365
366 sslContext->errorStr = QSslSocket::tr(s: "Error creating SSL context (%1)").arg(
367 a: unsupportedProtocol ? QSslSocket::tr(s: "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(ctx: sslContext->ctx) > 1 && *forceSecurityLevel())
375 q_SSL_CTX_set_security_level(ctx: sslContext->ctx, level: 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(s: "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(s: "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(protocol: configuration.protocol(), sslOptions: configuration.d->sslOptions);
480 q_SSL_CTX_set_options(ctx: sslContext->ctx, op: 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(c: ':');
497 cipherString.append(a: 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(a: sslContext->ctx, b: preTls13Ciphers.data())) {
511 sslContext->errorStr = QSslSocket::tr(s: "Invalid or empty cipher list (%1)").arg(a: 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(ctx: sslContext->ctx, str: tls13Ciphers.data())) {
521 sslContext->errorStr = QSslSocket::tr(s: "Invalid or empty cipher list (%1)").arg(a: 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(s: "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(ctx: q_SSL_CTX_get_cert_store(a: sslContext->ctx), x: (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(ctx: sslContext->ctx, CApath: 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(s: "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(a: sslContext->ctx, b: (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
586 sslContext->errorStr = QSslSocket::tr(s: "Error loading local certificate, %1").arg(a: 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(a: sslContext->pkey, b: reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
608 else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
609 q_EVP_PKEY_set1_DSA(a: sslContext->pkey, b: 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(a: sslContext->pkey, b: 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(a: sslContext->ctx, b: pkey)) {
621 sslContext->errorStr = QSslSocket::tr(s: "Error loading private key, %1").arg(a: 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(a: sslContext->ctx)) {
628 sslContext->errorStr = QSslSocket::tr(s: "Private key does not certify public key, %1").arg(a: 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(t: configuration.d->localCertificateChain)) {
636 if (first) {
637 first = false;
638 continue;
639 }
640 q_SSL_CTX_ctrl(a: sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, c: 0,
641 d: q_X509_dup(a: 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(a: sslContext->ctx, SSL_VERIFY_NONE, c: nullptr);
649 } else {
650 auto verificationCallback =
651 #if QT_CONFIG(dtls)
652 isDtls ? dtlscallbacks::q_X509DtlsCallback :
653 #endif // dtls
654 QTlsPrivate::q_X509Callback;
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(a: sslContext->ctx, b: verificationMode, c: 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(ctx: sslContext->ctx, cb: 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(ctx: sslContext->ctx, cb: dtlscallbacks::q_generate_cookie_callback);
679 q_SSL_CTX_set_cookie_verify_cb(ctx: sslContext->ctx, cb: 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(a: sslContext->ctx, b: 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(s: "Diffie-Hellman parameters are not valid");
696 sslContext->errorCode = QSslError::UnspecifiedError;
697 return;
698 }
699
700 if (!dhparams.isEmpty()) {
701#ifndef OPENSSL_NO_DEPRECATED_3_0
702 const QByteArray &params = dhparams.d->derData;
703 const char *ptr = params.constData();
704 DH *dh = q_d2i_DHparams(a: nullptr, pp: reinterpret_cast<const unsigned char **>(&ptr),
705 length: params.size());
706 if (dh == nullptr)
707 qFatal(msg: "q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
708 q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
709 q_DH_free(dh);
710#else
711 qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed");
712#endif
713 }
714
715#ifndef OPENSSL_NO_PSK
716 if (!client)
717 q_SSL_CTX_use_psk_identity_hint(ctx: sslContext->ctx, hint: sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
718#endif // !OPENSSL_NO_PSK
719
720 const auto qcurves = sslContext->sslConfiguration.ellipticCurves();
721 if (!qcurves.isEmpty()) {
722#ifdef OPENSSL_NO_EC
723 sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves"));
724 sslContext->errorCode = QSslError::UnspecifiedError;
725 return;
726#else
727 // Set the curves to be used.
728 std::vector<int> curves;
729 curves.reserve(n: qcurves.size());
730 for (const auto &sslCurve : qcurves)
731 curves.push_back(x: sslCurve.id);
732 if (!q_SSL_CTX_ctrl(a: sslContext->ctx, SSL_CTRL_SET_CURVES, c: long(curves.size()), d: &curves[0])) {
733 sslContext->errorStr = msgErrorSettingEllipticCurves(why: QTlsBackendOpenSSL::getErrorsFromOpenSsl());
734 sslContext->errorCode = QSslError::UnspecifiedError;
735 return;
736 }
737#endif
738 }
739
740 applyBackendConfig(sslContext);
741}
742
743void QSslContext::applyBackendConfig(QSslContext *sslContext)
744{
745 const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
746 if (conf.isEmpty())
747 return;
748
749#if QT_CONFIG(ocsp)
750 auto ocspResponsePos = conf.find(key: "Qt-OCSP-response");
751 if (ocspResponsePos != conf.end()) {
752 // This is our private, undocumented configuration option, existing only for
753 // the purpose of testing OCSP status responses. We don't even check this
754 // callback was set. If no - the test must fail.
755 q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, QTlsPrivate::qt_OCSP_status_server_callback);
756 if (conf.size() == 1)
757 return;
758 }
759#endif // ocsp
760
761 QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free);
762 if (cctx) {
763 q_SSL_CONF_CTX_set_ssl_ctx(a: cctx.data(), b: sslContext->ctx);
764 q_SSL_CONF_CTX_set_flags(a: cctx.data(), SSL_CONF_FLAG_FILE);
765
766 for (auto i = conf.constBegin(); i != conf.constEnd(); ++i) {
767 if (i.key() == "Qt-OCSP-response") // This never goes to SSL_CONF_cmd().
768 continue;
769
770 if (!i.value().canConvert(targetType: QMetaType(QMetaType::QByteArray))) {
771 sslContext->errorCode = QSslError::UnspecifiedError;
772 sslContext->errorStr = msgErrorSettingBackendConfig(
773 why: QSslSocket::tr(s: "Expecting QByteArray for %1").arg(
774 a: QString::fromUtf8(ba: 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").arg(
788 args: QString::fromUtf8(ba: i.key()), args: QString::fromUtf8(ba: value)));
789 return;
790 case 1:
791 sslContext->errorStr = msgErrorSettingBackendConfig(
792 why: QSslSocket::tr(s: "Wrong value for %1 (%2)").arg(
793 args: QString::fromUtf8(ba: i.key()), args: QString::fromUtf8(ba: value)));
794 return;
795 default:
796 sslContext->errorStr = msgErrorSettingBackendConfig(
797 why: QSslSocket::tr(s: "Unrecognized command %1 = %2").arg(
798 args: QString::fromUtf8(ba: i.key()), args: QString::fromUtf8(ba: value)));
799 return;
800 }
801 }
802
803 if (q_SSL_CONF_CTX_finish(a: cctx.data()) == 0) {
804 sslContext->errorStr = msgErrorSettingBackendConfig(why: QSslSocket::tr(s: "SSL_CONF_finish() failed"));
805 sslContext->errorCode = QSslError::UnspecifiedError;
806 }
807 } else {
808 sslContext->errorStr = msgErrorSettingBackendConfig(why: QSslSocket::tr(s: "SSL_CONF_CTX_new() failed"));
809 sslContext->errorCode = QSslError::UnspecifiedError;
810 }
811}
812
813QT_END_NAMESPACE
814

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