Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtls_st.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qtls_st_p.h"
6#include "qtlsbackend_st_p.h"
7#include "qtlskey_st_p.h"
8
9#include <QtNetwork/private/qssl_p.h>
10
11#include <QtNetwork/private/qsslcertificate_p.h>
12#include <QtNetwork/private/qsslcipher_p.h>
13#include <QtNetwork/private/qsslkey_p.h>
14
15#include <QtNetwork/qsslsocket.h>
16
17#include <QtCore/qmessageauthenticationcode.h>
18#include <QtCore/qoperatingsystemversion.h>
19#include <QtCore/qscopedvaluerollback.h>
20#include <QtCore/qcryptographichash.h>
21#include <QtCore/qsystemdetection.h>
22#include <QtCore/qdatastream.h>
23#include <QtCore/qsysinfo.h>
24#include <QtCore/qlist.h>
25#include <QtCore/qmutex.h>
26#include <QtCore/qdebug.h>
27#include <QtCore/quuid.h>
28#include <QtCore/qdir.h>
29
30#include <algorithm>
31#include <cstddef>
32#include <limits>
33#include <vector>
34
35#include <QtCore/private/qcore_mac_p.h>
36
37#ifdef Q_OS_MACOS
38#include <CoreServices/CoreServices.h>
39#endif
40
42
43using namespace Qt::StringLiterals;
44
45// Defined in qsslsocket_qt.cpp.
46QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
47 const QString &passPhrase);
48
49namespace QTlsPrivate {
50
51// Defined in qtlsbackend_st.cpp
52QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher);
53
54namespace {
55
56#ifdef Q_OS_MACOS
57/*
58
59Our own temporarykeychain is needed only on macOS where SecPKCS12Import changes
60the default keychain and where we see annoying pop-ups asking about accessing a
61private key.
62
63*/
64
65struct EphemeralSecKeychain
66{
67 EphemeralSecKeychain();
68 ~EphemeralSecKeychain();
69
70 SecKeychainRef keychain = nullptr;
71 Q_DISABLE_COPY_MOVE(EphemeralSecKeychain)
72};
73
74EphemeralSecKeychain::EphemeralSecKeychain()
75{
76 const auto uuid = QUuid::createUuid();
77 if (uuid.isNull()) {
78 qCWarning(lcSecureTransport) << "Failed to create a unique keychain name";
79 return;
80 }
81
82 const QByteArray uuidAsByteArray = uuid.toByteArray();
83 Q_ASSERT(uuidAsByteArray.size() > 2);
84 Q_ASSERT(uuidAsByteArray.startsWith('{'));
85 Q_ASSERT(uuidAsByteArray.endsWith('}'));
86 const auto uuidAsString = QLatin1StringView(uuidAsByteArray.data(), uuidAsByteArray.size()).mid(1, uuidAsByteArray.size() - 2);
87
88 const QString keychainName
89 = QDir::tempPath() + QDir::separator() + uuidAsString + ".keychain"_L1;
90 // SecKeychainCreate, pathName parameter:
91 //
92 // "A constant character string representing the POSIX path indicating where
93 // to store the keychain."
94 //
95 // Internally they seem to use std::string, but this does not really help.
96 // Fortunately, CFString has a convenient API.
97 QCFType<CFStringRef> cfName = keychainName.toCFString();
98 std::vector<char> posixPath;
99 // "Extracts the contents of a string as a NULL-terminated 8-bit string
100 // appropriate for passing to POSIX APIs."
101 posixPath.resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName));
102 const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
103 CFIndex(posixPath.size()));
104 if (!ok) {
105 qCWarning(lcSecureTransport) << "Failed to create a unique keychain name from"
106 << "QDir::tempPath()";
107 return;
108 }
109
110 std::vector<uint8_t> passUtf8(256);
111 if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) {
112 qCWarning(lcSecureTransport) << "SecRandomCopyBytes: failed to create a key";
113 return;
114 }
115
116 const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(),
117 &passUtf8[0], FALSE, nullptr,
118 &keychain);
119 if (status != errSecSuccess || !keychain) {
120 qCWarning(lcSecureTransport) << "SecKeychainCreate: failed to create a custom keychain";
121 if (keychain) {
122 SecKeychainDelete(keychain);
123 CFRelease(keychain);
124 keychain = nullptr;
125 }
126 }
127
128 if (keychain) {
129 SecKeychainSettings settings = {};
130 settings.version = SEC_KEYCHAIN_SETTINGS_VERS1;
131 // Strange, huh? But that's what their docs say to do! With lockOnSleep
132 // == false, set interval to INT_MAX to never lock ...
133 settings.lockInterval = INT_MAX;
134 if (SecKeychainSetSettings(keychain, &settings) != errSecSuccess)
135 qCWarning(lcSecureTransport) << "SecKeychainSettings: failed to disable lock on sleep";
136 }
137
138#ifdef QSSLSOCKET_DEBUG
139 if (keychain) {
140 qCDebug(lcSecureTransport) << "Custom keychain with name" << keychainName << "was created"
141 << "successfully";
142 }
143#endif
144}
145
146EphemeralSecKeychain::~EphemeralSecKeychain()
147{
148 if (keychain) {
149 // clear file off disk
150 SecKeychainDelete(keychain);
151 CFRelease(keychain);
152 }
153}
154
155#endif // Q_OS_MACOS
156
157void qt_releaseSecureTransportContext(SSLContextRef context)
158{
159 if (context)
160 CFRelease(context);
161}
162
163} // unnamed namespace
164
165// To be also used by qtlsbackend_st.cpp (thus not in unnamed namespace).
167{
168 const bool isServer = mode == QSslSocket::SslServerMode;
169 const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide;
170 // We never use kSSLDatagramType, so it's kSSLStreamType unconditionally.
171 SSLContextRef context = SSLCreateContext(nullptr, side, kSSLStreamType);
172 if (!context)
173 qCWarning(lcSecureTransport) << "SSLCreateContext failed";
174 return context;
175}
176
181
183{
184 qt_releaseSecureTransportContext(context);
185}
186
187QSecureTransportContext::operator SSLContextRef()const
188{
189 return context;
190}
191
192void QSecureTransportContext::reset(SSLContextRef newContext)
193{
194 qt_releaseSecureTransportContext(context);
195 context = newContext;
196}
197
198#if !defined(QT_PLATFORM_UIKIT) // dhparam is only used on macOS. (see the SSLSetDiffieHellmanParams call below)
199static const uint8_t dhparam[] =
200 "\x30\x82\x01\x08\x02\x82\x01\x01\x00\x97\xea\xd0\x46\xf7\xae\xa7\x76\x80"
201 "\x9c\x74\x56\x98\xd8\x56\x97\x2b\x20\x6c\x77\xe2\x82\xbb\xc8\x84\xbe\xe7"
202 "\x63\xaf\xcc\x30\xd0\x67\x97\x7d\x1b\xab\x59\x30\xa9\x13\x67\x21\xd7\xd4"
203 "\x0e\x46\xcf\xe5\x80\xdf\xc9\xb9\xba\x54\x9b\x46\x2f\x3b\x45\xfc\x2f\xaf"
204 "\xad\xc0\x17\x56\xdd\x52\x42\x57\x45\x70\x14\xe5\xbe\x67\xaa\xde\x69\x75"
205 "\x30\x0d\xf9\xa2\xc4\x63\x4d\x7a\x39\xef\x14\x62\x18\x33\x44\xa1\xf9\xc1"
206 "\x52\xd1\xb6\x72\x21\x98\xf8\xab\x16\x1b\x7b\x37\x65\xe3\xc5\x11\x00\xf6"
207 "\x36\x1f\xd8\x5f\xd8\x9f\x43\xa8\xce\x9d\xbf\x5e\xd6\x2d\xfa\x0a\xc2\x01"
208 "\x54\xc2\xd9\x81\x54\x55\xb5\x26\xf8\x88\x37\xf5\xfe\xe0\xef\x4a\x34\x81"
209 "\xdc\x5a\xb3\x71\x46\x27\xe3\xcd\x24\xf6\x1b\xf1\xe2\x0f\xc2\xa1\x39\x53"
210 "\x5b\xc5\x38\x46\x8e\x67\x4c\xd9\xdd\xe4\x37\x06\x03\x16\xf1\x1d\x7a\xba"
211 "\x2d\xc1\xe4\x03\x1a\x58\xe5\x29\x5a\x29\x06\x69\x61\x7a\xd8\xa9\x05\x9f"
212 "\xc1\xa2\x45\x9c\x17\xad\x52\x69\x33\xdc\x18\x8d\x15\xa6\x5e\xcd\x94\xf4"
213 "\x45\xbb\x9f\xc2\x7b\x85\x00\x61\xb0\x1a\xdc\x3c\x86\xaa\x9f\x5c\x04\xb3"
214 "\x90\x0b\x35\x64\xff\xd9\xe3\xac\xf2\xf2\xeb\x3a\x63\x02\x01\x02";
215#endif
216
217OSStatus TlsCryptographSecureTransport::ReadCallback(TlsCryptographSecureTransport *socket,
218 char *data, size_t *dataLength)
219{
221 Q_ASSERT(data);
222 Q_ASSERT(dataLength);
223
224 Q_ASSERT(socket->d);
225 QTcpSocket *plainSocket = socket->d->plainTcpSocket();
226 Q_ASSERT(plainSocket);
227
228 if (socket->isHandshakeComplete()) {
229 // Check if it's a renegotiation attempt, when the handshake is complete, the
230 // session state is 'kSSLConnected':
231 SSLSessionState currentState = kSSLConnected;
232 const OSStatus result = SSLGetSessionState(socket->context, &currentState);
233 if (result != noErr) {
234 *dataLength = 0;
235 return result;
236 }
237
238 if (currentState == kSSLHandshake) {
239 // Renegotiation detected, don't allow read more yet - 'transmit'
240 // will notice this and will call 'startHandshake':
241 *dataLength = 0;
242 socket->renegotiating = true;
243 return errSSLWouldBlock;
244 }
245 }
246
247 const qint64 bytes = plainSocket->read(data, *dataLength);
248#ifdef QSSLSOCKET_DEBUG
249 qCDebug(lcSecureTransport) << plainSocket << "read" << bytes;
250#endif
251 if (bytes < 0) {
252 *dataLength = 0;
253 return errSecIO;
254 }
255
256 const OSStatus err = (size_t(bytes) < *dataLength) ? OSStatus(errSSLWouldBlock) : OSStatus(errSecSuccess);
257 *dataLength = bytes;
258
259 return err;
260}
261
262OSStatus TlsCryptographSecureTransport::WriteCallback(TlsCryptographSecureTransport *socket,
263 const char *data, size_t *dataLength)
264{
266 Q_ASSERT(data);
267 Q_ASSERT(dataLength);
268
269 Q_ASSERT(socket->d);
270 QTcpSocket *plainSocket = socket->d->plainTcpSocket();
271 Q_ASSERT(plainSocket);
272
273 const qint64 bytes = plainSocket->write(data, *dataLength);
274#ifdef QSSLSOCKET_DEBUG
275 qCDebug(lcSecureTransport) << plainSocket << "write" << bytes;
276#endif
277 if (bytes < 0) {
278 *dataLength = 0;
279 return errSecIO;
280 }
281
282 const OSStatus err = (size_t(bytes) < *dataLength) ? OSStatus(errSSLWouldBlock) : OSStatus(errSecSuccess);
283 *dataLength = bytes;
284
285 return err;
286}
287
292
297
299{
300 Q_ASSERT(qObj);
301 Q_ASSERT(dObj);
302 q = qObj;
303 d = dObj;
304
305 renegotiating = false;
306 shutdown = false;
307}
308
310{
311 Q_ASSERT(q);
312 Q_ASSERT(d);
313 d->setEncrypted(true);
314#ifdef QSSLSOCKET_DEBUG
315 qCDebug(lcSecureTransport) << d->plainTcpSocket() << "connection encrypted";
316#endif
317
318 // Unlike OpenSSL, Secure Transport does not allow to negotiate protocols via
319 // a callback during handshake. We can only set our list of preferred protocols
320 // (and send it during handshake) and then receive what our peer has sent to us.
321 // And here we can finally try to find a match (if any).
322 const auto &configuration = q->sslConfiguration();
323 const auto &requestedProtocols = configuration.allowedNextProtocols();
324 if (const int requestedCount = requestedProtocols.size()) {
325 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
326 QTlsBackend::setNegotiatedProtocol(d, {});
327
328 QCFType<CFArrayRef> cfArray;
329 const OSStatus result = SSLCopyALPNProtocols(context, &cfArray);
330 if (result == errSecSuccess && cfArray && CFArrayGetCount(cfArray)) {
331 const int size = CFArrayGetCount(cfArray);
332 QList<QString> peerProtocols(size);
333 for (int i = 0; i < size; ++i)
334 peerProtocols[i] = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(cfArray, i));
335
336 for (int i = 0; i < requestedCount; ++i) {
337 const auto requestedName = QString::fromLatin1(requestedProtocols[i]);
338 for (int j = 0; j < size; ++j) {
339 if (requestedName == peerProtocols[j]) {
340 QTlsBackend::setNegotiatedProtocol(d, requestedName.toLatin1());
341 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
342 break;
343 }
344 }
345 if (configuration.nextProtocolNegotiationStatus() == QSslConfiguration::NextProtocolNegotiationNegotiated)
346 break;
347 }
348 }
349 }
350
351 if (!renegotiating)
352 emit q->encrypted();
353
354 if (d->isAutoStartingHandshake() && d->isPendingClose()) {
355 d->setPendingClose(false);
356 q->disconnectFromHost();
357 }
358}
359
361{
362 Q_ASSERT(d && d->plainTcpSocket());
363 d->setEncrypted(false);
364 if (d->plainTcpSocket()->bytesAvailable() <= 0)
365 destroySslContext();
366 // If there is still buffered data in the plain socket, don't destroy the ssl context yet.
367 // It will be destroyed when the socket is deleted.
368}
369
371{
372 Q_ASSERT(d && d->plainTcpSocket());
373 if (context) {
374 if (!shutdown) {
375 SSLClose(context);
376 context.reset(nullptr);
377 shutdown = true;
378 }
379 }
381}
382
384{
385 SSLCipherSuite cipher = 0;
386 if (context && SSLGetNegotiatedCipher(context, &cipher) == errSecSuccess)
387 return QSslCipher_from_SSLCipherSuite(cipher);
388
389 return QSslCipher();
390}
391
393{
394 if (!context)
396
397 SSLProtocol protocol = kSSLProtocolUnknown;
398 const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
399 if (err != errSecSuccess) {
400 qCWarning(lcSecureTransport) << "SSLGetNegotiatedProtocolVersion failed:" << err;
402 }
403
404 switch (protocol) {
407 case kTLSProtocol1:
408 return QSsl::TlsV1_0;
409 case kTLSProtocol11:
410 return QSsl::TlsV1_1;
412 case kTLSProtocol12:
413 return QSsl::TlsV1_2;
414 case kTLSProtocol13:
415 return QSsl::TlsV1_3;
416 default:
418 }
419}
420
422{
423 if (!initSslContext()) {
424 Q_ASSERT(d);
425 // Error description/code were set, 'error' emitted
426 // by initSslContext, but OpenSSL socket also sets error,
427 // emits a signal twice, so ...
428 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
429 return;
430 }
431
432 startHandshake();
433}
434
436{
437 if (!initSslContext()) {
438 // Error description/code were set, 'error' emitted
439 // by initSslContext, but OpenSSL socket also sets error
440 // emits a signal twice, so ...
441 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
442 return;
443 }
444
445 startHandshake();
446}
447
449{
450 Q_ASSERT(q);
451 Q_ASSERT(d);
452
453 // If we don't have any SSL context, don't bother transmitting.
454 // Edit: if SSL session closed, don't bother either.
455 if (!context || shutdown)
456 return;
457
458 if (!isHandshakeComplete())
459 startHandshake();
460
461 auto &writeBuffer = d->tlsWriteBuffer();
462 if (isHandshakeComplete() && !writeBuffer.isEmpty()) {
463 qint64 totalBytesWritten = 0;
464 while (writeBuffer.nextDataBlockSize() > 0 && context) {
465 const size_t nextDataBlockSize = writeBuffer.nextDataBlockSize();
466 size_t writtenBytes = 0;
467 const OSStatus err = SSLWrite(context, writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
468#ifdef QSSLSOCKET_DEBUG
469 qCDebug(lcSecureTransport) << d->plainTcpSocket() << "SSLWrite returned" << err;
470#endif
471 if (err != errSecSuccess && err != errSSLWouldBlock) {
472 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
473 QStringLiteral("SSLWrite failed: %1").arg(err));
474 break;
475 }
476
477 if (writtenBytes) {
478 writeBuffer.free(writtenBytes);
479 totalBytesWritten += writtenBytes;
480 }
481
482 if (writtenBytes < nextDataBlockSize)
483 break;
484 }
485
486 if (totalBytesWritten > 0) {
487 // Don't emit bytesWritten() recursively.
488 auto &emittedBytesWritten = d->tlsEmittedBytesWritten();
489 if (!emittedBytesWritten) {
490 emittedBytesWritten = true;
491 emit q->bytesWritten(totalBytesWritten);
492 emittedBytesWritten = false;
493 }
494 emit q->channelBytesWritten(0, totalBytesWritten);
495 }
496 }
497
498 auto &buffer = d->tlsBuffer();
499 const auto readBufferMaxSize = d->maxReadBufferSize();
500 if (isHandshakeComplete()) {
501 QVarLengthArray<char, 4096> data;
502 while (context && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
503 size_t readBytes = 0;
504 data.resize(4096);
505 const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
506#ifdef QSSLSOCKET_DEBUG
507 qCDebug(lcSecureTransport) << d->plainTcpSocket() << "SSLRead returned" << err;
508#endif
509 if (err == errSSLClosedGraceful) {
510 shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
512 QSslSocket::tr("The TLS/SSL connection has been closed"));
513 break;
514 } else if (err != errSecSuccess && err != errSSLWouldBlock) {
515 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
516 QStringLiteral("SSLRead failed: %1").arg(err));
517 break;
518 }
519
520 if (err == errSSLWouldBlock && renegotiating) {
521 startHandshake();
522 break;
523 }
524
525 if (readBytes) {
526 buffer.append(data.constData(), readBytes);
527 if (bool *readyReadEmittedPointer = d->readyReadPointer())
528 *readyReadEmittedPointer = true;
529 emit q->readyRead();
530 emit q->channelReadyRead(0);
531 }
532
533 if (err == errSSLWouldBlock)
534 break;
535 }
536 }
537}
538
540{
541 if (ciph.name() == "AES128-SHA"_L1)
542 return TLS_RSA_WITH_AES_128_CBC_SHA;
543 if (ciph.name() == "DHE-RSA-AES128-SHA"_L1)
544 return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
545 if (ciph.name() == "AES256-SHA"_L1)
546 return TLS_RSA_WITH_AES_256_CBC_SHA;
547 if (ciph.name() == "DHE-RSA-AES256-SHA"_L1)
548 return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
549 if (ciph.name() == "ECDH-ECDSA-NULL-SHA"_L1)
550 return TLS_ECDH_ECDSA_WITH_NULL_SHA;
551 if (ciph.name() == "ECDH-ECDSA-RC4-SHA"_L1)
552 return TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
553 if (ciph.name() == "ECDH-ECDSA-DES-CBC3-SHA"_L1)
554 return TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
555 if (ciph.name() == "ECDH-ECDSA-AES128-SHA"_L1)
556 return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
557 if (ciph.name() == "ECDH-ECDSA-AES256-SHA"_L1)
558 return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
559 if (ciph.name() == "ECDH-ECDSA-RC4-SHA"_L1)
560 return TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
561 if (ciph.name() == "ECDH-ECDSA-DES-CBC3-SHA"_L1)
562 return TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
563 if (ciph.name() == "ECDH-ECDSA-AES128-SHA"_L1)
564 return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
565 if (ciph.name() == "ECDH-ECDSA-AES256-SHA"_L1)
566 return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
567 if (ciph.name() == "ECDH-RSA-NULL-SHA"_L1)
568 return TLS_ECDH_RSA_WITH_NULL_SHA;
569 if (ciph.name() == "ECDH-RSA-RC4-SHA"_L1)
570 return TLS_ECDH_RSA_WITH_RC4_128_SHA;
571 if (ciph.name() == "ECDH-RSA-DES-CBC3-SHA"_L1)
572 return TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
573 if (ciph.name() == "ECDH-RSA-AES128-SHA"_L1)
574 return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
575 if (ciph.name() == "ECDH-RSA-AES256-SHA"_L1)
576 return TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
577 if (ciph.name() == "ECDH-RSA-RC4-SHA"_L1)
578 return TLS_ECDHE_RSA_WITH_RC4_128_SHA;
579 if (ciph.name() == "ECDH-RSA-DES-CBC3-SHA"_L1)
580 return TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
581 if (ciph.name() == "ECDH-RSA-AES128-SHA"_L1)
582 return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
583 if (ciph.name() == "ECDH-RSA-AES256-SHA"_L1)
584 return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
585 if (ciph.name() == "DES-CBC3-SHA"_L1)
586 return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
587 if (ciph.name() == "AES128-SHA256"_L1)
588 return TLS_RSA_WITH_AES_128_CBC_SHA256;
589 if (ciph.name() == "AES256-SHA256"_L1)
590 return TLS_RSA_WITH_AES_256_CBC_SHA256;
591 if (ciph.name() == "DHE-RSA-DES-CBC3-SHA"_L1)
592 return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
593 if (ciph.name() == "DHE-RSA-AES128-SHA256"_L1)
594 return TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
595 if (ciph.name() == "DHE-RSA-AES256-SHA256"_L1)
596 return TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
597 if (ciph.name() == "AES256-GCM-SHA384"_L1)
598 return TLS_RSA_WITH_AES_256_GCM_SHA384;
599 if (ciph.name() == "ECDHE-ECDSA-AES128-SHA256"_L1)
600 return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
601 if (ciph.name() == "ECDHE-ECDSA-AES256-SHA384"_L1)
602 return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
603 if (ciph.name() == "ECDH-ECDSA-AES128-SHA256"_L1)
604 return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
605 if (ciph.name() == "ECDH-ECDSA-AES256-SHA384"_L1)
606 return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
607 if (ciph.name() == "ECDHE-RSA-AES128-SHA256"_L1)
608 return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
609 if (ciph.name() == "ECDHE-RSA-AES256-SHA384"_L1)
610 return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
611 if (ciph.name() == "ECDHE-RSA-AES256-SHA384"_L1)
612 return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
613 if (ciph.name() == "ECDHE-RSA-AES256-GCM-SHA384"_L1)
614 return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
615 if (ciph.name() == "AES128-GCM-SHA256"_L1)
616 return TLS_AES_128_GCM_SHA256;
617 if (ciph.name() == "AES256-GCM-SHA384"_L1)
618 return TLS_AES_256_GCM_SHA384;
619 if (ciph.name() == "CHACHA20-POLY1305-SHA256"_L1)
620 return TLS_CHACHA20_POLY1305_SHA256;
621 if (ciph.name() == "AES128-CCM-SHA256"_L1)
622 return TLS_AES_128_CCM_SHA256;
623 if (ciph.name() == "AES128-CCM8-SHA256"_L1)
624 return TLS_AES_128_CCM_8_SHA256;
625 if (ciph.name() == "ECDHE-ECDSA-AES128-GCM-SHA256"_L1)
626 return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
627 if (ciph.name() == "ECDHE-ECDSA-AES256-GCM-SHA384"_L1)
628 return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
629 if (ciph.name() == "ECDH-ECDSA-AES128-GCM-SHA256"_L1)
630 return TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
631 if (ciph.name() == "ECDH-ECDSA-AES256-GCM-SHA384"_L1)
632 return TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
633 if (ciph.name() == "ECDHE-RSA-AES128-GCM-SHA256"_L1)
634 return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
635 if (ciph.name() == "ECDH-RSA-AES128-GCM-SHA256"_L1)
636 return TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
637 if (ciph.name() == "ECDH-RSA-AES256-GCM-SHA384"_L1)
638 return TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
639 if (ciph.name() == "ECDHE-RSA-CHACHA20-POLY1305-SHA256"_L1)
640 return TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
641 if (ciph.name() == "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256"_L1)
642 return TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
643
644 return 0;
645}
646
647bool TlsCryptographSecureTransport::initSslContext()
648{
649 Q_ASSERT(q);
650 Q_ASSERT(d);
651
652 Q_ASSERT_X(!context, Q_FUNC_INFO, "invalid socket state, context is not null");
653 auto *plainSocket = d->plainTcpSocket();
654 Q_ASSERT(plainSocket);
655
656 const auto mode = d->tlsMode();
657
659 if (!context) {
660 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
661 return false;
662 }
663
664 const OSStatus err = SSLSetIOFuncs(context,
665 reinterpret_cast<SSLReadFunc>(&TlsCryptographSecureTransport::ReadCallback),
666 reinterpret_cast<SSLWriteFunc>(&TlsCryptographSecureTransport::WriteCallback));
667 if (err != errSecSuccess) {
668 destroySslContext();
669 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
670 QStringLiteral("SSLSetIOFuncs failed: %1").arg(err));
671 return false;
672 }
673
674 SSLSetConnection(context, this);
675
676 const auto &configuration = q->sslConfiguration();
678 && !configuration.localCertificateChain().isEmpty()) {
679 QString errorDescription;
681 if (!setSessionCertificate(errorDescription, errorCode)) {
682 destroySslContext();
683 setErrorAndEmit(d, errorCode, errorDescription);
684 return false;
685 }
686 }
687
688 if (!setSessionProtocol()) {
689 destroySslContext();
690 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Failed to set protocol version"));
691 return false;
692 }
693
694 const auto protocolNames = configuration.allowedNextProtocols();
695 QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
696 if (cfNames) {
697 for (const QByteArray &name : protocolNames) {
698 if (name.size() > 255) {
699 qCWarning(lcSecureTransport) << "TLS ALPN extension" << name
700 << "is too long and will be ignored.";
701 continue;
702 } else if (name.isEmpty()) {
703 continue;
704 }
705 QCFString cfName(QString::fromLatin1(name).toCFString());
706 CFArrayAppendValue(cfNames, cfName);
707 }
708
709 if (CFArrayGetCount(cfNames)) {
710 // Up to the application layer to check that negotiation
711 // failed, and handle this non-TLS error, we do not handle
712 // the result of this call as an error:
713 if (SSLSetALPNProtocols(context, cfNames) != errSecSuccess)
714 qCWarning(lcSecureTransport) << "SSLSetALPNProtocols failed - too long protocol names?";
715 }
716 } else {
717 qCWarning(lcSecureTransport) << "failed to allocate ALPN names array";
718 }
719
721 // enable Server Name Indication (SNI)
722 const auto verificationPeerName = d->verificationName();
723 QString tlsHostName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
724 if (tlsHostName.isEmpty())
725 tlsHostName = d->tlsHostName();
726
727 const QByteArray ace(QUrl::toAce(tlsHostName));
728 SSLSetPeerDomainName(context, ace.data(), ace.size());
729 // tell SecureTransport we handle peer verification ourselves
730 OSStatus err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnServerAuth, true);
731 if (err == errSecSuccess)
732 err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnCertRequested, true);
733
734 if (err != errSecSuccess) {
735 destroySslContext();
736 setErrorAndEmit(d, QSslSocket::SslInternalError,
737 QStringLiteral("SSLSetSessionOption failed: %1").arg(err));
738 return false;
739 }
740 //
741 } else {
742 if (configuration.peerVerifyMode() != QSslSocket::VerifyNone) {
743 // kAlwaysAuthenticate - always fails even if we set break on client auth.
744 OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
745 if (err == errSecSuccess) {
746 // We'd like to verify peer ourselves, otherwise handshake will
747 // most probably fail before we can do anything.
748 err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnClientAuth, true);
749 }
750
751 if (err != errSecSuccess) {
752 destroySslContext();
753 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
754 QStringLiteral("failed to set SSL context option in server mode: %1").arg(err));
755 return false;
756 }
757 }
758#if !defined(QT_PLATFORM_UIKIT)
759 // No SSLSetDiffieHellmanParams on iOS; calling it is optional according to docs.
760 SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
761#endif
762 }
763 if (configuration.ciphers().size() > 0) {
764 QVector<SSLCipherSuite> cfCiphers;
765 for (const QSslCipher &cipher : configuration.ciphers()) {
767 cfCiphers << sslCipher;
768 }
769 if (cfCiphers.size() == 0) {
770 qCWarning(lcSecureTransport) << "failed to add any of the requested ciphers from the configuration";
771 return false;
772 }
773 OSStatus err = SSLSetEnabledCiphers(context, cfCiphers.data(), cfCiphers.size());
774 if (err != errSecSuccess) {
775 qCWarning(lcSecureTransport) << "failed to set the ciphers from the configuration";
776 return false;
777 }
778 }
779 return true;
780}
781
782void TlsCryptographSecureTransport::destroySslContext()
783{
784 context.reset(nullptr);
785}
786
787bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescription, QAbstractSocket::SocketError &errorCode)
788{
789 Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
790
791 Q_ASSERT(d);
792 const auto &configuration = q->sslConfiguration();
793
794#ifdef QSSLSOCKET_DEBUG
795 auto *plainSocket = d->plainTcpSocket();
796#endif
797
798 QSslCertificate localCertificate;
799
800 if (!configuration.localCertificateChain().isEmpty())
801 localCertificate = configuration.localCertificateChain().at(0);
802
803 if (!localCertificate.isNull()) {
804 // Require a private key as well.
805 if (configuration.privateKey().isNull()) {
807 errorDescription = QStringLiteral("Cannot provide a certificate with no key");
808 return false;
809 }
810
811 // import certificates and key
812 const QString passPhrase(QString::fromLatin1("foobar"));
813 QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain(),
814 configuration.privateKey(), passPhrase).toCFData();
815 QCFType<CFStringRef> password = passPhrase.toCFString();
816 const void *keys[2] = { kSecImportExportPassphrase };
817 const void *values[2] = { password };
818 CFIndex nKeys = 1;
819#ifdef Q_OS_MACOS
820 bool envOk = false;
821 const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk);
822 if (envOk && env) {
823 static const EphemeralSecKeychain temporaryKeychain;
824 if (temporaryKeychain.keychain) {
825 nKeys = 2;
826 keys[1] = kSecImportExportKeychain;
827 values[1] = temporaryKeychain.keychain;
828 }
829 }
830#endif
831 QCFType<CFDictionaryRef> options = CFDictionaryCreate(nullptr, keys, values, nKeys,
832 nullptr, nullptr);
833 QCFType<CFArrayRef> items;
834 OSStatus err = SecPKCS12Import(pkcs12, options, &items);
835 if (err != errSecSuccess) {
836#ifdef QSSLSOCKET_DEBUG
837 qCWarning(lcSecureTransport) << plainSocket
838 << QStringLiteral("SecPKCS12Import failed: %1").arg(err);
839#endif
841 errorDescription = QStringLiteral("SecPKCS12Import failed: %1").arg(err);
842 return false;
843 }
844
845 if (!CFArrayGetCount(items)) {
846#ifdef QSSLSOCKET_DEBUG
847 qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no items";
848#endif
850 errorDescription = QStringLiteral("SecPKCS12Import returned no items");
851 return false;
852 }
853
854 CFDictionaryRef import = (CFDictionaryRef)CFArrayGetValueAtIndex(items, 0);
855 SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(import, kSecImportItemIdentity);
856 if (!identity) {
857#ifdef QSSLSOCKET_DEBUG
858 qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no identity";
859#endif
861 errorDescription = QStringLiteral("SecPKCS12Import returned no identity");
862 return false;
863 }
864
865 QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
866 if (!certs) {
868 errorDescription = QStringLiteral("Failed to allocate certificates array");
869 return false;
870 }
871
872 CFArrayAppendValue(certs, identity);
873
874 CFArrayRef chain = (CFArrayRef)CFDictionaryGetValue(import, kSecImportItemCertChain);
875 if (chain) {
876 for (CFIndex i = 1, e = CFArrayGetCount(chain); i < e; ++i)
877 CFArrayAppendValue(certs, CFArrayGetValueAtIndex(chain, i));
878 }
879
880 err = SSLSetCertificate(context, certs);
881 if (err != errSecSuccess) {
882#ifdef QSSLSOCKET_DEBUG
883 qCWarning(lcSecureTransport) << plainSocket
884 << QStringLiteral("Cannot set certificate and key: %1").arg(err);
885#endif
887 errorDescription = QStringLiteral("Cannot set certificate and key: %1").arg(err);
888 return false;
889 }
890 }
891
892 return true;
893}
894
895bool TlsCryptographSecureTransport::setSessionProtocol()
896{
897 Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
898 Q_ASSERT(q);
899 Q_ASSERT(d);
900 // SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
901 // Calling SSLSetProtocolVersionMax/Min with any of these two constants results
902 // in errInvalidParam and a failure to set the protocol version. This means
903 // no TLS 1.3 on macOS and iOS.
904 const auto &configuration = q->sslConfiguration();
905 auto *plainSocket = d->plainTcpSocket();
906 switch (configuration.protocol()) {
907 case QSsl::TlsV1_3:
909 qCWarning(lcSecureTransport) << plainSocket << "SecureTransport does not support TLS 1.3";
910 return false;
911 default:;
912 }
913
914 OSStatus err = errSecSuccess;
915
918 if (configuration.protocol() == QSsl::TlsV1_0) {
919 #ifdef QSSLSOCKET_DEBUG
920 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.0";
921 #endif
922 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
923 if (err == errSecSuccess)
924 err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
925 } else if (configuration.protocol() == QSsl::TlsV1_1) {
926 #ifdef QSSLSOCKET_DEBUG
927 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.1";
928 #endif
929 err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
930 if (err == errSecSuccess)
931 err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
933 } else if (configuration.protocol() == QSsl::TlsV1_2) {
934 #ifdef QSSLSOCKET_DEBUG
935 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
936 #endif
937 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
938 if (err == errSecSuccess)
939 err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
940 } else if (configuration.protocol() == QSsl::AnyProtocol) {
941 #ifdef QSSLSOCKET_DEBUG
942 qCDebug(lcSecureTransport) << plainSocket << "requesting : any";
943 #endif
944 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
945 } else if (configuration.protocol() == QSsl::SecureProtocols) {
946 #ifdef QSSLSOCKET_DEBUG
947 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
948 #endif
949 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
952 } else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
953 #ifdef QSSLSOCKET_DEBUG
954 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1 - TLSv1.2";
955 #endif
956 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
957 } else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
958 #ifdef QSSLSOCKET_DEBUG
959 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
960 #endif
961 err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
963 } else if (configuration.protocol() == QSsl::TlsV1_2OrLater) {
964 #ifdef QSSLSOCKET_DEBUG
965 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
966 #endif
967 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
968 } else {
969 #ifdef QSSLSOCKET_DEBUG
970 qCDebug(lcSecureTransport) << plainSocket << "no protocol version found in the configuration";
971 #endif
972 return false;
973 }
974
975 return err == errSecSuccess;
976}
977
978bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
979{
980 Q_ASSERT(q);
981 Q_ASSERT(d);
982 const auto &configuration = q->sslConfiguration();
983 const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode();
985 && (verifyMode == QSslSocket::QueryPeer
986 || verifyMode == QSslSocket::AutoVerifyPeer
987 || verifyMode == QSslSocket::VerifyNone);
988}
989
990bool TlsCryptographSecureTransport::verifySessionProtocol() const
991{
992 Q_ASSERT(q);
993
994 const auto &configuration = q->sslConfiguration();
995 bool protocolOk = false;
996 if (configuration.protocol() == QSsl::AnyProtocol)
997 protocolOk = true;
998 else if (configuration.protocol() == QSsl::SecureProtocols)
999 protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
1002 else if (configuration.protocol() == QSsl::TlsV1_0OrLater)
1003 protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
1004 else if (configuration.protocol() == QSsl::TlsV1_1OrLater)
1005 protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
1007 else if (configuration.protocol() == QSsl::TlsV1_2OrLater)
1008 protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
1009 else if (configuration.protocol() == QSsl::TlsV1_3OrLater)
1010 protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
1011 else
1012 protocolOk = (sessionProtocol() == configuration.protocol());
1013
1014 return protocolOk;
1015}
1016
1017bool TlsCryptographSecureTransport::verifyPeerTrust()
1018{
1019 Q_ASSERT(q);
1020 Q_ASSERT(d);
1021
1022 const auto mode = d->tlsMode();
1023 const QSslSocket::PeerVerifyMode verifyMode = q->peerVerifyMode();
1024 const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
1025
1026 Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
1027
1028 auto *plainSocket = d->plainTcpSocket();
1029 Q_ASSERT(plainSocket);
1030
1031 QCFType<SecTrustRef> trust;
1032 OSStatus err = SSLCopyPeerTrust(context, &trust);
1033 // !trust - SSLCopyPeerTrust can return errSecSuccess but null trust.
1034 if (err != errSecSuccess || !trust) {
1035 if (!canIgnoreVerify) {
1037 QStringLiteral("Failed to obtain peer trust: %1").arg(err));
1038 plainSocket->disconnectFromHost();
1039 return false;
1040 } else {
1041 return true;
1042 }
1043 }
1044
1045 QList<QSslError> errors;
1046
1047 // Store certificates.
1048 // Apple's docs say SetTrustEvaluate must be called before
1049 // SecTrustGetCertificateAtIndex, but this results
1050 // in 'kSecTrustResultRecoverableTrustFailure', so
1051 // here we just ignore 'res' (later we'll use SetAnchor etc.
1052 // and evaluate again).
1053 SecTrustResultType res = kSecTrustResultInvalid;
1054 err = SecTrustEvaluate(trust, &res);
1055 if (err != errSecSuccess) {
1056 // We can not ignore this, it's not even about trust verification
1057 // probably ...
1059 QStringLiteral("SecTrustEvaluate failed: %1").arg(err));
1060 plainSocket->disconnectFromHost();
1061 return false;
1062 }
1063
1064 QTlsBackend::clearPeerCertificates(d);
1065
1066 QList<QSslCertificate> peerCertificateChain;
1067 const CFIndex certCount = SecTrustGetCertificateCount(trust);
1068 for (CFIndex i = 0; i < certCount; ++i) {
1069 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
1070 QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
1071 peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
1072 }
1073 QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
1074
1075 if (peerCertificateChain.size())
1076 QTlsBackend::storePeerCertificate(d, peerCertificateChain.at(0));
1077
1078 // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
1079 for (const QSslCertificate &cert : std::as_const(peerCertificateChain)) {
1080 if (QSslCertificatePrivate::isBlacklisted(cert) && !canIgnoreVerify) {
1082 errors << error;
1083 emit q->peerVerifyError(error);
1084 if (q->state() != QAbstractSocket::ConnectedState)
1085 return false;
1086 }
1087 }
1088
1089 const bool doVerifyPeer = verifyMode == QSslSocket::VerifyPeer
1090 || (verifyMode == QSslSocket::AutoVerifyPeer
1092 // Check the peer certificate itself. First try the subject's common name
1093 // (CN) as a wildcard, then try all alternate subject name DNS entries the
1094 // same way.
1095 const auto &peerCertificate = q->peerCertificate();
1096 if (!peerCertificate.isNull()) {
1097 // but only if we're a client connecting to a server
1098 // if we're the server, don't check CN
1099 const QString verificationPeerName = d->verificationName();
1101 const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
1102 if (!isMatchingHostname(peerCertificate, peerName) && !canIgnoreVerify) {
1103 // No matches in common names or alternate names.
1104 const QSslError error(QSslError::HostNameMismatch, peerCertificate);
1105 errors << error;
1106 emit q->peerVerifyError(error);
1107 if (q->state() != QAbstractSocket::ConnectedState)
1108 return false;
1109 }
1110 }
1111 } else {
1112 // No peer certificate presented. Report as error if the socket
1113 // expected one.
1114 if (doVerifyPeer && !canIgnoreVerify) {
1116 errors << error;
1117 emit q->peerVerifyError(error);
1118 if (q->state() != QAbstractSocket::ConnectedState)
1119 return false;
1120 }
1121 }
1122
1123 // verify certificate chain
1124 QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
1125 const auto &caCertificates = q->sslConfiguration().caCertificates();
1126 for (const QSslCertificate &cert : caCertificates) {
1127 QCFType<CFDataRef> certData = cert.toDer().toCFData();
1128 if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
1129 CFArrayAppendValue(certArray, secRef);
1130 }
1131
1132 SecTrustSetAnchorCertificates(trust, certArray);
1133
1134 // By default SecTrustEvaluate uses both CA certificates provided in
1135 // QSslConfiguration and the ones from the system database. This behavior can
1136 // be unexpected if a user's code tries to limit the trusted CAs to those
1137 // explicitly set in QSslConfiguration.
1138 // Since on macOS we initialize the default QSslConfiguration copying the
1139 // system CA certificates (using SecTrustSettingsCopyCertificates) we can
1140 // call SecTrustSetAnchorCertificatesOnly(trust, true) to force SecTrustEvaluate
1141 // to use anchors only from our QSslConfiguration.
1142 // Unfortunately, SecTrustSettingsCopyCertificates is not available on iOS
1143 // and the default QSslConfiguration always has an empty list of system CA
1144 // certificates. This leaves no way to provide client code with access to the
1145 // actual system CA certificate list (which most use-cases need) other than
1146 // by letting SecTrustEvaluate fall through to the system list; so, in this case
1147 // (even though the client code may have provided its own certs), we retain
1148 // the default behavior. Note, with macOS SDK below 10.12 using 'trust my
1149 // anchors only' may result in some valid chains rejected, apparently the
1150 // ones containing intermediated certificates; so we use this functionality
1151 // on more recent versions only.
1152
1153 bool anchorsFromConfigurationOnly = false;
1154
1155#ifdef Q_OS_MACOS
1157 anchorsFromConfigurationOnly = true;
1158#endif // Q_OS_MACOS
1159
1160 SecTrustSetAnchorCertificatesOnly(trust, anchorsFromConfigurationOnly);
1161
1162 SecTrustResultType trustResult = kSecTrustResultInvalid;
1163 SecTrustEvaluate(trust, &trustResult);
1164 switch (trustResult) {
1165 case kSecTrustResultUnspecified:
1166 case kSecTrustResultProceed:
1167 break;
1168 default:
1169 if (!canIgnoreVerify) {
1170 const QSslError error(QSslError::CertificateUntrusted, peerCertificate);
1171 errors << error;
1172 emit q->peerVerifyError(error);
1173 }
1174 }
1175
1176 // report errors
1177 if (!errors.isEmpty() && !canIgnoreVerify) {
1178 sslErrors = errors;
1179 // checkSslErrors unconditionally emits sslErrors:
1180 // a user's slot can abort/close/disconnect on this
1181 // signal, so we also test the socket's state:
1182 if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState)
1183 return false;
1184 } else {
1185 sslErrors.clear();
1186 }
1187
1188 return true;
1189}
1190
1191/*
1192 Copied verbatim from qsslsocket_openssl.cpp
1193*/
1194bool TlsCryptographSecureTransport::checkSslErrors()
1195{
1196 if (sslErrors.isEmpty())
1197 return true;
1198
1199 Q_ASSERT(q);
1200 Q_ASSERT(d);
1201
1202 emit q->sslErrors(sslErrors);
1203 const auto mode = d->tlsMode();
1204 const auto &configuration = q->sslConfiguration();
1205 const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
1206 || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
1208 const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
1209 // check whether we need to emit an SSL handshake error
1210 if (doVerifyPeer && doEmitSslError) {
1211 if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
1213 d->setPaused(true);
1214 } else {
1216 sslErrors.constFirst().errorString());
1219 }
1220 return false;
1221 }
1222
1223 return true;
1224}
1225
1226bool TlsCryptographSecureTransport::startHandshake()
1227{
1228 Q_ASSERT(context);
1229 Q_ASSERT(q);
1230 Q_ASSERT(d);
1231
1232 auto *plainSocket = d->plainTcpSocket();
1233 Q_ASSERT(plainSocket);
1234 const auto mode = d->tlsMode();
1235
1236 OSStatus err = SSLHandshake(context);
1237#ifdef QSSLSOCKET_DEBUG
1238 qCDebug(lcSecureTransport) << plainSocket << "SSLHandhake returned" << err;
1239#endif
1240
1241 if (err == errSSLWouldBlock) {
1242 // startHandshake has to be called again ... later.
1243 return false;
1244 } else if (err == errSSLServerAuthCompleted) {
1245 // errSSLServerAuthCompleted is a define for errSSLPeerAuthCompleted,
1246 // it works for both server/client modes.
1247 // In future we'll evaluate peer's trust at this point,
1248 // for now we just continue.
1249 // if (!verifyPeerTrust())
1250 // ...
1251 return startHandshake();
1252 } else if (err == errSSLClientCertRequested) {
1254 QString errorDescription;
1256 // setSessionCertificate does not fail if we have no certificate.
1257 // Failure means a real error (invalid certificate, no private key, etc).
1258 if (!setSessionCertificate(errorDescription, errorCode)) {
1259 setErrorAndEmit(d, errorCode, errorDescription);
1260 renegotiating = false;
1261 return false;
1262 } else {
1263 // We try to resume a handshake, even if have no
1264 // local certificates ... (up to server to deal with our failure).
1265 return startHandshake();
1266 }
1267 } else if (err != errSecSuccess) {
1268 if (err == errSSLBadCert && canIgnoreTrustVerificationFailure()) {
1269 // We're on the server side and client did not provide any
1270 // certificate. This is the new 'nice' error returned by
1271 // Security Framework after it was recently updated.
1272 return startHandshake();
1273 }
1274
1275 renegotiating = false;
1277 QStringLiteral("SSLHandshake failed: %1").arg(err));
1278 plainSocket->disconnectFromHost();
1279 return false;
1280 }
1281
1282 // Connection aborted during handshake phase.
1283 if (q->state() != QAbstractSocket::ConnectedState) {
1284 qCDebug(lcSecureTransport) << "connection aborted";
1285 renegotiating = false;
1286 return false;
1287 }
1288
1289 // check protocol version ourselves, as Secure Transport does not enforce
1290 // the requested min / max versions.
1291 if (!verifySessionProtocol()) {
1292 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError, QStringLiteral("Protocol version mismatch"));
1293 plainSocket->disconnectFromHost();
1294 renegotiating = false;
1295 return false;
1296 }
1297
1298 if (verifyPeerTrust()) {
1300 renegotiating = false;
1301 return true;
1302 } else {
1303 renegotiating = false;
1304 return false;
1305 }
1306}
1307
1308bool TlsCryptographSecureTransport::isHandshakeComplete() const
1309{
1310 Q_ASSERT(q);
1311 return q->isEncrypted() && !renegotiating;
1312}
1313
1315{
1316 return sslErrors;
1317}
1318
1319} // namespace QTlsPrivate
1320
qint64 bytesAvailable() const override
Returns the number of incoming bytes that are waiting to be read.
virtual void disconnectFromHost()
Attempts to close the socket.
SocketError
This enum describes the socket errors that can occur.
\inmodule QtCore
Definition qbytearray.h:57
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:209
static QString tempPath()
Returns the absolute canonical path of the system's temporary directory.
Definition qdir.cpp:2133
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
constexpr QLatin1StringView mid(qsizetype pos, qsizetype n=-1) const
bool isEmpty() const noexcept
Definition qlist.h:401
const T & constFirst() const noexcept
Definition qlist.h:647
void clear()
Definition qlist.h:434
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
static constexpr QOperatingSystemVersionBase MacOSSierra
\variable QOperatingSystemVersion::MacOSSierra
static Q_NETWORK_EXPORT bool isBlacklisted(const QSslCertificate &certificate)
The QSslCertificate class provides a convenient API for an X509 certificate.
bool isNull() const
Returns true if this is a null certificate (i.e., a certificate with no contents); otherwise returns ...
The QSslCipher class represents an SSL cryptographic cipher.
Definition qsslcipher.h:22
The QSslError class provides an SSL error.
Definition qsslerror.h:21
QString errorString() const
Returns a short localized human-readable description of the error.
@ CertificateBlacklisted
Definition qsslerror.h:49
@ HostNameMismatch
Definition qsslerror.h:47
@ CertificateUntrusted
Definition qsslerror.h:42
@ NoPeerCertificate
Definition qsslerror.h:46
The QSslKey class provides an interface for private and public keys.
Definition qsslkey.h:23
bool * readyReadPointer()
bool verifyErrorsHaveBeenIgnored()
void setEncrypted(bool enc)
QTcpSocket * plainTcpSocket() const
QString verificationName() const
bool isAutoStartingHandshake() const
qint64 maxReadBufferSize() const
bool & tlsEmittedBytesWritten()
QString tlsHostName() const
QRingBufferRef & tlsBuffer()
void setPaused(bool p)
void setPendingClose(bool pc)
static void pauseSocketNotifiers(QSslSocket *)
QRingBufferRef & tlsWriteBuffer()
QSslSocket::SslMode tlsMode() const
bool isPendingClose() const
The QSslSocket class provides an SSL encrypted socket for both clients and servers.
Definition qsslsocket.h:29
SslMode
Describes the connection modes available for QSslSocket.
Definition qsslsocket.h:33
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
The QTcpSocket class provides a TCP socket.
Definition qtcpsocket.h:18
void reset(SSLContextRef newContext)
Definition qtls_st.cpp:192
QSecureTransportContext(SSLContextRef context)
Definition qtls_st.cpp:177
QSslCipher sessionCipher() const override
Definition qtls_st.cpp:383
QList< QSslError > tlsErrors() const override
Definition qtls_st.cpp:1314
void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override
Definition qtls_st.cpp:298
QSsl::SslProtocol sessionProtocol() const override
Definition qtls_st.cpp:392
SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph)
Definition qtls_st.cpp:539
static QByteArray toAce(const QString &domain, AceProcessingOptions options={})
Definition qurl.cpp:3064
static QUuid createUuid()
On any platform other than Windows, this function returns a new UUID with variant QUuid::DCE and vers...
Definition quuid.cpp:997
@ Der
Definition qssl.h:30
SslProtocol
Describes the protocol of the cipher.
Definition qssl.h:50
@ TlsV1_2OrLater
Definition qssl.h:59
@ TlsV1_3
Definition qssl.h:66
@ TlsV1_3OrLater
Definition qssl.h:67
@ SecureProtocols
Definition qssl.h:55
@ TlsV1_2
Definition qssl.h:53
@ AnyProtocol
Definition qssl.h:54
@ UnknownProtocol
Definition qssl.h:69
Combined button and popup list for selecting options.
Namespace containing onternal types that TLS backends implement.
QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher)
static const uint8_t dhparam[]
Definition qtls_st.cpp:199
SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
Definition qtls_st.cpp:166
static void * context
#define QT_WARNING_POP
#define QT_WARNING_DISABLE_DEPRECATED
#define Q_FUNC_INFO
#define QT_WARNING_PUSH
DBusConnection const char DBusError * error
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLsizei GLsizei GLint * values
[15]
GLenum mode
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLuint name
GLuint res
const GLubyte * c
GLuint writeBuffer
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
SSL_CTX int void * arg
#define QStringLiteral(str)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
QByteArray _q_makePkcs12(const QList< QSslCertificate > &certs, const QSslKey &key, const QString &passPhrase)
QByteArray _q_makePkcs12(const QList< QSslCertificate > &certs, const QSslKey &key, const QString &passPhrase)
#define emit
long long qint64
Definition qtypes.h:60
QSettings settings("MySoft", "Star Runner")
[0]
QStringList keys
QObject::connect nullptr
QTcpSocket * socket
[1]
QList< QTreeWidgetItem * > items
QList< QSslCertificate > cert
[0]
const auto certs
[1]