diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_mac.cpp | 23 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_mac_shared.cpp | 149 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 31 | ||||
-rw-r--r-- | src/network/ssl/ssl.pri | 5 |
5 files changed, 160 insertions, 52 deletions
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 805adc734f..1dfd87a0f8 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -1507,6 +1507,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates() returned by defaultCaCertificates(). You can replace that database with your own with setDefaultCaCertificates(). + \note: On OS X, only certificates that are either trusted for all + purposes or trusted for the purpose of SSL in the keychain will be + returned. + \sa caCertificates(), defaultCaCertificates(), setDefaultCaCertificates() */ QList<QSslCertificate> QSslSocket::systemCaCertificates() diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp index a8f7b7320e..2af0264116 100644 --- a/src/network/ssl/qsslsocket_mac.cpp +++ b/src/network/ssl/qsslsocket_mac.cpp @@ -213,29 +213,6 @@ void QSslSocketPrivate::resetDefaultEllipticCurves() Q_UNIMPLEMENTED(); } - -QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() -{ - QList<QSslCertificate> systemCerts; -#ifdef Q_OS_OSX - // SecTrustSettingsCopyCertificates is not defined on iOS. - QCFType<CFArrayRef> cfCerts; - OSStatus status = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts); - if (status == noErr) { - const CFIndex size = CFArrayGetCount(cfCerts); - for (CFIndex i = 0; i < size; ++i) { - SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); - QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert); - systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der); - } - } else { - // no detailed error handling here - qCWarning(lcSsl) << "SecTrustSettingsCopyCertificates failed:" << status; - } -#endif - return systemCerts; -} - QSslSocketBackendPrivate::QSslSocketBackendPrivate() : context(Q_NULLPTR) { diff --git a/src/network/ssl/qsslsocket_mac_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp new file mode 100644 index 0000000000..b9ffd51da8 --- /dev/null +++ b/src/network/ssl/qsslsocket_mac_shared.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 ownCloud Inc +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//#define QSSLSOCKET_DEBUG +//#define QT_DECRYPT_SSL_TRAFFIC + +#include "qssl_p.h" +#include "qsslsocket.h" + +#ifndef QT_NO_OPENSSL +# include "qsslsocket_openssl_p.h" +# include "qsslsocket_openssl_symbols_p.h" +#endif + +#include "qsslcertificate_p.h" + +#ifdef Q_OS_DARWIN +# include <private/qcore_mac_p.h> +#endif + +#include <QtCore/qdebug.h> + +#ifdef Q_OS_OSX +# include <Security/Security.h> +#endif + + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_OSX +namespace { + +bool hasTrustedSslServerPolicy(SecPolicyRef policy, CFDictionaryRef props) { + QCFType<CFDictionaryRef> policyProps = SecPolicyCopyProperties(policy); + // only accept certificates with policies for SSL server validation for now + if (CFEqual(CFDictionaryGetValue(policyProps, kSecPolicyOid), kSecPolicyAppleSSL)) { + CFBooleanRef policyClient; + if (CFDictionaryGetValueIfPresent(policyProps, kSecPolicyClient, reinterpret_cast<const void**>(&policyClient)) && + CFEqual(policyClient, kCFBooleanTrue)) { + return false; // no client certs + } + if (!CFDictionaryContainsKey(props, kSecTrustSettingsResult)) { + // as per the docs, no trust settings result implies full trust + return true; + } + CFNumberRef number = static_cast<CFNumberRef>(CFDictionaryGetValue(props, kSecTrustSettingsResult)); + SecTrustSettingsResult settingsResult; + CFNumberGetValue(number, kCFNumberSInt32Type, &settingsResult); + switch (settingsResult) { + case kSecTrustSettingsResultTrustRoot: + case kSecTrustSettingsResultTrustAsRoot: + return true; + default: + return false; + } + } + return false; +} + +bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain) +{ + QCFType<CFArrayRef> cfTrustSettings; + OSStatus status = SecTrustSettingsCopyTrustSettings(cfCert, domain, &cfTrustSettings); + if (status == noErr) { + CFIndex size = CFArrayGetCount(cfTrustSettings); + // if empty, trust for everything (as per the Security Framework documentation) + if (size == 0) { + return true; + } else { + for (CFIndex i = 0; i < size; ++i) { + CFDictionaryRef props = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(cfTrustSettings, i)); + if (CFDictionaryContainsKey(props, kSecTrustSettingsPolicy)) { + if (hasTrustedSslServerPolicy((SecPolicyRef)CFDictionaryGetValue(props, kSecTrustSettingsPolicy), props)) + return true; + } + } + } + } else { + qCWarning(lcSsl, "Error receiving trust for a CA certificate"); + } + return false; +} + +} // anon namespace +#endif // Q_OS_OSX + +QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() +{ + ensureInitialized(); + + QList<QSslCertificate> systemCerts; + // SecTrustSettingsCopyCertificates is not defined on iOS. +#ifdef Q_OS_OSX + QCFType<CFArrayRef> cfCerts; + // iterate through all enum members, order: + // kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainSystem + for (int dom = kSecTrustSettingsDomainUser; dom <= kSecTrustSettingsDomainSystem; dom++) { + OSStatus status = SecTrustSettingsCopyCertificates(dom, &cfCerts); + if (status == noErr) { + const CFIndex size = CFArrayGetCount(cfCerts); + for (CFIndex i = 0; i < size; ++i) { + SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); + QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert); + if (::isCaCertificateTrusted(cfCert, dom)) { + if (derData == NULL) { + qCWarning(lcSsl, "Error retrieving a CA certificate from the system store"); + } else { + systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der); + } + } + } + } + } +#endif + return systemCerts; +} + +QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 31aeac9489..bbd712317c 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -76,15 +76,6 @@ #include <string.h> -#ifdef Q_OS_DARWIN -# include <private/qcore_mac_p.h> -#endif - -#ifdef Q_OS_OSX -# include <Security/Security.h> -#endif - - QT_BEGIN_NAMESPACE #if defined(Q_OS_WIN) @@ -668,6 +659,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves() setDefaultSupportedEllipticCurves(curves); } +#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() { ensureInitialized(); @@ -676,25 +668,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() timer.start(); #endif QList<QSslCertificate> systemCerts; - // note: also check implementation in openssl_mac.cpp -#if defined(Q_OS_OSX) - // SecTrustSettingsCopyCertificates is not defined on iOS. - QCFType<CFArrayRef> cfCerts; - - OSStatus status = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts); - if (status == noErr ) { - const CFIndex size = CFArrayGetCount(cfCerts); - for (CFIndex i = 0; i < size; ++i) { - SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); - QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert); - if (derData == NULL) { - qCWarning(lcSsl, "error retrieving a CA certificate from the system store"); - } else { - systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der); - } - } - } -#elif defined(Q_OS_WIN) +#if defined(Q_OS_WIN) if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) { HCERTSTORE hSystemStore; #if defined(Q_OS_WINCE) @@ -771,6 +745,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() return systemCerts; } +#endif // Q_OS_DARWIN void QSslSocketBackendPrivate::startClientEncryption() { diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index 29c47cd7c6..2173bf6ccc 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -46,6 +46,7 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op SOURCES += ssl/qsslcertificate_qt.cpp \ ssl/qsslkey_qt.cpp \ ssl/qsslkey_mac.cpp \ + ssl/qsslsocket_mac_shared.cpp \ ssl/qsslsocket_mac.cpp \ ssl/qsslellipticcurve_dummy.cpp } @@ -62,7 +63,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { ssl/qsslsocket_openssl.cpp \ ssl/qsslsocket_openssl_symbols.cpp -android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp + darwin:SOURCES += ssl/qsslsocket_mac_shared.cpp + + android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp # Add optional SSL libs # Static linking of OpenSSL with msvc: |