summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp4
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp3
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp4
-rw-r--r--src/network/ssl/qsslsocket.cpp7
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp130
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp44
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp10
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h5
8 files changed, 195 insertions, 12 deletions
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index 6e5e29d7bf..e9b3760ce5 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -44,6 +44,7 @@
#include <QTimer>
#include <QAuthenticator>
#include <QEventLoop>
+#include <QCryptographicHash>
#include "private/qhttpnetworkreply_p.h"
#include "private/qnetworkaccesscache_p.h"
@@ -158,7 +159,10 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy)
}
if (!key.scheme().isEmpty()) {
+ const QByteArray obfuscatedPassword = QCryptographicHash::hash(proxy->password().toUtf8(),
+ QCryptographicHash::Sha1).toHex();
key.setUserName(proxy->user());
+ key.setPassword(QString::fromUtf8(obfuscatedPassword));
key.setHost(proxy->hostName());
key.setPort(proxy->port());
key.setQuery(result);
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index e140b33ce9..1e69aebb54 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -668,8 +668,7 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
mreq6.ipv6mr_interface = interface.index();
- } else
- if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
+ } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
level = IPPROTO_IP;
sockOpt = how4;
sockArg = &mreq4;
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 28aea6be3d..2088d3927e 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -943,9 +943,7 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
mreq6.ipv6mr_interface = iface.index();
- } else
-
- if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
+ } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
level = IPPROTO_IP;
sockOpt = how4;
sockArg = reinterpret_cast<char *>(&mreq4);
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index bb0d949684..b4109cadb5 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -971,6 +971,13 @@ QList<QSslCertificate> QSslSocket::localCertificateChain() const
sockets, but are also rarely used by client sockets if the server requires
the client to authenticate.
+ \note Secure Transport SSL backend on macOS may update the default keychain
+ (the default is probably your login keychain) by importing your local certificates
+ and keys. This can also result in system dialogs showing up and asking for
+ permission when your application is using these private keys. If such behavior
+ is undesired, set the QT_SSL_USE_TEMPORARY_KEYCHAIN environment variable to a
+ non-zero value; this will prompt QSslSocket to use its own temporary keychain.
+
\sa localCertificate(), setPrivateKey()
*/
void QSslSocket::setLocalCertificate(const QSslCertificate &certificate)
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index 752640bd46..07de954cef 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -53,9 +53,12 @@
#include <QtCore/qvector.h>
#include <QtCore/qmutex.h>
#include <QtCore/qdebug.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qdir.h>
#include <algorithm>
#include <cstddef>
+#include <vector>
#include <QtCore/private/qcore_mac_p.h>
@@ -65,6 +68,102 @@
QT_BEGIN_NAMESPACE
+namespace
+{
+#ifdef Q_OS_MACOS
+/*
+
+Our own temporarykeychain is needed only on macOS where SecPKCS12Import changes
+the default keychain and where we see annoying pop-ups asking about accessing a
+private key.
+
+*/
+
+struct EphemeralSecKeychain
+{
+ EphemeralSecKeychain();
+ ~EphemeralSecKeychain();
+
+ SecKeychainRef keychain = nullptr;
+ Q_DISABLE_COPY(EphemeralSecKeychain)
+};
+
+EphemeralSecKeychain::EphemeralSecKeychain()
+{
+ const auto uuid = QUuid::createUuid();
+ if (uuid.isNull()) {
+ qCWarning(lcSsl) << "Failed to create an unique keychain name";
+ return;
+ }
+
+ QString uuidAsString(uuid.toString());
+ Q_ASSERT(uuidAsString.size() > 2);
+ Q_ASSERT(uuidAsString.startsWith(QLatin1Char('{'))
+ && uuidAsString.endsWith(QLatin1Char('}')));
+ uuidAsString = uuidAsString.mid(1, uuidAsString.size() - 2);
+
+ QString keychainName(QDir::tempPath());
+ keychainName.append(QDir::separator());
+ keychainName += uuidAsString;
+ keychainName += QLatin1String(".keychain");
+ // SecKeychainCreate, pathName parameter:
+ //
+ // "A constant character string representing the POSIX path indicating where
+ // to store the keychain."
+ //
+ // Internally they seem to use std::string, but this does not really help.
+ // Fortunately, CFString has a convenient API.
+ QCFType<CFStringRef> cfName = keychainName.toCFString();
+ std::vector<char> posixPath;
+ // "Extracts the contents of a string as a NULL-terminated 8-bit string
+ // appropriate for passing to POSIX APIs."
+ posixPath.resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName));
+ const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
+ CFIndex(posixPath.size()));
+ if (!ok) {
+ qCWarning(lcSsl) << "Failed to create a unique keychain name from"
+ << "QDir::tempPath()";
+ return;
+ }
+
+ std::vector<uint8_t> passUtf8(256);
+ if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) {
+ qCWarning(lcSsl) << "SecRandomCopyBytes: failed to create a key";
+ return;
+ }
+
+ const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(),
+ &passUtf8[0], FALSE, nullptr,
+ &keychain);
+ if (status != errSecSuccess || !keychain) {
+ qCWarning(lcSsl) << "SecKeychainCreate: failed to create a custom keychain";
+ if (keychain) {
+ SecKeychainDelete(keychain);
+ CFRelease(keychain);
+ keychain = nullptr;
+ }
+ }
+
+#ifdef QSSLSOCKET_DEBUG
+ if (keychain) {
+ qCDebug(lcSsl) << "Custom keychain with name" << keychainName << "was created"
+ << "successfully";
+ }
+#endif
+}
+
+EphemeralSecKeychain::~EphemeralSecKeychain()
+{
+ if (keychain) {
+ // clear file off disk
+ SecKeychainDelete(keychain);
+ CFRelease(keychain);
+ }
+}
+
+#endif // Q_OS_MACOS
+}
+
static SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
{
const bool isServer = mode == QSslSocket::SslServerMode;
@@ -794,11 +893,24 @@ bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription,
QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain,
configuration.privateKey, passPhrase).toCFData();
QCFType<CFStringRef> password = passPhrase.toCFString();
- const void *keys[] = { kSecImportExportPassphrase };
- const void *values[] = { password };
- QCFType<CFDictionaryRef> options(CFDictionaryCreate(Q_NULLPTR, keys, values, 1,
- Q_NULLPTR, Q_NULLPTR));
- CFArrayRef items = Q_NULLPTR;
+ const void *keys[2] = { kSecImportExportPassphrase };
+ const void *values[2] = { password };
+ CFIndex nKeys = 1;
+#ifdef Q_OS_MACOS
+ bool envOk = false;
+ const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk);
+ if (envOk && env) {
+ static const EphemeralSecKeychain temporaryKeychain;
+ if (temporaryKeychain.keychain) {
+ nKeys = 2;
+ keys[1] = kSecImportExportKeychain;
+ values[1] = temporaryKeychain.keychain;
+ }
+ }
+#endif
+ QCFType<CFDictionaryRef> options = CFDictionaryCreate(nullptr, keys, values, nKeys,
+ nullptr, nullptr);
+ CFArrayRef items = nullptr;
OSStatus err = SecPKCS12Import(pkcs12, options, &items);
if (err != noErr) {
#ifdef QSSLSOCKET_DEBUG
@@ -830,7 +942,7 @@ bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription,
return false;
}
- QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(Q_NULLPTR, 0, &kCFTypeArrayCallBacks);
+ QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
if (!certs) {
errorCode = QAbstractSocket::SslInternalError;
errorDescription = QStringLiteral("Failed to allocate certificates array");
@@ -975,6 +1087,12 @@ bool QSslSocketBackendPrivate::verifySessionProtocol() const
protocolOk = (sessionProtocol() >= QSsl::SslV3);
else if (configuration.protocol == QSsl::SecureProtocols)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
+ else if (configuration.protocol == QSsl::TlsV1_0OrLater)
+ protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
+ else if (configuration.protocol == QSsl::TlsV1_1OrLater)
+ protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
+ else if (configuration.protocol == QSsl::TlsV1_2OrLater)
+ protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
else
protocolOk = (sessionProtocol() == configuration.protocol);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index aca7507d13..28576f1167 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -213,6 +213,48 @@ static unsigned int q_ssl_psk_server_callback(SSL *ssl,
#endif
} // extern "C"
+static void q_OpenSSL_add_all_algorithms_safe()
+{
+#ifdef Q_OS_WIN
+ // Prior to version 1.0.1m an attempt to call OpenSSL_add_all_algorithms on
+ // Windows could result in 'exit' call from OPENSSL_config (QTBUG-43843).
+ // We can predict this and avoid OPENSSL_add_all_algorithms call.
+ // From OpenSSL docs:
+ // "An application does not need to add algorithms to use them explicitly,
+ // for example by EVP_sha1(). It just needs to add them if it (or any of
+ // the functions it calls) needs to lookup algorithms.
+ // The cipher and digest lookup functions are used in many parts of the
+ // library. If the table is not initialized several functions will
+ // misbehave and complain they cannot find algorithms. This includes the
+ // PEM, PKCS#12, SSL and S/MIME libraries. This is a common query in
+ // the OpenSSL mailing lists."
+ //
+ // Anyway, as a result, we chose not to call this function if it would exit.
+
+ if (q_SSLeay() < 0x100010DFL)
+ {
+ // Now, before we try to call it, check if an attempt to open config file
+ // will result in exit:
+ if (char *confFileName = q_CONF_get1_default_config_file()) {
+ BIO *confFile = q_BIO_new_file(confFileName, "r");
+ const auto lastError = q_ERR_peek_last_error();
+ q_OPENSSL_free(confFileName);
+ if (confFile) {
+ q_BIO_free(confFile);
+ } else {
+ q_ERR_clear_error();
+ if (ERR_GET_REASON(lastError) == ERR_R_SYS_LIB) {
+ qCWarning(lcSsl, "failed to open openssl.conf file");
+ return;
+ }
+ }
+ }
+ }
+#endif // Q_OS_WIN
+
+ q_OpenSSL_add_all_algorithms();
+}
+
QSslSocketBackendPrivate::QSslSocketBackendPrivate()
: ssl(0),
readBio(0),
@@ -504,7 +546,7 @@ bool QSslSocketPrivate::ensureLibraryLoaded()
if (q_SSL_library_init() != 1)
return false;
q_SSL_load_error_strings();
- q_OpenSSL_add_all_algorithms();
+ q_OpenSSL_add_all_algorithms_safe();
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
if (q_SSLeay() >= 0x10001000L)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 2a0d746fde..02364b194b 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -144,6 +144,9 @@ DEFINEFUNC(unsigned char *, ASN1_STRING_data, ASN1_STRING *a, a, return 0, retur
DEFINEFUNC(int, ASN1_STRING_length, ASN1_STRING *a, a, return 0, return)
DEFINEFUNC2(int, ASN1_STRING_to_UTF8, unsigned char **a, a, ASN1_STRING *b, b, return 0, return);
DEFINEFUNC4(long, BIO_ctrl, BIO *a, a, int b, b, long c, c, void *d, d, return -1, return)
+DEFINEFUNC2(BIO *, BIO_new_file, const char *filename, filename, const char *mode, mode, return 0, return)
+DEFINEFUNC(void, ERR_clear_error, DUMMYARG, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC(void, OPENSSL_free, void *ptr, ptr, return, DUMMYARG)
DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return)
DEFINEFUNC(BIO *, BIO_new, BIO_METHOD *a, a, return 0, return)
DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return 0, return)
@@ -168,6 +171,7 @@ DEFINEFUNC(void, DSA_free, DSA *a, a, return, DUMMYARG)
DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, const unsigned char **b, b, long c, c, return 0, return)
DEFINEFUNC2(char *, ERR_error_string, unsigned long a, a, char *b, b, return 0, return)
DEFINEFUNC(unsigned long, ERR_get_error, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(unsigned long, ERR_peek_last_error, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, ERR_free_strings, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC(void, EVP_CIPHER_CTX_cleanup, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
DEFINEFUNC(void, EVP_CIPHER_CTX_init, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
@@ -407,6 +411,7 @@ DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c,
DEFINEFUNC3(EC_KEY *, d2i_ECPrivateKey, EC_KEY **a, a, unsigned char **b, b, long c, c, return 0, return)
#endif
#endif
+DEFINEFUNC(char *, CONF_get1_default_config_file, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
@@ -780,6 +785,9 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(ASN1_STRING_length)
RESOLVEFUNC(ASN1_STRING_to_UTF8)
RESOLVEFUNC(BIO_ctrl)
+ RESOLVEFUNC(BIO_new_file)
+ RESOLVEFUNC(ERR_clear_error)
+ RESOLVEFUNC(OPENSSL_free)
RESOLVEFUNC(BIO_free)
RESOLVEFUNC(BIO_new)
RESOLVEFUNC(BIO_new_mem_buf)
@@ -803,6 +811,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(DSA_free)
RESOLVEFUNC(ERR_error_string)
RESOLVEFUNC(ERR_get_error)
+ RESOLVEFUNC(ERR_peek_last_error)
RESOLVEFUNC(ERR_free_strings)
RESOLVEFUNC(EVP_CIPHER_CTX_cleanup)
RESOLVEFUNC(EVP_CIPHER_CTX_init)
@@ -992,6 +1001,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(d2i_DSAPrivateKey)
RESOLVEFUNC(d2i_RSAPrivateKey)
#endif
+ RESOLVEFUNC(CONF_get1_default_config_file)
RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf)
RESOLVEFUNC(OPENSSL_add_all_algorithms_conf)
RESOLVEFUNC(SSL_CTX_load_verify_locations)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index b35a895d38..68dc6da811 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -221,6 +221,9 @@ unsigned char * q_ASN1_STRING_data(ASN1_STRING *a);
int q_ASN1_STRING_length(ASN1_STRING *a);
int q_ASN1_STRING_to_UTF8(unsigned char **a, ASN1_STRING *b);
long q_BIO_ctrl(BIO *a, int b, long c, void *d);
+BIO *q_BIO_new_file(const char *filename, const char *mode);
+void q_ERR_clear_error();
+void q_OPENSSL_free(void *ptr);
Q_AUTOTEST_EXPORT int q_BIO_free(BIO *a);
Q_AUTOTEST_EXPORT BIO *q_BIO_new(BIO_METHOD *a);
BIO *q_BIO_new_mem_buf(void *a, int b);
@@ -256,6 +259,7 @@ void q_DSA_free(DSA *a);
X509 *q_d2i_X509(X509 **a, const unsigned char **b, long c);
char *q_ERR_error_string(unsigned long a, char *b);
unsigned long q_ERR_get_error();
+unsigned long q_ERR_peek_last_error();
void q_ERR_free_strings();
void q_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
void q_EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
@@ -565,6 +569,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
(char *)(dsa))
#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
+char *q_CONF_get1_default_config_file();
void q_OPENSSL_add_all_algorithms_noconf();
void q_OPENSSL_add_all_algorithms_conf();
int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);