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