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