summaryrefslogtreecommitdiffstats
path: root/src/network/ssl/qsslsocket_mac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/ssl/qsslsocket_mac.cpp')
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp379
1 files changed, 293 insertions, 86 deletions
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index 2af0264116..326686fad0 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -51,12 +51,291 @@
#include <algorithm>
#include <cstddef>
+#include <QtCore/private/qcore_mac_p.h>
+
#ifdef Q_OS_OSX
#include <CoreServices/CoreServices.h>
#endif
QT_BEGIN_NAMESPACE
+static SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
+{
+ const bool isServer = mode == QSslSocket::SslServerMode;
+ SSLContextRef context = Q_NULLPTR;
+
+#ifndef Q_OS_OSX
+ const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide;
+ // We never use kSSLDatagramType, so it's kSSLStreamType unconditionally.
+ context = SSLCreateContext(Q_NULLPTR, side, kSSLStreamType);
+ if (!context)
+ qCWarning(lcSsl) << "SSLCreateContext failed";
+#else // Q_OS_OSX
+
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_NA)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide;
+ // We never use kSSLDatagramType, so it's kSSLStreamType unconditionally.
+ context = SSLCreateContext(Q_NULLPTR, side, kSSLStreamType);
+ if (!context)
+ qCWarning(lcSsl) << "SSLCreateContext failed";
+ } else {
+#else
+ {
+#endif
+ const OSStatus errCode = SSLNewContext(isServer, &context);
+ if (errCode != noErr || !context)
+ qCWarning(lcSsl) << "SSLNewContext failed with error:" << errCode;
+ }
+#endif // !Q_OS_OSX
+
+ return context;
+}
+
+static void qt_releaseSecureTransportContext(SSLContextRef context)
+{
+ if (!context)
+ return;
+
+#ifndef Q_OS_OSX
+ CFRelease(context);
+#else
+
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_NA)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ CFRelease(context);
+ } else {
+#else
+ {
+#endif // QT_MAC_PLATFORM_...
+ const OSStatus errCode = SSLDisposeContext(context);
+ if (errCode != noErr)
+ qCWarning(lcSsl) << "SSLDisposeContext failed with error:" << errCode;
+ }
+#endif // !Q_OS_OSX
+}
+
+static bool qt_setSessionProtocol(SSLContextRef context, const QSslConfigurationPrivate &configuration,
+ QTcpSocket *plainSocket)
+{
+ Q_ASSERT(context);
+
+#ifndef QSSLSOCKET_DEBUG
+ Q_UNUSED(plainSocket)
+#endif
+
+ OSStatus err = noErr;
+
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_5_0)
+ if (configuration.protocol == QSsl::SslV3) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : SSLv3";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kSSLProtocol3);
+ } else if (configuration.protocol == QSsl::TlsV1_0) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.0";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
+ } else if (configuration.protocol == QSsl::TlsV1_1) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
+ } else if (configuration.protocol == QSsl::TlsV1_2) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::AnyProtocol) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : any";
+ #endif
+ // kSSLProtocol3, since kSSLProtocol2 is disabled:
+ err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1SslV3) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : SSLv3 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::SecureProtocols) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "no protocol version found in the configuration";
+ #endif
+ return false;
+ }
+#endif
+
+ return err == noErr;
+}
+
+#ifdef Q_OS_OSX
+
+static bool qt_setSessionProtocolOSX(SSLContextRef context, const QSslConfigurationPrivate &configuration,
+ QTcpSocket *plainSocket)
+{
+ // This function works with (now) deprecated API that does not even exist on
+ // iOS but is the only API we have on OS X below 10.8
+
+ // Without SSLSetProtocolVersionMin/Max functions it's quite difficult
+ // to have the required result:
+ // If we use SSLSetProtocolVersion - any constant except the ones with 'Only' suffix -
+ // allows a negotiation and we can not set the lower limit.
+ // SSLSetProtocolVersionEnabled supports only a limited subset of constants, if you believe their docs:
+ // kSSLProtocol2
+ // kSSLProtocol3
+ // kTLSProtocol1
+ // kSSLProtocolAll
+ // Here we can only have a look into the SecureTransport's code and hope that what we see there
+ // and what we have on 10.7 is similar:
+ // SSLSetProtocoLVersionEnabled actually accepts other constants also,
+ // called twice with two different protocols it sets a range,
+ // called once with a protocol (when all protocols were disabled)
+ // - only this protocol is enabled (without a lower limit negotiation).
+
+ Q_ASSERT(context);
+
+#ifndef QSSLSOCKET_DEBUG
+ Q_UNUSED(plainSocket)
+#endif
+
+ OSStatus err = noErr;
+
+ // First, disable ALL:
+ if (SSLSetProtocolVersionEnabled(context, kSSLProtocolAll, false) != noErr)
+ return false;
+
+ if (configuration.protocol == QSsl::SslV3) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : SSLv3";
+ #endif
+ err = SSLSetProtocolVersion(context, kSSLProtocol3Only);
+ } else if (configuration.protocol == QSsl::TlsV1_0) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.0";
+ #endif
+ err = SSLSetProtocolVersion(context, kTLSProtocol1Only);
+ } else if (configuration.protocol == QSsl::TlsV1_1) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol11, true);
+ } else if (configuration.protocol == QSsl::TlsV1_2) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol12, true);
+ } else if (configuration.protocol == QSsl::AnyProtocol) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : any";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kSSLProtocolAll, true);
+ } else if (configuration.protocol == QSsl::TlsV1SslV3) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : SSLv3 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol12, true);
+ if (err == noErr)
+ err = SSLSetProtocolVersionEnabled(context, kSSLProtocol3, true);
+ } else if (configuration.protocol == QSsl::SecureProtocols) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol12, true);
+ if (err == noErr)
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol1, true);
+ } else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol12, true);
+ if (err == noErr)
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol1, true);
+ } else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol12, true);
+ if (err == noErr)
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol11, true);
+ } else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionEnabled(context, kTLSProtocol12, true);
+ } else {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "no protocol version found in the configuration";
+ #endif
+ return false;
+ }
+
+ return err == noErr;
+}
+
+#endif // Q_OS_OSX
+
+QSecureTransportContext::QSecureTransportContext(SSLContextRef c)
+ : context(c)
+{
+}
+
+QSecureTransportContext::~QSecureTransportContext()
+{
+ qt_releaseSecureTransportContext(context);
+}
+
+QSecureTransportContext::operator SSLContextRef()const
+{
+ return context;
+}
+
+void QSecureTransportContext::reset(SSLContextRef newContext)
+{
+ qt_releaseSecureTransportContext(context);
+ context = newContext;
+}
+
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_securetransport_mutex, (QMutex::Recursive))
//#define QSSLSOCKET_DEBUG
@@ -144,7 +423,7 @@ void QSslSocketPrivate::ensureInitialized()
// from QSslCertificatePrivate's ctor.
s_loadedCiphersAndCerts = true;
- QCFType<SSLContextRef> context(SSLCreateContext(Q_NULLPTR, kSSLClientSide, kSSLStreamType));
+ const QSecureTransportContext context(qt_createSecureTransportContext(QSslSocket::SslClientMode));
if (context) {
QList<QSslCipher> ciphers;
QList<QSslCipher> defaultCiphers;
@@ -171,7 +450,6 @@ void QSslSocketPrivate::ensureInitialized()
if (!s_loadRootCertsOnDemand)
setDefaultCaCertificates(systemCaCertificates());
} else {
- qCWarning(lcSsl) << "SSLCreateContext failed";
s_loadedCiphersAndCerts = false;
}
@@ -640,11 +918,7 @@ bool QSslSocketBackendPrivate::initSslContext()
Q_ASSERT_X(!context, Q_FUNC_INFO, "invalid socket state, context is not null");
Q_ASSERT(plainSocket);
- SSLProtocolSide side = kSSLClientSide;
- if (mode == QSslSocket::SslServerMode)
- side = kSSLServerSide;
-
- context = SSLCreateContext(Q_NULLPTR, side, kSSLStreamType);
+ context.reset(qt_createSecureTransportContext(mode));
if (!context) {
setErrorAndEmit(QAbstractSocket::SslInternalError, "SSLCreateContext failed");
return false;
@@ -740,7 +1014,7 @@ bool QSslSocketBackendPrivate::initSslContext()
void QSslSocketBackendPrivate::destroySslContext()
{
- context = Q_NULLPTR;
+ context.reset(Q_NULLPTR);
}
static QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase);
@@ -837,8 +1111,6 @@ bool QSslSocketBackendPrivate::setSessionProtocol()
{
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
- OSStatus err = noErr;
-
// QSsl::SslV2 == kSSLProtocol2 is disabled in secure transport and
// always fails with errSSLIllegalParam:
// if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)
@@ -849,85 +1121,20 @@ bool QSslSocketBackendPrivate::setSessionProtocol()
return false;
}
- if (configuration.protocol == QSsl::SslV3) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : SSLv3";
-#endif
- err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kSSLProtocol3);
- } else if (configuration.protocol == QSsl::TlsV1_0) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.0";
-#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1_1) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1";
-#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
- } else if (configuration.protocol == QSsl::TlsV1_2) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
-#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::AnyProtocol) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : any";
-#endif
- // kSSLProtocol3, since kSSLProtocol2 is disabled:
- err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1SslV3) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : SSLv3 - TLSv1.2";
-#endif
- err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::SecureProtocols) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
-#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
-#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
-#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
-#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+#ifndef Q_OS_OSX
+ return qt_setSessionProtocol(context, configuration, plainSocket);
+#else
+
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_NA)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ return qt_setSessionProtocol(context, configuration, plainSocket);
} else {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "no protocol version found in the configuration";
+#else
+ {
#endif
- return false;
+ return qt_setSessionProtocolOSX(context, configuration, plainSocket);
}
-
- return err == noErr;
+#endif
}
bool QSslSocketBackendPrivate::canIgnoreTrustVerificationFailure() const