9#include <QtNetwork/private/qssl_p.h>
11#include <QtNetwork/private/qsslcertificate_p.h>
12#include <QtNetwork/private/qsslcipher_p.h>
13#include <QtNetwork/private/qsslkey_p.h>
15#include <QtNetwork/qsslsocket.h>
17#include <QtCore/qmessageauthenticationcode.h>
18#include <QtCore/qoperatingsystemversion.h>
19#include <QtCore/qscopedvaluerollback.h>
20#include <QtCore/qcryptographichash.h>
21#include <QtCore/qsystemdetection.h>
22#include <QtCore/qdatastream.h>
23#include <QtCore/qsysinfo.h>
24#include <QtCore/qlist.h>
25#include <QtCore/qmutex.h>
26#include <QtCore/qdebug.h>
27#include <QtCore/quuid.h>
28#include <QtCore/qdir.h>
35#include <QtCore/private/qcore_mac_p.h>
38#include <CoreServices/CoreServices.h>
65struct EphemeralSecKeychain
67 EphemeralSecKeychain();
68 ~EphemeralSecKeychain();
70 SecKeychainRef keychain =
nullptr;
71 Q_DISABLE_COPY_MOVE(EphemeralSecKeychain)
74EphemeralSecKeychain::EphemeralSecKeychain()
78 qCWarning(lcSecureTransport) <<
"Failed to create a unique keychain name";
82 const QByteArray uuidAsByteArray = uuid.toByteArray();
98 std::vector<char> posixPath;
101 posixPath.
resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName));
102 const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
103 CFIndex(posixPath.size()));
105 qCWarning(lcSecureTransport) <<
"Failed to create a unique keychain name from"
106 <<
"QDir::tempPath()";
110 std::vector<uint8_t> passUtf8(256);
111 if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) {
112 qCWarning(lcSecureTransport) <<
"SecRandomCopyBytes: failed to create a key";
116 const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(),
117 &passUtf8[0], FALSE,
nullptr,
119 if (status != errSecSuccess || !keychain) {
120 qCWarning(lcSecureTransport) <<
"SecKeychainCreate: failed to create a custom keychain";
122 SecKeychainDelete(keychain);
130 settings.version = SEC_KEYCHAIN_SETTINGS_VERS1;
134 if (SecKeychainSetSettings(keychain, &
settings) != errSecSuccess)
135 qCWarning(lcSecureTransport) <<
"SecKeychainSettings: failed to disable lock on sleep";
138#ifdef QSSLSOCKET_DEBUG
140 qCDebug(lcSecureTransport) <<
"Custom keychain with name" << keychainName <<
"was created"
146EphemeralSecKeychain::~EphemeralSecKeychain()
150 SecKeychainDelete(keychain);
157void qt_releaseSecureTransportContext(SSLContextRef
context)
169 const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide;
171 SSLContextRef
context = SSLCreateContext(
nullptr, side, kSSLStreamType);
173 qCWarning(lcSecureTransport) <<
"SSLCreateContext failed";
184 qt_releaseSecureTransportContext(context);
187QSecureTransportContext::operator SSLContextRef()
const
194 qt_releaseSecureTransportContext(context);
195 context = newContext;
198#if !defined(QT_PLATFORM_UIKIT)
200 "\x30\x82\x01\x08\x02\x82\x01\x01\x00\x97\xea\xd0\x46\xf7\xae\xa7\x76\x80"
201 "\x9c\x74\x56\x98\xd8\x56\x97\x2b\x20\x6c\x77\xe2\x82\xbb\xc8\x84\xbe\xe7"
202 "\x63\xaf\xcc\x30\xd0\x67\x97\x7d\x1b\xab\x59\x30\xa9\x13\x67\x21\xd7\xd4"
203 "\x0e\x46\xcf\xe5\x80\xdf\xc9\xb9\xba\x54\x9b\x46\x2f\x3b\x45\xfc\x2f\xaf"
204 "\xad\xc0\x17\x56\xdd\x52\x42\x57\x45\x70\x14\xe5\xbe\x67\xaa\xde\x69\x75"
205 "\x30\x0d\xf9\xa2\xc4\x63\x4d\x7a\x39\xef\x14\x62\x18\x33\x44\xa1\xf9\xc1"
206 "\x52\xd1\xb6\x72\x21\x98\xf8\xab\x16\x1b\x7b\x37\x65\xe3\xc5\x11\x00\xf6"
207 "\x36\x1f\xd8\x5f\xd8\x9f\x43\xa8\xce\x9d\xbf\x5e\xd6\x2d\xfa\x0a\xc2\x01"
208 "\x54\xc2\xd9\x81\x54\x55\xb5\x26\xf8\x88\x37\xf5\xfe\xe0\xef\x4a\x34\x81"
209 "\xdc\x5a\xb3\x71\x46\x27\xe3\xcd\x24\xf6\x1b\xf1\xe2\x0f\xc2\xa1\x39\x53"
210 "\x5b\xc5\x38\x46\x8e\x67\x4c\xd9\xdd\xe4\x37\x06\x03\x16\xf1\x1d\x7a\xba"
211 "\x2d\xc1\xe4\x03\x1a\x58\xe5\x29\x5a\x29\x06\x69\x61\x7a\xd8\xa9\x05\x9f"
212 "\xc1\xa2\x45\x9c\x17\xad\x52\x69\x33\xdc\x18\x8d\x15\xa6\x5e\xcd\x94\xf4"
213 "\x45\xbb\x9f\xc2\x7b\x85\x00\x61\xb0\x1a\xdc\x3c\x86\xaa\x9f\x5c\x04\xb3"
214 "\x90\x0b\x35\x64\xff\xd9\xe3\xac\xf2\xf2\xeb\x3a\x63\x02\x01\x02";
218 char *
data,
size_t *dataLength)
228 if (
socket->isHandshakeComplete()) {
231 SSLSessionState currentState = kSSLConnected;
232 const OSStatus
result = SSLGetSessionState(
socket->context, ¤tState);
238 if (currentState == kSSLHandshake) {
242 socket->renegotiating =
true;
243 return errSSLWouldBlock;
248#ifdef QSSLSOCKET_DEBUG
249 qCDebug(lcSecureTransport) << plainSocket <<
"read" << bytes;
256 const OSStatus err = (size_t(bytes) < *dataLength) ? OSStatus(errSSLWouldBlock) : OSStatus(errSecSuccess);
262OSStatus TlsCryptographSecureTransport::WriteCallback(TlsCryptographSecureTransport *
socket,
263 const char *
data,
size_t *dataLength)
274#ifdef QSSLSOCKET_DEBUG
275 qCDebug(lcSecureTransport) << plainSocket <<
"write" << bytes;
282 const OSStatus err = (size_t(bytes) < *dataLength) ? OSStatus(errSSLWouldBlock) : OSStatus(errSecSuccess);
305 renegotiating =
false;
314#ifdef QSSLSOCKET_DEBUG
322 const auto &configuration =
q->sslConfiguration();
323 const auto &requestedProtocols = configuration.allowedNextProtocols();
324 if (
const int requestedCount = requestedProtocols.size()) {
326 QTlsBackend::setNegotiatedProtocol(d, {});
329 const OSStatus
result = SSLCopyALPNProtocols(context, &cfArray);
330 if (
result == errSecSuccess && cfArray && CFArrayGetCount(cfArray)) {
331 const int size = CFArrayGetCount(cfArray);
334 peerProtocols[
i] = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(cfArray,
i));
336 for (
int i = 0;
i < requestedCount; ++
i) {
338 for (
int j = 0;
j <
size; ++
j) {
339 if (requestedName == peerProtocols[
j]) {
340 QTlsBackend::setNegotiatedProtocol(d, requestedName.toLatin1());
356 q->disconnectFromHost();
376 context.
reset(
nullptr);
385 SSLCipherSuite cipher = 0;
386 if (context && SSLGetNegotiatedCipher(context, &cipher) == errSecSuccess)
397 SSLProtocol protocol = kSSLProtocolUnknown;
398 const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
399 if (err != errSecSuccess) {
400 qCWarning(lcSecureTransport) <<
"SSLGetNegotiatedProtocolVersion failed:" << err;
408 return QSsl::TlsV1_0;
410 return QSsl::TlsV1_1;
423 if (!initSslContext()) {
437 if (!initSslContext()) {
455 if (!context || shutdown)
458 if (!isHandshakeComplete())
462 if (isHandshakeComplete() && !
writeBuffer.isEmpty()) {
463 qint64 totalBytesWritten = 0;
464 while (
writeBuffer.nextDataBlockSize() > 0 && context) {
466 size_t writtenBytes = 0;
467 const OSStatus err = SSLWrite(context,
writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
468#ifdef QSSLSOCKET_DEBUG
471 if (err != errSecSuccess && err != errSSLWouldBlock) {
479 totalBytesWritten += writtenBytes;
482 if (writtenBytes < nextDataBlockSize)
486 if (totalBytesWritten > 0) {
489 if (!emittedBytesWritten) {
490 emittedBytesWritten =
true;
491 emit q->bytesWritten(totalBytesWritten);
492 emittedBytesWritten =
false;
494 emit q->channelBytesWritten(0, totalBytesWritten);
500 if (isHandshakeComplete()) {
502 while (context && (!readBufferMaxSize ||
buffer.size() < readBufferMaxSize)) {
503 size_t readBytes = 0;
505 const OSStatus err = SSLRead(context,
data.data(),
data.size(), &readBytes);
506#ifdef QSSLSOCKET_DEBUG
509 if (err == errSSLClosedGraceful) {
512 QSslSocket::tr(
"The TLS/SSL connection has been closed"));
514 }
else if (err != errSecSuccess && err != errSSLWouldBlock) {
520 if (err == errSSLWouldBlock && renegotiating) {
528 *readyReadEmittedPointer =
true;
530 emit q->channelReadyRead(0);
533 if (err == errSSLWouldBlock)
541 if (ciph.
name() ==
"AES128-SHA"_L1)
542 return TLS_RSA_WITH_AES_128_CBC_SHA;
543 if (ciph.
name() ==
"DHE-RSA-AES128-SHA"_L1)
544 return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
545 if (ciph.
name() ==
"AES256-SHA"_L1)
546 return TLS_RSA_WITH_AES_256_CBC_SHA;
547 if (ciph.
name() ==
"DHE-RSA-AES256-SHA"_L1)
548 return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
549 if (ciph.
name() ==
"ECDH-ECDSA-NULL-SHA"_L1)
550 return TLS_ECDH_ECDSA_WITH_NULL_SHA;
551 if (ciph.
name() ==
"ECDH-ECDSA-RC4-SHA"_L1)
552 return TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
553 if (ciph.
name() ==
"ECDH-ECDSA-DES-CBC3-SHA"_L1)
554 return TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
555 if (ciph.
name() ==
"ECDH-ECDSA-AES128-SHA"_L1)
556 return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
557 if (ciph.
name() ==
"ECDH-ECDSA-AES256-SHA"_L1)
558 return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
559 if (ciph.
name() ==
"ECDH-ECDSA-RC4-SHA"_L1)
560 return TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
561 if (ciph.
name() ==
"ECDH-ECDSA-DES-CBC3-SHA"_L1)
562 return TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
563 if (ciph.
name() ==
"ECDH-ECDSA-AES128-SHA"_L1)
564 return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
565 if (ciph.
name() ==
"ECDH-ECDSA-AES256-SHA"_L1)
566 return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
567 if (ciph.
name() ==
"ECDH-RSA-NULL-SHA"_L1)
568 return TLS_ECDH_RSA_WITH_NULL_SHA;
569 if (ciph.
name() ==
"ECDH-RSA-RC4-SHA"_L1)
570 return TLS_ECDH_RSA_WITH_RC4_128_SHA;
571 if (ciph.
name() ==
"ECDH-RSA-DES-CBC3-SHA"_L1)
572 return TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
573 if (ciph.
name() ==
"ECDH-RSA-AES128-SHA"_L1)
574 return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
575 if (ciph.
name() ==
"ECDH-RSA-AES256-SHA"_L1)
576 return TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
577 if (ciph.
name() ==
"ECDH-RSA-RC4-SHA"_L1)
578 return TLS_ECDHE_RSA_WITH_RC4_128_SHA;
579 if (ciph.
name() ==
"ECDH-RSA-DES-CBC3-SHA"_L1)
580 return TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
581 if (ciph.
name() ==
"ECDH-RSA-AES128-SHA"_L1)
582 return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
583 if (ciph.
name() ==
"ECDH-RSA-AES256-SHA"_L1)
584 return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
585 if (ciph.
name() ==
"DES-CBC3-SHA"_L1)
586 return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
587 if (ciph.
name() ==
"AES128-SHA256"_L1)
588 return TLS_RSA_WITH_AES_128_CBC_SHA256;
589 if (ciph.
name() ==
"AES256-SHA256"_L1)
590 return TLS_RSA_WITH_AES_256_CBC_SHA256;
591 if (ciph.
name() ==
"DHE-RSA-DES-CBC3-SHA"_L1)
592 return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
593 if (ciph.
name() ==
"DHE-RSA-AES128-SHA256"_L1)
594 return TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
595 if (ciph.
name() ==
"DHE-RSA-AES256-SHA256"_L1)
596 return TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
597 if (ciph.
name() ==
"AES256-GCM-SHA384"_L1)
598 return TLS_RSA_WITH_AES_256_GCM_SHA384;
599 if (ciph.
name() ==
"ECDHE-ECDSA-AES128-SHA256"_L1)
600 return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
601 if (ciph.
name() ==
"ECDHE-ECDSA-AES256-SHA384"_L1)
602 return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
603 if (ciph.
name() ==
"ECDH-ECDSA-AES128-SHA256"_L1)
604 return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
605 if (ciph.
name() ==
"ECDH-ECDSA-AES256-SHA384"_L1)
606 return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
607 if (ciph.
name() ==
"ECDHE-RSA-AES128-SHA256"_L1)
608 return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
609 if (ciph.
name() ==
"ECDHE-RSA-AES256-SHA384"_L1)
610 return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
611 if (ciph.
name() ==
"ECDHE-RSA-AES256-SHA384"_L1)
612 return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
613 if (ciph.
name() ==
"ECDHE-RSA-AES256-GCM-SHA384"_L1)
614 return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
615 if (ciph.
name() ==
"AES128-GCM-SHA256"_L1)
616 return TLS_AES_128_GCM_SHA256;
617 if (ciph.
name() ==
"AES256-GCM-SHA384"_L1)
618 return TLS_AES_256_GCM_SHA384;
619 if (ciph.
name() ==
"CHACHA20-POLY1305-SHA256"_L1)
620 return TLS_CHACHA20_POLY1305_SHA256;
621 if (ciph.
name() ==
"AES128-CCM-SHA256"_L1)
622 return TLS_AES_128_CCM_SHA256;
623 if (ciph.
name() ==
"AES128-CCM8-SHA256"_L1)
624 return TLS_AES_128_CCM_8_SHA256;
625 if (ciph.
name() ==
"ECDHE-ECDSA-AES128-GCM-SHA256"_L1)
626 return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
627 if (ciph.
name() ==
"ECDHE-ECDSA-AES256-GCM-SHA384"_L1)
628 return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
629 if (ciph.
name() ==
"ECDH-ECDSA-AES128-GCM-SHA256"_L1)
630 return TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
631 if (ciph.
name() ==
"ECDH-ECDSA-AES256-GCM-SHA384"_L1)
632 return TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
633 if (ciph.
name() ==
"ECDHE-RSA-AES128-GCM-SHA256"_L1)
634 return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
635 if (ciph.
name() ==
"ECDH-RSA-AES128-GCM-SHA256"_L1)
636 return TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
637 if (ciph.
name() ==
"ECDH-RSA-AES256-GCM-SHA384"_L1)
638 return TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
639 if (ciph.
name() ==
"ECDHE-RSA-CHACHA20-POLY1305-SHA256"_L1)
640 return TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
641 if (ciph.
name() ==
"ECDHE-ECDSA-CHACHA20-POLY1305-SHA256"_L1)
642 return TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
647bool TlsCryptographSecureTransport::initSslContext()
664 const OSStatus err = SSLSetIOFuncs(context,
665 reinterpret_cast<SSLReadFunc
>(&TlsCryptographSecureTransport::ReadCallback),
666 reinterpret_cast<SSLWriteFunc
>(&TlsCryptographSecureTransport::WriteCallback));
667 if (err != errSecSuccess) {
674 SSLSetConnection(context,
this);
676 const auto &configuration =
q->sslConfiguration();
678 && !configuration.localCertificateChain().isEmpty()) {
681 if (!setSessionCertificate(errorDescription, errorCode)) {
683 setErrorAndEmit(d, errorCode, errorDescription);
688 if (!setSessionProtocol()) {
694 const auto protocolNames = configuration.allowedNextProtocols();
698 if (
name.size() > 255) {
700 <<
"is too long and will be ignored.";
702 }
else if (
name.isEmpty()) {
706 CFArrayAppendValue(cfNames, cfName);
709 if (CFArrayGetCount(cfNames)) {
713 if (SSLSetALPNProtocols(context, cfNames) != errSecSuccess)
714 qCWarning(lcSecureTransport) <<
"SSLSetALPNProtocols failed - too long protocol names?";
717 qCWarning(lcSecureTransport) <<
"failed to allocate ALPN names array";
723 QString tlsHostName(verificationPeerName.isEmpty() ?
q->peerName() : verificationPeerName);
724 if (tlsHostName.isEmpty())
728 SSLSetPeerDomainName(context, ace.data(), ace.size());
730 OSStatus err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnServerAuth,
true);
731 if (err == errSecSuccess)
732 err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnCertRequested,
true);
734 if (err != errSecSuccess) {
744 OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
745 if (err == errSecSuccess) {
748 err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnClientAuth,
true);
751 if (err != errSecSuccess) {
758#if !defined(QT_PLATFORM_UIKIT)
763 if (configuration.ciphers().size() > 0) {
765 for (
const QSslCipher &cipher : configuration.ciphers()) {
767 cfCiphers << sslCipher;
769 if (cfCiphers.
size() == 0) {
770 qCWarning(lcSecureTransport) <<
"failed to add any of the requested ciphers from the configuration";
773 OSStatus err = SSLSetEnabledCiphers(context, cfCiphers.
data(), cfCiphers.
size());
774 if (err != errSecSuccess) {
775 qCWarning(lcSecureTransport) <<
"failed to set the ciphers from the configuration";
782void TlsCryptographSecureTransport::destroySslContext()
784 context.
reset(
nullptr);
792 const auto &configuration =
q->sslConfiguration();
794#ifdef QSSLSOCKET_DEBUG
800 if (!configuration.localCertificateChain().isEmpty())
801 localCertificate = configuration.localCertificateChain().at(0);
803 if (!localCertificate.
isNull()) {
805 if (configuration.privateKey().isNull()) {
807 errorDescription =
QStringLiteral(
"Cannot provide a certificate with no key");
814 configuration.privateKey(), passPhrase).toCFData();
816 const void *
keys[2] = { kSecImportExportPassphrase };
817 const void *
values[2] = { password };
823 static const EphemeralSecKeychain temporaryKeychain;
824 if (temporaryKeychain.keychain) {
826 keys[1] = kSecImportExportKeychain;
827 values[1] = temporaryKeychain.keychain;
834 OSStatus err = SecPKCS12Import(pkcs12, options, &
items);
835 if (err != errSecSuccess) {
836#ifdef QSSLSOCKET_DEBUG
837 qCWarning(lcSecureTransport) << plainSocket
841 errorDescription =
QStringLiteral(
"SecPKCS12Import failed: %1").arg(err);
845 if (!CFArrayGetCount(
items)) {
846#ifdef QSSLSOCKET_DEBUG
847 qCWarning(lcSecureTransport) << plainSocket <<
"SecPKCS12Import returned no items";
850 errorDescription =
QStringLiteral(
"SecPKCS12Import returned no items");
854 CFDictionaryRef
import = (CFDictionaryRef)CFArrayGetValueAtIndex(
items, 0);
855 SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(
import, kSecImportItemIdentity);
857#ifdef QSSLSOCKET_DEBUG
858 qCWarning(lcSecureTransport) << plainSocket <<
"SecPKCS12Import returned no identity";
861 errorDescription =
QStringLiteral(
"SecPKCS12Import returned no identity");
868 errorDescription =
QStringLiteral(
"Failed to allocate certificates array");
872 CFArrayAppendValue(
certs, identity);
874 CFArrayRef chain = (CFArrayRef)CFDictionaryGetValue(
import, kSecImportItemCertChain);
876 for (CFIndex
i = 1,
e = CFArrayGetCount(chain);
i <
e; ++
i)
877 CFArrayAppendValue(
certs, CFArrayGetValueAtIndex(chain,
i));
880 err = SSLSetCertificate(context,
certs);
881 if (err != errSecSuccess) {
882#ifdef QSSLSOCKET_DEBUG
883 qCWarning(lcSecureTransport) << plainSocket
887 errorDescription =
QStringLiteral(
"Cannot set certificate and key: %1").arg(err);
895bool TlsCryptographSecureTransport::setSessionProtocol()
904 const auto &configuration =
q->sslConfiguration();
906 switch (configuration.protocol()) {
909 qCWarning(lcSecureTransport) << plainSocket <<
"SecureTransport does not support TLS 1.3";
914 OSStatus err = errSecSuccess;
918 if (configuration.protocol() == QSsl::TlsV1_0) {
919 #ifdef QSSLSOCKET_DEBUG
920 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : TLSv1.0";
922 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
923 if (err == errSecSuccess)
924 err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
925 }
else if (configuration.protocol() == QSsl::TlsV1_1) {
926 #ifdef QSSLSOCKET_DEBUG
927 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : TLSv1.1";
929 err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
930 if (err == errSecSuccess)
931 err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
934 #ifdef QSSLSOCKET_DEBUG
935 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : TLSv1.2";
937 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
938 if (err == errSecSuccess)
939 err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
941 #ifdef QSSLSOCKET_DEBUG
942 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : any";
944 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
946 #ifdef QSSLSOCKET_DEBUG
947 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : TLSv1.2";
949 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
952 }
else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
953 #ifdef QSSLSOCKET_DEBUG
954 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : TLSv1 - TLSv1.2";
956 err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
957 }
else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
958 #ifdef QSSLSOCKET_DEBUG
959 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : TLSv1.1 - TLSv1.2";
961 err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
964 #ifdef QSSLSOCKET_DEBUG
965 qCDebug(lcSecureTransport) << plainSocket <<
"requesting : TLSv1.2";
967 err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
969 #ifdef QSSLSOCKET_DEBUG
970 qCDebug(lcSecureTransport) << plainSocket <<
"no protocol version found in the configuration";
975 return err == errSecSuccess;
978bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure()
const
982 const auto &configuration =
q->sslConfiguration();
990bool TlsCryptographSecureTransport::verifySessionProtocol()
const
994 const auto &configuration =
q->sslConfiguration();
995 bool protocolOk =
false;
1002 else if (configuration.protocol() == QSsl::TlsV1_0OrLater)
1004 else if (configuration.protocol() == QSsl::TlsV1_1OrLater)
1017bool TlsCryptographSecureTransport::verifyPeerTrust()
1024 const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
1032 OSStatus err = SSLCopyPeerTrust(context, &trust);
1034 if (err != errSecSuccess || !trust) {
1035 if (!canIgnoreVerify) {
1053 SecTrustResultType
res = kSecTrustResultInvalid;
1054 err = SecTrustEvaluate(trust, &
res);
1055 if (err != errSecSuccess) {
1064 QTlsBackend::clearPeerCertificates(d);
1067 const CFIndex certCount = SecTrustGetCertificateCount(trust);
1068 for (CFIndex
i = 0;
i < certCount; ++
i) {
1069 SecCertificateRef
cert = SecTrustGetCertificateAtIndex(trust,
i);
1073 QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
1075 if (peerCertificateChain.
size())
1076 QTlsBackend::storePeerCertificate(d, peerCertificateChain.
at(0));
1095 const auto &peerCertificate =
q->peerCertificate();
1096 if (!peerCertificate.isNull()) {
1101 const QString peerName(verificationPeerName.
isEmpty () ?
q->peerName() : verificationPeerName);
1102 if (!isMatchingHostname(peerCertificate, peerName) && !canIgnoreVerify) {
1114 if (doVerifyPeer && !canIgnoreVerify) {
1125 const auto &caCertificates =
q->sslConfiguration().caCertificates();
1129 CFArrayAppendValue(certArray, secRef);
1132 SecTrustSetAnchorCertificates(trust, certArray);
1153 bool anchorsFromConfigurationOnly =
false;
1157 anchorsFromConfigurationOnly =
true;
1160 SecTrustSetAnchorCertificatesOnly(trust, anchorsFromConfigurationOnly);
1162 SecTrustResultType trustResult = kSecTrustResultInvalid;
1163 SecTrustEvaluate(trust, &trustResult);
1164 switch (trustResult) {
1165 case kSecTrustResultUnspecified:
1166 case kSecTrustResultProceed:
1169 if (!canIgnoreVerify) {
1177 if (!errors.
isEmpty() && !canIgnoreVerify) {
1194bool TlsCryptographSecureTransport::checkSslErrors()
1202 emit q->sslErrors(sslErrors);
1204 const auto &configuration =
q->sslConfiguration();
1210 if (doVerifyPeer && doEmitSslError) {
1226bool TlsCryptographSecureTransport::startHandshake()
1236 OSStatus err = SSLHandshake(context);
1237#ifdef QSSLSOCKET_DEBUG
1238 qCDebug(lcSecureTransport) << plainSocket <<
"SSLHandhake returned" << err;
1241 if (err == errSSLWouldBlock) {
1244 }
else if (err == errSSLServerAuthCompleted) {
1251 return startHandshake();
1252 }
else if (err == errSSLClientCertRequested) {
1258 if (!setSessionCertificate(errorDescription, errorCode)) {
1259 setErrorAndEmit(d, errorCode, errorDescription);
1260 renegotiating =
false;
1265 return startHandshake();
1267 }
else if (err != errSecSuccess) {
1268 if (err == errSSLBadCert && canIgnoreTrustVerificationFailure()) {
1272 return startHandshake();
1275 renegotiating =
false;
1284 qCDebug(lcSecureTransport) <<
"connection aborted";
1285 renegotiating =
false;
1291 if (!verifySessionProtocol()) {
1294 renegotiating =
false;
1298 if (verifyPeerTrust()) {
1300 renegotiating =
false;
1303 renegotiating =
false;
1308bool TlsCryptographSecureTransport::isHandshakeComplete()
const
1311 return q->isEncrypted() && !renegotiating;
qint64 bytesAvailable() const override
Returns the number of incoming bytes that are waiting to be read.
virtual void disconnectFromHost()
Attempts to close the socket.
SocketError
This enum describes the socket errors that can occur.
@ SslInvalidUserDataError
@ SslHandshakeFailedError
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
bool endsWith(char c) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
bool startsWith(QByteArrayView bv) const
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
static QString tempPath()
Returns the absolute canonical path of the system's temporary directory.
qint64 nextDataBlockSize() const
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
constexpr QLatin1StringView mid(qsizetype pos, qsizetype n=-1) const
qsizetype size() const noexcept
bool isEmpty() const noexcept
const_reference at(qsizetype i) const noexcept
const T & constFirst() const noexcept
static constexpr QOperatingSystemVersionBase MacOSSierra
\variable QOperatingSystemVersion::MacOSSierra
static QOperatingSystemVersion current()
[0]
static Q_NETWORK_PRIVATE_EXPORT bool isBlacklisted(const QSslCertificate &certificate)
The QSslCertificate class provides a convenient API for an X509 certificate.
bool isNull() const
Returns true if this is a null certificate (i.e., a certificate with no contents); otherwise returns ...
The QSslCipher class represents an SSL cryptographic cipher.
QString name() const
Returns the name of the cipher, or an empty QString if this is a null cipher.
@ NextProtocolNegotiationNone
@ NextProtocolNegotiationNegotiated
The QSslError class provides an SSL error.
QString errorString() const
Returns a short localized human-readable description of the error.
The QSslKey class provides an interface for private and public keys.
bool * readyReadPointer()
bool verifyErrorsHaveBeenIgnored()
void setEncrypted(bool enc)
QTcpSocket * plainTcpSocket() const
QString verificationName() const
bool isAutoStartingHandshake() const
qint64 maxReadBufferSize() const
bool & tlsEmittedBytesWritten()
QString tlsHostName() const
QRingBufferRef & tlsBuffer()
void setPendingClose(bool pc)
static void pauseSocketNotifiers(QSslSocket *)
QRingBufferRef & tlsWriteBuffer()
QSslSocket::SslMode tlsMode() const
bool isPendingClose() const
The QSslSocket class provides an SSL encrypted socket for both clients and servers.
SslMode
Describes the connection modes available for QSslSocket.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
void resize(qsizetype size)
Sets the size of the string to size characters.
The QTcpSocket class provides a TCP socket.
~QSecureTransportContext()
void reset(SSLContextRef newContext)
QSecureTransportContext(SSLContextRef context)
void disconnectFromHost() override
TlsCryptographSecureTransport()
void startClientEncryption() override
void continueHandshake() override
QSslCipher sessionCipher() const override
QList< QSslError > tlsErrors() const override
void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override
QSsl::SslProtocol sessionProtocol() const override
void startServerEncryption() override
SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph)
~TlsCryptographSecureTransport() override
void disconnected() override
static QByteArray toAce(const QString &domain, AceProcessingOptions options={})
static QUuid createUuid()
On any platform other than Windows, this function returns a new UUID with variant QUuid::DCE and vers...
SslProtocol
Describes the protocol of the cipher.
Combined button and popup list for selecting options.
Namespace containing onternal types that TLS backends implement.
QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher)
static const uint8_t dhparam[]
SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
#define QT_WARNING_DISABLE_DEPRECATED
DBusConnection const char DBusError * error
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLsizei GLsizei GLint * values
[15]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLdouble GLdouble GLdouble GLdouble q
#define Q_ASSERT_X(cond, x, msg)
#define QStringLiteral(str)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
QByteArray _q_makePkcs12(const QList< QSslCertificate > &certs, const QSslKey &key, const QString &passPhrase)
QByteArray _q_makePkcs12(const QList< QSslCertificate > &certs, const QSslKey &key, const QString &passPhrase)
QSettings settings("MySoft", "Star Runner")
[0]
QList< QSslCertificate > cert
[0]