2015-11-25 14:42:58 +03:00
|
|
|
From 6b9366e7748857f14d5b0f92ced70c08ab5235b7 Mon Sep 17 00:00:00 2001
|
|
|
|
From: Daniel Molkentin <danimo@owncloud.com>
|
|
|
|
Date: Wed, 25 Nov 2015 12:37:27 +0100
|
2015-11-25 12:40:13 +03:00
|
|
|
Subject: [PATCH 2/2] QSslSocket: evaluate CAs in all keychain categories
|
|
|
|
|
|
|
|
This will make sure that certs in the domainUser (login),
|
|
|
|
and domainAdmin (per machine) keychain are being picked up
|
|
|
|
in systemCaCertificates() in addition to the (usually immutable)
|
|
|
|
DomainSystem keychain.
|
|
|
|
|
|
|
|
Also consider the trust settings on OS X: If a certificate
|
|
|
|
is either fully trusted or trusted for the purpose of SSL,
|
|
|
|
it will be accepted.
|
|
|
|
|
|
|
|
[ChangeLog][Platform Specific Changes] OS X now accepts trusted
|
|
|
|
certificates from the login and system keychains.
|
|
|
|
|
|
|
|
(Backport of fe3a84138e266c425f11353f7d8dc28a588af89e to Qt 5.4)
|
|
|
|
|
|
|
|
Task-number: QTBUG-32898
|
|
|
|
Change-Id: Ia23083d5af74388eeee31ba07239735cbbe64368
|
|
|
|
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
|
|
|
---
|
|
|
|
src/network/ssl/qsslsocket.cpp | 4 +
|
2015-11-25 14:42:58 +03:00
|
|
|
src/network/ssl/qsslsocket_mac_shared.cpp | 148 ++++++++++++++++++++++++++++++
|
2015-11-25 12:40:13 +03:00
|
|
|
src/network/ssl/qsslsocket_openssl.cpp | 30 +-----
|
|
|
|
src/network/ssl/ssl.pri | 4 +-
|
2015-11-25 14:42:58 +03:00
|
|
|
4 files changed, 158 insertions(+), 28 deletions(-)
|
2015-11-25 12:40:13 +03:00
|
|
|
create mode 100644 src/network/ssl/qsslsocket_mac_shared.cpp
|
|
|
|
|
|
|
|
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
|
|
|
|
index 8887f47..6347c20 100644
|
|
|
|
--- a/src/network/ssl/qsslsocket.cpp
|
|
|
|
+++ b/src/network/ssl/qsslsocket.cpp
|
|
|
|
@@ -1446,6 +1446,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
|
|
|
|
returned by defaultCaCertificates(). You can replace that database
|
|
|
|
with your own with setDefaultCaCertificates().
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
+ \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_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp
|
|
|
|
new file mode 100644
|
2015-11-25 14:42:58 +03:00
|
|
|
index 0000000..60fea4c
|
2015-11-25 12:40:13 +03:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/src/network/ssl/qsslsocket_mac_shared.cpp
|
2015-11-25 14:42:58 +03:00
|
|
|
@@ -0,0 +1,148 @@
|
2015-11-25 12:40:13 +03:00
|
|
|
+/****************************************************************************
|
|
|
|
+**
|
|
|
|
+** 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 "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 {
|
2015-11-25 14:42:58 +03:00
|
|
|
+ qWarning("Error receiving trust for a CA certificate");
|
2015-11-25 12:40:13 +03:00
|
|
|
+ }
|
|
|
|
+ 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) {
|
2015-11-25 14:42:58 +03:00
|
|
|
+ qWarning("Error retrieving a CA certificate from the system store");
|
2015-11-25 12:40:13 +03:00
|
|
|
+ } 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
|
2015-11-25 14:42:58 +03:00
|
|
|
index 7d0fe00..7415e32 100644
|
2015-11-25 12:40:13 +03:00
|
|
|
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
|
|
|
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
|
|
|
@@ -71,14 +71,6 @@
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
#include <string.h>
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
-#ifdef Q_OS_DARWIN
|
|
|
|
-# include <private/qcore_mac_p.h>
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-#ifdef Q_OS_OSX
|
|
|
|
-# include <Security/Security.h>
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
QT_BEGIN_NAMESPACE
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
@@ -616,6 +608,7 @@ void QSslSocketPrivate::resetDefaultCiphers()
|
|
|
|
setDefaultCiphers(defaultCiphers);
|
|
|
|
}
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
+#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp
|
|
|
|
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
|
|
|
{
|
|
|
|
ensureInitialized();
|
|
|
|
@@ -624,25 +617,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) {
|
2015-11-25 14:42:58 +03:00
|
|
|
- qWarning("error retrieving a CA certificate from the system store");
|
2015-11-25 12:40:13 +03:00
|
|
|
- } 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)
|
|
|
|
@@ -719,6 +694,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
return systemCerts;
|
|
|
|
}
|
|
|
|
+#endif // Q_OS_DARWIN
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
void QSslSocketBackendPrivate::startClientEncryption()
|
|
|
|
{
|
|
|
|
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
|
|
|
|
index 384e149..9546f18 100644
|
|
|
|
--- a/src/network/ssl/ssl.pri
|
|
|
|
+++ b/src/network/ssl/ssl.pri
|
|
|
|
@@ -45,7 +45,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
|
|
|
|
ssl/qsslsocket_openssl.cpp \
|
|
|
|
ssl/qsslsocket_openssl_symbols.cpp
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
-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
|
2015-11-25 14:42:58 +03:00
|
|
|
|
2015-11-25 12:40:13 +03:00
|
|
|
# Add optional SSL libs
|
|
|
|
# Static linking of OpenSSL with msvc:
|
2015-11-25 14:42:58 +03:00
|
|
|
--
|
2015-11-25 12:40:13 +03:00
|
|
|
1.9.1
|
2015-11-25 14:42:58 +03:00
|
|
|
|