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 // Don't write close_notify to an already-invalid socket.
377 if (d->plainTcpSocket()->isValid())
378 SSLClose(context);
379 context.reset(nullptr);
380 shutdown = true;
381 }
382 }
383 d->plainTcpSocket()->disconnectFromHost();
384}
385
387{
388 SSLCipherSuite cipher = 0;
389 if (context && SSLGetNegotiatedCipher(context, &cipher) == errSecSuccess)
390 return QSslCipher_from_SSLCipherSuite(cipher);
391
392 return QSslCipher();
393}
394
396{
397 if (!context)
398 return QSsl::UnknownProtocol;
399
400 SSLProtocol protocol = kSSLProtocolUnknown;
401 const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
402 if (err != errSecSuccess) {
403 qCWarning(lcSecureTransport) << "SSLGetNegotiatedProtocolVersion failed:" << err;
404 return QSsl::UnknownProtocol;
405 }
406
407 switch (protocol) {
408QT_WARNING_PUSH
409QT_WARNING_DISABLE_DEPRECATED
410 case kTLSProtocol1:
411 return QSsl::TlsV1_0;
412 case kTLSProtocol11:
413 return QSsl::TlsV1_1;
414QT_WARNING_POP
415 case kTLSProtocol12:
416 return QSsl::TlsV1_2;
417 case kTLSProtocol13:
418 return QSsl::TlsV1_3;
419 default:
420 return QSsl::UnknownProtocol;
421 }
422}
423
425{
426 if (!initSslContext()) {
427 Q_ASSERT(d);
428 // Error description/code were set, 'error' emitted
429 // by initSslContext, but OpenSSL socket also sets error,
430 // emits a signal twice, so ...
431 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
432 return;
433 }
434
435 startHandshake();
436}
437
439{
440 if (!initSslContext()) {
441 // Error description/code were set, 'error' emitted
442 // by initSslContext, but OpenSSL socket also sets error
443 // emits a signal twice, so ...
444 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
445 return;
446 }
447
448 startHandshake();
449}
450
452{
453 Q_ASSERT(q);
454 Q_ASSERT(d);
455
456 // If we don't have any SSL context, don't bother transmitting.
457 // Edit: if SSL session closed, don't bother either.
458 if (!context || shutdown)
459 return;
460
461 if (!isHandshakeComplete())
462 startHandshake();
463
464 auto &writeBuffer = d->tlsWriteBuffer();
465 if (isHandshakeComplete() && !writeBuffer.isEmpty()) {
466 qint64 totalBytesWritten = 0;
467 while (writeBuffer.nextDataBlockSize() > 0 && context) {
468 const size_t nextDataBlockSize = writeBuffer.nextDataBlockSize();
469 size_t writtenBytes = 0;
470 const OSStatus err = SSLWrite(context, writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
471#ifdef QSSLSOCKET_DEBUG
472 qCDebug(lcSecureTransport) << d->plainTcpSocket() << "SSLWrite returned" << err;
473#endif
474 if (err != errSecSuccess && err != errSSLWouldBlock) {
475 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
476 QStringLiteral("SSLWrite failed: %1").arg(err));
477 break;
478 }
479
480 if (writtenBytes) {
481 writeBuffer.free(writtenBytes);
482 totalBytesWritten += writtenBytes;
483 }
484
485 if (writtenBytes < nextDataBlockSize)
486 break;
487 }
488
489 if (totalBytesWritten > 0) {
490 // Don't emit bytesWritten() recursively.
491 auto &emittedBytesWritten = d->tlsEmittedBytesWritten();
492 if (!emittedBytesWritten) {
493 emittedBytesWritten = true;
494 emit q->bytesWritten(totalBytesWritten);
495 emittedBytesWritten = false;
496 }
497 emit q->channelBytesWritten(0, totalBytesWritten);
498 }
499 }
500
501 auto &buffer = d->tlsBuffer();
502 const auto readBufferMaxSize = d->maxReadBufferSize();
503 if (isHandshakeComplete()) {
504 QVarLengthArray<char, 4096> data;
505 while (context && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
506 size_t readBytes = 0;
507 data.resize(4096);
508 const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
509#ifdef QSSLSOCKET_DEBUG
510 qCDebug(lcSecureTransport) << d->plainTcpSocket() << "SSLRead returned" << err;
511#endif
512 if (err == errSSLClosedGraceful) {
513 shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
514 setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
515 QSslSocket::tr("The TLS/SSL connection has been closed"));
516 break;
517 } else if (err != errSecSuccess && err != errSSLWouldBlock) {
518 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
519 QStringLiteral("SSLRead failed: %1").arg(err));
520 break;
521 }
522
523 if (err == errSSLWouldBlock && renegotiating) {
524 startHandshake();
525 break;
526 }
527
528 if (readBytes) {
529 buffer.append(data.constData(), readBytes);
530 if (bool *readyReadEmittedPointer = d->readyReadPointer())
531 *readyReadEmittedPointer = true;
532 emit q->readyRead();
533 emit q->channelReadyRead(0);
534 }
535
536 if (err == errSSLWouldBlock)
537 break;
538 }
539 }
540}
541
543{
544 if (ciph.name() == "AES128-SHA"_L1)
545 return TLS_RSA_WITH_AES_128_CBC_SHA;
546 if (ciph.name() == "DHE-RSA-AES128-SHA"_L1)
547 return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
548 if (ciph.name() == "AES256-SHA"_L1)
549 return TLS_RSA_WITH_AES_256_CBC_SHA;
550 if (ciph.name() == "DHE-RSA-AES256-SHA"_L1)
551 return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
552 if (ciph.name() == "ECDH-ECDSA-NULL-SHA"_L1)
553 return TLS_ECDH_ECDSA_WITH_NULL_SHA;
554 if (ciph.name() == "ECDH-ECDSA-RC4-SHA"_L1)
555 return TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
556 if (ciph.name() == "ECDH-ECDSA-DES-CBC3-SHA"_L1)
557 return TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
558 if (ciph.name() == "ECDH-ECDSA-AES128-SHA"_L1)
559 return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
560 if (ciph.name() == "ECDH-ECDSA-AES256-SHA"_L1)
561 return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
562 if (ciph.name() == "ECDH-ECDSA-RC4-SHA"_L1)
563 return TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
564 if (ciph.name() == "ECDH-ECDSA-DES-CBC3-SHA"_L1)
565 return TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
566 if (ciph.name() == "ECDH-ECDSA-AES128-SHA"_L1)
567 return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
568 if (ciph.name() == "ECDH-ECDSA-AES256-SHA"_L1)
569 return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
570 if (ciph.name() == "ECDH-RSA-NULL-SHA"_L1)
571 return TLS_ECDH_RSA_WITH_NULL_SHA;
572 if (ciph.name() == "ECDH-RSA-RC4-SHA"_L1)
573 return TLS_ECDH_RSA_WITH_RC4_128_SHA;
574 if (ciph.name() == "ECDH-RSA-DES-CBC3-SHA"_L1)
575 return TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
576 if (ciph.name() == "ECDH-RSA-AES128-SHA"_L1)
577 return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
578 if (ciph.name() == "ECDH-RSA-AES256-SHA"_L1)
579 return TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
580 if (ciph.name() == "ECDH-RSA-RC4-SHA"_L1)
581 return TLS_ECDHE_RSA_WITH_RC4_128_SHA;
582 if (ciph.name() == "ECDH-RSA-DES-CBC3-SHA"_L1)
583 return TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
584 if (ciph.name() == "ECDH-RSA-AES128-SHA"_L1)
585 return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
586 if (ciph.name() == "ECDH-RSA-AES256-SHA"_L1)
587 return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
588 if (ciph.name() == "DES-CBC3-SHA"_L1)
589 return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
590 if (ciph.name() == "AES128-SHA256"_L1)
591 return TLS_RSA_WITH_AES_128_CBC_SHA256;
592 if (ciph.name() == "AES256-SHA256"_L1)
593 return TLS_RSA_WITH_AES_256_CBC_SHA256;
594 if (ciph.name() == "DHE-RSA-DES-CBC3-SHA"_L1)
595 return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
596 if (ciph.name() == "DHE-RSA-AES128-SHA256"_L1)
597 return TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
598 if (ciph.name() == "DHE-RSA-AES256-SHA256"_L1)
599 return TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
600 if (ciph.name() == "AES256-GCM-SHA384"_L1)
601 return TLS_RSA_WITH_AES_256_GCM_SHA384;
602 if (ciph.name() == "ECDHE-ECDSA-AES128-SHA256"_L1)
603 return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
604 if (ciph.name() == "ECDHE-ECDSA-AES256-SHA384"_L1)
605 return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
606 if (ciph.name() == "ECDH-ECDSA-AES128-SHA256"_L1)
607 return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
608 if (ciph.name() == "ECDH-ECDSA-AES256-SHA384"_L1)
609 return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
610 if (ciph.name() == "ECDHE-RSA-AES128-SHA256"_L1)
611 return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
612 if (ciph.name() == "ECDHE-RSA-AES256-SHA384"_L1)
613 return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
614 if (ciph.name() == "ECDHE-RSA-AES256-SHA384"_L1)
615 return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
616 if (ciph.name() == "ECDHE-RSA-AES256-GCM-SHA384"_L1)
617 return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
618 if (ciph.name() == "AES128-GCM-SHA256"_L1)
619 return TLS_AES_128_GCM_SHA256;
620 if (ciph.name() == "AES256-GCM-SHA384"_L1)
621 return TLS_AES_256_GCM_SHA384;
622 if (ciph.name() == "CHACHA20-POLY1305-SHA256"_L1)
623 return TLS_CHACHA20_POLY1305_SHA256;
624 if (ciph.name() == "AES128-CCM-SHA256"_L1)
625 return TLS_AES_128_CCM_SHA256;
626 if (ciph.name() == "AES128-CCM8-SHA256"_L1)
627 return TLS_AES_128_CCM_8_SHA256;
628 if (ciph.name() == "ECDHE-ECDSA-AES128-GCM-SHA256"_L1)
629 return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
630 if (ciph.name() == "ECDHE-ECDSA-AES256-GCM-SHA384"_L1)
631 return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
632 if (ciph.name() == "ECDH-ECDSA-AES128-GCM-SHA256"_L1)
633 return TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
634 if (ciph.name() == "ECDH-ECDSA-AES256-GCM-SHA384"_L1)
635 return TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
636 if (ciph.name() == "ECDHE-RSA-AES128-GCM-SHA256"_L1)
637 return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
638 if (ciph.name() == "ECDH-RSA-AES128-GCM-SHA256"_L1)
639 return TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
640 if (ciph.name() == "ECDH-RSA-AES256-GCM-SHA384"_L1)
641 return TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
642 if (ciph.name() == "ECDHE-RSA-CHACHA20-POLY1305-SHA256"_L1)
643 return TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
644 if (ciph.name() == "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256"_L1)
645 return TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
646
647 return 0;
648}
649
650bool TlsCryptographSecureTransport::initSslContext()
651{
652 Q_ASSERT(q);
653 Q_ASSERT(d);
654
655 Q_ASSERT_X(!context, Q_FUNC_INFO, "invalid socket state, context is not null");
656 auto *plainSocket = d->plainTcpSocket();
657 Q_ASSERT(plainSocket);
658
659 const auto mode = d->tlsMode();
660
661 context.reset(qt_createSecureTransportContext(mode));
662 if (!context) {
663 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
664 return false;
665 }
666
667 const OSStatus err = SSLSetIOFuncs(context,
668 reinterpret_cast<SSLReadFunc>(&TlsCryptographSecureTransport::ReadCallback),
669 reinterpret_cast<SSLWriteFunc>(&TlsCryptographSecureTransport::WriteCallback));
670 if (err != errSecSuccess) {
671 destroySslContext();
672 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
673 QStringLiteral("SSLSetIOFuncs failed: %1").arg(err));
674 return false;
675 }
676
677 SSLSetConnection(context, this);
678
679 const auto &configuration = q->sslConfiguration();
680 if (mode == QSslSocket::SslServerMode
681 && !configuration.localCertificateChain().isEmpty()) {
682 QString errorDescription;
683 QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
684 if (!setSessionCertificate(errorDescription, errorCode)) {
685 destroySslContext();
686 setErrorAndEmit(d, errorCode, errorDescription);
687 return false;
688 }
689 }
690
691 if (!setSessionProtocol()) {
692 destroySslContext();
693 setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Failed to set protocol version"));
694 return false;
695 }
696
697 const auto protocolNames = configuration.allowedNextProtocols();
698 QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
699 if (cfNames) {
700 for (const QByteArray &name : protocolNames) {
701 if (name.size() > 255) {
702 qCWarning(lcSecureTransport) << "TLS ALPN extension" << name
703 << "is too long and will be ignored.";
704 continue;
705 } else if (name.isEmpty()) {
706 continue;
707 }
708 QCFString cfName(QString::fromLatin1(name).toCFString());
709 CFArrayAppendValue(cfNames, cfName);
710 }
711
712 if (CFArrayGetCount(cfNames)) {
713 // Up to the application layer to check that negotiation
714 // failed, and handle this non-TLS error, we do not handle
715 // the result of this call as an error:
716 if (SSLSetALPNProtocols(context, cfNames) != errSecSuccess)
717 qCWarning(lcSecureTransport) << "SSLSetALPNProtocols failed - too long protocol names?";
718 }
719 } else {
720 qCWarning(lcSecureTransport) << "failed to allocate ALPN names array";
721 }
722
723 if (mode == QSslSocket::SslClientMode) {
724 // enable Server Name Indication (SNI)
725 const auto verificationPeerName = d->verificationName();
726 QString tlsHostName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
727 if (tlsHostName.isEmpty())
728 tlsHostName = d->tlsHostName();
729
730 const QByteArray ace(QUrl::toAce(tlsHostName));
731 SSLSetPeerDomainName(context, ace.data(), ace.size());
732 // tell SecureTransport we handle peer verification ourselves
733 OSStatus err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnServerAuth, true);
734 if (err == errSecSuccess)
735 err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnCertRequested, true);
736
737 if (err != errSecSuccess) {
738 destroySslContext();
739 setErrorAndEmit(d, QSslSocket::SslInternalError,
740 QStringLiteral("SSLSetSessionOption failed: %1").arg(err));
741 return false;
742 }
743 //
744 } else {
745 if (configuration.peerVerifyMode() != QSslSocket::VerifyNone) {
746 // kAlwaysAuthenticate - always fails even if we set break on client auth.
747 OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
748 if (err == errSecSuccess) {
749 // We'd like to verify peer ourselves, otherwise handshake will
750 // most probably fail before we can do anything.
751 err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnClientAuth, true);
752 }
753
754 if (err != errSecSuccess) {
755 destroySslContext();
756 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
757 QStringLiteral("failed to set SSL context option in server mode: %1").arg(err));
758 return false;
759 }
760 }
761#if !defined(QT_PLATFORM_UIKIT)
762 // No SSLSetDiffieHellmanParams on iOS; calling it is optional according to docs.
763 SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
764#endif
765 }
766 if (configuration.ciphers().size() > 0) {
767 QVector<SSLCipherSuite> cfCiphers;
768 for (const QSslCipher &cipher : configuration.ciphers()) {
769 if (auto sslCipher = TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(cipher))
770 cfCiphers << sslCipher;
771 }
772 if (cfCiphers.size() == 0) {
773 qCWarning(lcSecureTransport) << "failed to add any of the requested ciphers from the configuration";
774 return false;
775 }
776 OSStatus err = SSLSetEnabledCiphers(context, cfCiphers.data(), cfCiphers.size());
777 if (err != errSecSuccess) {
778 qCWarning(lcSecureTransport) << "failed to set the ciphers from the configuration";
779 return false;
780 }
781 }
782 return true;
783}
784
785void TlsCryptographSecureTransport::destroySslContext()
786{
787 context.reset(nullptr);
788}
789
790bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescription, QAbstractSocket::SocketError &errorCode)
791{
792 Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
793
794 Q_ASSERT(d);
795 const auto &configuration = q->sslConfiguration();
796
797#ifdef QSSLSOCKET_DEBUG
798 auto *plainSocket = d->plainTcpSocket();
799#endif
800
801 QSslCertificate localCertificate;
802
803 if (!configuration.localCertificateChain().isEmpty())
804 localCertificate = configuration.localCertificateChain().at(0);
805
806 if (!localCertificate.isNull()) {
807 // Require a private key as well.
808 if (configuration.privateKey().isNull()) {
809 errorCode = QAbstractSocket::SslInvalidUserDataError;
810 errorDescription = QStringLiteral("Cannot provide a certificate with no key");
811 return false;
812 }
813
814 // import certificates and key
815 const QString passPhrase(QString::fromLatin1("foobar"));
816 QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain(),
817 configuration.privateKey(), passPhrase).toCFData();
818 QCFType<CFStringRef> password = passPhrase.toCFString();
819 const void *keys[2] = { kSecImportExportPassphrase };
820 const void *values[2] = { password };
821 CFIndex nKeys = 1;
822#ifdef Q_OS_MACOS
823#if QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(150000, 180000)
824 // Starting from macOS 15 our temporary keychain is ignored.
825 // We have to use kSecImportToMemoryOnly/kCFBooleanTrue key/value
826 // instead. This key is "memory" but looks like Security framework
827 // does not compare strings, but pointers instead, so we need an actual
828 // key/constant.
829 if (__builtin_available(macOS 15, *)) {
830 nKeys = 2;
831 keys[1] = kSecImportToMemoryOnly;
832 values[1] = kCFBooleanTrue;
833 } else {
834#else
835 {
836#endif
837 bool envOk = false;
838 const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk);
839 if (envOk && env) {
840 static const EphemeralSecKeychain temporaryKeychain;
841 if (temporaryKeychain.keychain) {
842 nKeys = 2;
843 keys[1] = kSecImportExportKeychain;
844 values[1] = temporaryKeychain.keychain;
845 }
846 }
847 }
848#endif // Q_OS_MACOS
849 QCFType<CFDictionaryRef> options = CFDictionaryCreate(nullptr, keys, values, nKeys,
850 nullptr, nullptr);
851 QCFType<CFArrayRef> items;
852 OSStatus err = SecPKCS12Import(pkcs12, options, &items);
853 if (err != errSecSuccess) {
854#ifdef QSSLSOCKET_DEBUG
855 qCWarning(lcSecureTransport) << plainSocket
856 << QStringLiteral("SecPKCS12Import failed: %1").arg(err);
857#endif
858 errorCode = QAbstractSocket::SslInvalidUserDataError;
859 errorDescription = QStringLiteral("SecPKCS12Import failed: %1").arg(err);
860 return false;
861 }
862
863 if (!CFArrayGetCount(items)) {
864#ifdef QSSLSOCKET_DEBUG
865 qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no items";
866#endif
867 errorCode = QAbstractSocket::SslInvalidUserDataError;
868 errorDescription = QStringLiteral("SecPKCS12Import returned no items");
869 return false;
870 }
871
872 CFDictionaryRef import = (CFDictionaryRef)CFArrayGetValueAtIndex(items, 0);
873 SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(import, kSecImportItemIdentity);
874 if (!identity) {
875#ifdef QSSLSOCKET_DEBUG
876 qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no identity";
877#endif
878 errorCode = QAbstractSocket::SslInvalidUserDataError;
879 errorDescription = QStringLiteral("SecPKCS12Import returned no identity");
880 return false;
881 }
882
883 QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
884 if (!certs) {
885 errorCode = QAbstractSocket::SslInternalError;
886 errorDescription = QStringLiteral("Failed to allocate certificates array");
887 return false;
888 }
889
890 CFArrayAppendValue(certs, identity);
891
892 CFArrayRef chain = (CFArrayRef)CFDictionaryGetValue(import, kSecImportItemCertChain);
893 if (chain) {
894 for (CFIndex i = 1, e = CFArrayGetCount(chain); i < e; ++i)
895 CFArrayAppendValue(certs, CFArrayGetValueAtIndex(chain, i));
896 }
897
898 err = SSLSetCertificate(context, certs);
899 if (err != errSecSuccess) {
900#ifdef QSSLSOCKET_DEBUG
901 qCWarning(lcSecureTransport) << plainSocket
902 << QStringLiteral("Cannot set certificate and key: %1").arg(err);
903#endif
904 errorCode = QAbstractSocket::SslInvalidUserDataError;
905 errorDescription = QStringLiteral("Cannot set certificate and key: %1").arg(err);
906 return false;
907 }
908 }
909
910 return true;
911}
912
913bool TlsCryptographSecureTransport::setSessionProtocol()
914{
915 Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
916 Q_ASSERT(q);
917 Q_ASSERT(d);
918 // SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
919 // Calling SSLSetProtocolVersionMax/Min with any of these two constants results
920 // in errInvalidParam and a failure to set the protocol version. This means
921 // no TLS 1.3 on macOS and iOS.
922 const auto &configuration = q->sslConfiguration();
923 auto *plainSocket = d->plainTcpSocket();
924 switch (configuration.protocol()) {
925 case QSsl::TlsV1_3:
926 case QSsl::TlsV1_3OrLater:
927 qCWarning(lcSecureTransport) << plainSocket << "SecureTransport does not support TLS 1.3";
928 return false;
929 default:;
930 }
931
932 OSStatus err = errSecSuccess;
933
934QT_WARNING_PUSH
935QT_WARNING_DISABLE_DEPRECATED
936 if (configuration.protocol() == QSsl::TlsV1_0) {
937 #ifdef QSSLSOCKET_DEBUG
938 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.0";
939 #endif
940 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
941 if (err == errSecSuccess)
942 err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
943 } else if (configuration.protocol() == QSsl::TlsV1_1) {
944 #ifdef QSSLSOCKET_DEBUG
945 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.1";
946 #endif
947 err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
948 if (err == errSecSuccess)
949 err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
950QT_WARNING_POP
951 } else if (configuration.protocol() == QSsl::TlsV1_2) {
952 #ifdef QSSLSOCKET_DEBUG
953 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
954 #endif
955 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
956 if (err == errSecSuccess)
957 err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
958 } else if (configuration.protocol() == QSsl::AnyProtocol) {
959 #ifdef QSSLSOCKET_DEBUG
960 qCDebug(lcSecureTransport) << plainSocket << "requesting : any";
961 #endif
962 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
963 } else if (configuration.protocol() == QSsl::SecureProtocols) {
964 #ifdef QSSLSOCKET_DEBUG
965 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
966 #endif
967 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
968QT_WARNING_PUSH
969QT_WARNING_DISABLE_DEPRECATED
970 } else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
971 #ifdef QSSLSOCKET_DEBUG
972 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1 - TLSv1.2";
973 #endif
974 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
975 } else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
976 #ifdef QSSLSOCKET_DEBUG
977 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
978 #endif
979 err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
980QT_WARNING_POP
981 } else if (configuration.protocol() == QSsl::TlsV1_2OrLater) {
982 #ifdef QSSLSOCKET_DEBUG
983 qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
984 #endif
985 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
986 } else {
987 #ifdef QSSLSOCKET_DEBUG
988 qCDebug(lcSecureTransport) << plainSocket << "no protocol version found in the configuration";
989 #endif
990 return false;
991 }
992
993 return err == errSecSuccess;
994}
995
996bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
997{
998 Q_ASSERT(q);
999 Q_ASSERT(d);
1000 const auto &configuration = q->sslConfiguration();
1001 const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode();
1002 return d->tlsMode() == QSslSocket::SslServerMode
1003 && (verifyMode == QSslSocket::QueryPeer
1004 || verifyMode == QSslSocket::AutoVerifyPeer
1005 || verifyMode == QSslSocket::VerifyNone);
1006}
1007
1008bool TlsCryptographSecureTransport::verifySessionProtocol() const
1009{
1010 Q_ASSERT(q);
1011
1012 const auto &configuration = q->sslConfiguration();
1013 bool protocolOk = false;
1014 if (configuration.protocol() == QSsl::AnyProtocol)
1015 protocolOk = true;
1016 else if (configuration.protocol() == QSsl::SecureProtocols)
1017 protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
1018QT_WARNING_PUSH
1019QT_WARNING_DISABLE_DEPRECATED
1020 else if (configuration.protocol() == QSsl::TlsV1_0OrLater)
1021 protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
1022 else if (configuration.protocol() == QSsl::TlsV1_1OrLater)
1023 protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
1024QT_WARNING_POP
1025 else if (configuration.protocol() == QSsl::TlsV1_2OrLater)
1026 protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
1027 else if (configuration.protocol() == QSsl::TlsV1_3OrLater)
1028 protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
1029 else
1030 protocolOk = (sessionProtocol() == configuration.protocol());
1031
1032 return protocolOk;
1033}
1034
1035bool TlsCryptographSecureTransport::verifyPeerTrust()
1036{
1037 Q_ASSERT(q);
1038 Q_ASSERT(d);
1039
1040 const auto mode = d->tlsMode();
1041 const QSslSocket::PeerVerifyMode verifyMode = q->peerVerifyMode();
1042 const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
1043
1044 Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
1045
1046 auto *plainSocket = d->plainTcpSocket();
1047 Q_ASSERT(plainSocket);
1048
1049 QCFType<SecTrustRef> trust;
1050 OSStatus err = SSLCopyPeerTrust(context, &trust);
1051 // !trust - SSLCopyPeerTrust can return errSecSuccess but null trust.
1052 if (err != errSecSuccess || !trust) {
1053 if (!canIgnoreVerify) {
1054 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1055 QStringLiteral("Failed to obtain peer trust: %1").arg(err));
1056 plainSocket->disconnectFromHost();
1057 return false;
1058 } else {
1059 return true;
1060 }
1061 }
1062
1063 QList<QSslError> errors;
1064
1065 // Store certificates.
1066 // Apple's docs say SetTrustEvaluate must be called before
1067 // SecTrustGetCertificateAtIndex, but this results
1068 // in 'kSecTrustResultRecoverableTrustFailure', so
1069 // here we just ignore 'res' (later we'll use SetAnchor etc.
1070 // and evaluate again).
1071 SecTrustResultType res = kSecTrustResultInvalid;
1072 err = SecTrustEvaluate(trust, &res);
1073 if (err != errSecSuccess) {
1074 // We can not ignore this, it's not even about trust verification
1075 // probably ...
1076 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1077 QStringLiteral("SecTrustEvaluate failed: %1").arg(err));
1078 plainSocket->disconnectFromHost();
1079 return false;
1080 }
1081
1082 QTlsBackend::clearPeerCertificates(d);
1083
1084 QList<QSslCertificate> peerCertificateChain;
1085 const CFIndex certCount = SecTrustGetCertificateCount(trust);
1086 for (CFIndex i = 0; i < certCount; ++i) {
1087 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
1088 QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
1089 peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
1090 }
1091 QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
1092
1093 if (peerCertificateChain.size())
1094 QTlsBackend::storePeerCertificate(d, peerCertificateChain.at(0));
1095
1096 // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
1097 for (const QSslCertificate &cert : std::as_const(peerCertificateChain)) {
1098 if (QSslCertificatePrivate::isBlacklisted(cert) && !canIgnoreVerify) {
1099 const QSslError error(QSslError::CertificateBlacklisted, cert);
1100 errors << error;
1101 emit q->peerVerifyError(error);
1102 if (q->state() != QAbstractSocket::ConnectedState)
1103 return false;
1104 }
1105 }
1106
1107 const bool doVerifyPeer = verifyMode == QSslSocket::VerifyPeer
1108 || (verifyMode == QSslSocket::AutoVerifyPeer
1109 && d->tlsMode() == QSslSocket::SslClientMode);
1110 // Check the peer certificate itself. First try the subject's common name
1111 // (CN) as a wildcard, then try all alternate subject name DNS entries the
1112 // same way.
1113 const auto &peerCertificate = q->peerCertificate();
1114 if (!peerCertificate.isNull()) {
1115 // but only if we're a client connecting to a server
1116 // if we're the server, don't check CN
1117 const QString verificationPeerName = d->verificationName();
1118 if (mode == QSslSocket::SslClientMode) {
1119 const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
1120 if (!isMatchingHostname(peerCertificate, peerName) && !canIgnoreVerify) {
1121 // No matches in common names or alternate names.
1122 const QSslError error(QSslError::HostNameMismatch, peerCertificate);
1123 errors << error;
1124 emit q->peerVerifyError(error);
1125 if (q->state() != QAbstractSocket::ConnectedState)
1126 return false;
1127 }
1128 }
1129 } else {
1130 // No peer certificate presented. Report as error if the socket
1131 // expected one.
1132 if (doVerifyPeer && !canIgnoreVerify) {
1133 const QSslError error(QSslError::NoPeerCertificate);
1134 errors << error;
1135 emit q->peerVerifyError(error);
1136 if (q->state() != QAbstractSocket::ConnectedState)
1137 return false;
1138 }
1139 }
1140
1141 // verify certificate chain
1142 QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
1143 const auto &caCertificates = q->sslConfiguration().caCertificates();
1144 for (const QSslCertificate &cert : caCertificates) {
1145 QCFType<CFDataRef> certData = cert.toDer().toCFData();
1146 if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
1147 CFArrayAppendValue(certArray, secRef);
1148 }
1149
1150 SecTrustSetAnchorCertificates(trust, certArray);
1151
1152 // By default SecTrustEvaluate uses both CA certificates provided in
1153 // QSslConfiguration and the ones from the system database. This behavior can
1154 // be unexpected if a user's code tries to limit the trusted CAs to those
1155 // explicitly set in QSslConfiguration.
1156 // Since on macOS we initialize the default QSslConfiguration copying the
1157 // system CA certificates (using SecTrustSettingsCopyCertificates) we can
1158 // call SecTrustSetAnchorCertificatesOnly(trust, true) to force SecTrustEvaluate
1159 // to use anchors only from our QSslConfiguration.
1160 // Unfortunately, SecTrustSettingsCopyCertificates is not available on iOS
1161 // and the default QSslConfiguration always has an empty list of system CA
1162 // certificates. This leaves no way to provide client code with access to the
1163 // actual system CA certificate list (which most use-cases need) other than
1164 // by letting SecTrustEvaluate fall through to the system list; so, in this case
1165 // (even though the client code may have provided its own certs), we retain
1166 // the default behavior. Note, with macOS SDK below 10.12 using 'trust my
1167 // anchors only' may result in some valid chains rejected, apparently the
1168 // ones containing intermediated certificates; so we use this functionality
1169 // on more recent versions only.
1170
1171 bool anchorsFromConfigurationOnly = false;
1172
1173#ifdef Q_OS_MACOS
1174 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra)
1175 anchorsFromConfigurationOnly = true;
1176#endif // Q_OS_MACOS
1177
1178 SecTrustSetAnchorCertificatesOnly(trust, anchorsFromConfigurationOnly);
1179
1180 SecTrustResultType trustResult = kSecTrustResultInvalid;
1181 SecTrustEvaluate(trust, &trustResult);
1182 switch (trustResult) {
1183 case kSecTrustResultUnspecified:
1184 case kSecTrustResultProceed:
1185 break;
1186 default:
1187 if (!canIgnoreVerify) {
1188 const QSslError error(QSslError::CertificateUntrusted, peerCertificate);
1189 errors << error;
1190 emit q->peerVerifyError(error);
1191 }
1192 }
1193
1194 // report errors
1195 if (!errors.isEmpty() && !canIgnoreVerify) {
1196 sslErrors = errors;
1197 // checkSslErrors unconditionally emits sslErrors:
1198 // a user's slot can abort/close/disconnect on this
1199 // signal, so we also test the socket's state:
1200 if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState)
1201 return false;
1202 } else {
1203 sslErrors.clear();
1204 }
1205
1206 return true;
1207}
1208
1209/*
1210 Copied verbatim from qsslsocket_openssl.cpp
1211*/
1212bool TlsCryptographSecureTransport::checkSslErrors()
1213{
1214 if (sslErrors.isEmpty())
1215 return true;
1216
1217 Q_ASSERT(q);
1218 Q_ASSERT(d);
1219
1220 emit q->sslErrors(sslErrors);
1221 const auto mode = d->tlsMode();
1222 const auto &configuration = q->sslConfiguration();
1223 const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
1224 || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
1225 && mode == QSslSocket::SslClientMode);
1226 const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
1227 // check whether we need to emit an SSL handshake error
1228 if (doVerifyPeer && doEmitSslError) {
1229 if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
1230 QSslSocketPrivate::pauseSocketNotifiers(q);
1231 d->setPaused(true);
1232 } else {
1233 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1234 sslErrors.constFirst().errorString());
1235 Q_ASSERT(d->plainTcpSocket());
1236 d->plainTcpSocket()->disconnectFromHost();
1237 }
1238 return false;
1239 }
1240
1241 return true;
1242}
1243
1244bool TlsCryptographSecureTransport::startHandshake()
1245{
1246 Q_ASSERT(context);
1247 Q_ASSERT(q);
1248 Q_ASSERT(d);
1249
1250 auto *plainSocket = d->plainTcpSocket();
1251 Q_ASSERT(plainSocket);
1252 const auto mode = d->tlsMode();
1253
1254 OSStatus err = SSLHandshake(context);
1255#ifdef QSSLSOCKET_DEBUG
1256 qCDebug(lcSecureTransport) << plainSocket << "SSLHandhake returned" << err;
1257#endif
1258
1259 if (err == errSSLWouldBlock) {
1260 // startHandshake has to be called again ... later.
1261 return false;
1262 } else if (err == errSSLServerAuthCompleted) {
1263 // errSSLServerAuthCompleted is a define for errSSLPeerAuthCompleted,
1264 // it works for both server/client modes.
1265 // In future we'll evaluate peer's trust at this point,
1266 // for now we just continue.
1267 // if (!verifyPeerTrust())
1268 // ...
1269 return startHandshake();
1270 } else if (err == errSSLClientCertRequested) {
1271 Q_ASSERT(mode == QSslSocket::SslClientMode);
1272 QString errorDescription;
1273 QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
1274 // setSessionCertificate does not fail if we have no certificate.
1275 // Failure means a real error (invalid certificate, no private key, etc).
1276 if (!setSessionCertificate(errorDescription, errorCode)) {
1277 setErrorAndEmit(d, errorCode, errorDescription);
1278 renegotiating = false;
1279 return false;
1280 } else {
1281 // We try to resume a handshake, even if have no
1282 // local certificates ... (up to server to deal with our failure).
1283 return startHandshake();
1284 }
1285 } else if (err != errSecSuccess) {
1286 if (err == errSSLBadCert && canIgnoreTrustVerificationFailure()) {
1287 // We're on the server side and client did not provide any
1288 // certificate. This is the new 'nice' error returned by
1289 // Security Framework after it was recently updated.
1290 return startHandshake();
1291 }
1292
1293 renegotiating = false;
1294 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1295 QStringLiteral("SSLHandshake failed: %1").arg(err));
1296 plainSocket->disconnectFromHost();
1297 return false;
1298 }
1299
1300 // Connection aborted during handshake phase.
1301 if (q->state() != QAbstractSocket::ConnectedState) {
1302 qCDebug(lcSecureTransport) << "connection aborted";
1303 renegotiating = false;
1304 return false;
1305 }
1306
1307 // check protocol version ourselves, as Secure Transport does not enforce
1308 // the requested min / max versions.
1309 if (!verifySessionProtocol()) {
1310 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError, QStringLiteral("Protocol version mismatch"));
1311 plainSocket->disconnectFromHost();
1312 renegotiating = false;
1313 return false;
1314 }
1315
1316 if (verifyPeerTrust()) {
1318 renegotiating = false;
1319 return true;
1320 } else {
1321 renegotiating = false;
1322 return false;
1323 }
1324}
1325
1326bool TlsCryptographSecureTransport::isHandshakeComplete() const
1327{
1328 Q_ASSERT(q);
1329 return q->isEncrypted() && !renegotiating;
1330}
1331
1333{
1334 return sslErrors;
1335}
1336
1337} // namespace QTlsPrivate
1338
1339QT_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:386
QList< QSslError > tlsErrors() const override
Definition qtls_st.cpp:1332
void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override
Definition qtls_st.cpp:299
QSsl::SslProtocol sessionProtocol() const override
Definition qtls_st.cpp:395
SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph)
Definition qtls_st.cpp:542
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)