QSslSocket: OpenSSL 1.1 backend

This patch-set implements a new QSslSocket backend based on OpenSSL 1.1.

1. General.

The code in this patch was organized to achieve these (somewhat contradicting)
objectives:
- keep the new code free of #if-ery, as far as possible;
- make it easy to clean away dead code when we're eventually able to retire
  out-dated OpenSSL versions;
- reduce the amount of code duplication.

If changes in some file/component were insignificant (~5 one-liners per file),
we still use pp-checks like: #if QT_CONFIG(opensslv11) ... #else ... #endif -
the logic is simple and it's still easy to clean the code if we remove the legacy
back-end. Where it saved #if-ery, we also introduced 'forward-compatible'
macros implementing equivalents of 1.1 functions using older OpenSSL.

In case some class contains a lot of version-specific ifdefs (particularly where
nested #if-ery was complex) we choose to split code into: "pre11" h/cpp files,
"shared" h/cpp files (they preserve their original names, e.g qsslsocket_openssl.cpp)
and "11" h/cpp files. If in future we remove the legacy back-end, "pre11" should be
removed; "shared" and "11" parts - merged.

2. Configuration.

We introduced a new feature 'opensslv11' which complements the pre-existing
'openssl' and 'openssl-linked' features. The 'opensslv11' feature is enabled
by a simple test which either compiles successfully or ends in a compilation
error, depending on a value of the OPENSSL_VERSION_NUMBER constant. If the
feature was enabled, we also append an additional compilation flag
-DOPENSSL_API_COMPAT=0x10100000L to make sure our new code does not contain
deprecated structures, function calls, macro-invocations from OpenSSL < 1.1.

Change-Id: I2064efbe9685def5d2bb2233a66f7581954fb74a
Reviewed-by: André Klitzing <aklitzing@gmail.com>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Richard J. Moore 2017-03-23 12:43:22 +01:00 committed by André Klitzing
parent 10de063ff1
commit cfbe03a6e0
20 changed files with 2338 additions and 1103 deletions

View File

@ -0,0 +1,48 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the config.tests of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <openssl/opensslv.h>
#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER-0 < 0x10100000L
# error "OpenSSL >= 1.1 is required"
#endif
int main()
{
}

View File

@ -0,0 +1,2 @@
SOURCES = openssl.cpp
CONFIG -= x11 qt

View File

@ -105,6 +105,12 @@
"type": "compile",
"test": "unix/sctp",
"use": "network"
},
"openssl11": {
"label": "OpenSSL v. 1.1 support",
"type": "compile",
"test": "unix/openssl11",
"use": "network"
}
},
@ -172,6 +178,11 @@
"condition": "config.winrt || features.securetransport || features.openssl",
"output": [ "publicFeature", "feature" ]
},
"opensslv11": {
"label": "OpenSSL v. 1.1",
"condition": "tests.openssl11",
"output": ["publicFeature", "feature"]
},
"sctp": {
"label": "SCTP",
"autoDetect": false,

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -64,12 +65,14 @@ bool QSslCertificate::operator==(const QSslCertificate &other) const
uint qHash(const QSslCertificate &key, uint seed) Q_DECL_NOTHROW
{
if (X509 * const x509 = key.d->x509) {
(void)q_X509_cmp(x509, x509); // populate x509->sha1_hash
// (if someone knows a better way...)
return qHashBits(x509->sha1_hash, SHA_DIGEST_LENGTH, seed);
} else {
return seed;
const EVP_MD *sha1 = q_EVP_sha1();
unsigned int len = 0;
unsigned char md[EVP_MAX_MD_SIZE];
q_X509_digest(x509, sha1, md, &len);
return qHashBits(md, len, seed);
}
return seed;
}
bool QSslCertificate::isNull() const
@ -89,8 +92,7 @@ QByteArray QSslCertificate::version() const
{
QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
if (d->versionString.isEmpty() && d->x509)
d->versionString =
QByteArray::number(qlonglong(q_ASN1_INTEGER_get(d->x509->cert_info->version)) + 1);
d->versionString = QByteArray::number(qlonglong(q_X509_get_version(d->x509)) + 1);
return d->versionString;
}
@ -99,7 +101,7 @@ QByteArray QSslCertificate::serialNumber() const
{
QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
if (d->serialNumberString.isEmpty() && d->x509) {
ASN1_INTEGER *serialNumber = d->x509->cert_info->serialNumber;
ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(d->x509);
QByteArray hexString;
hexString.reserve(serialNumber->length * 3);
for (int a = 0; a < serialNumber->length; ++a) {
@ -199,14 +201,15 @@ QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlter
continue;
}
const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(genName->d.ia5));
const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(genName->d.ia5));
const QString altName = QString::fromLatin1(altNameStr, len);
if (genName->type == GEN_DNS)
result.insert(QSsl::DnsEntry, altName);
else if (genName->type == GEN_EMAIL)
result.insert(QSsl::EmailEntry, altName);
}
q_sk_pop_free((STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_sk_free));
q_OPENSSL_sk_pop_free((OPENSSL_STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_OPENSSL_sk_free));
}
return result;
@ -235,25 +238,26 @@ QSslKey QSslCertificate::publicKey() const
QSslKey key;
key.d->type = QSsl::PublicKey;
X509_PUBKEY *xkey = d->x509->cert_info->key;
EVP_PKEY *pkey = q_X509_PUBKEY_get(xkey);
Q_ASSERT(pkey);
if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) {
EVP_PKEY *pkey = q_X509_get_pubkey(d->x509);
Q_ASSERT(pkey);
const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
if (keyType == EVP_PKEY_RSA) {
key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
key.d->algorithm = QSsl::Rsa;
key.d->isNull = false;
} else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
} else if (keyType == EVP_PKEY_DSA) {
key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
key.d->algorithm = QSsl::Dsa;
key.d->isNull = false;
#ifndef OPENSSL_NO_EC
} else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_EC) {
} else if (keyType == EVP_PKEY_EC) {
key.d->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
key.d->algorithm = QSsl::Ec;
key.d->isNull = false;
#endif
} else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) {
} else if (keyType == EVP_PKEY_DH) {
// DH unsupported
} else {
// error?
@ -275,7 +279,7 @@ static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
if (!meth) {
ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext);
QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_data(value)),
QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(value)),
q_ASN1_STRING_length(value));
return result;
}
@ -371,7 +375,7 @@ static QVariant x509ExtensionToValue(X509_EXTENSION *ext)
continue;
}
const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(name->d.uniformResourceIdentifier));
const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(name->d.uniformResourceIdentifier));
const QString uri = QString::fromUtf8(uriStr, len);
result[QString::fromUtf8(QSslCertificatePrivate::asn1ObjectName(ad->method))] = uri;
@ -380,11 +384,7 @@ static QVariant x509ExtensionToValue(X509_EXTENSION *ext)
}
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
q_sk_pop_free((_STACK*)info, reinterpret_cast<void(*)(void*)>(q_sk_free));
#else
q_sk_pop_free((STACK*)info, reinterpret_cast<void(*)(void*)>(q_sk_free));
#endif
q_OPENSSL_sk_pop_free((OPENSSL_STACK*)info, reinterpret_cast<void(*)(void *)>(q_OPENSSL_sk_free));
return result;
}
break;
@ -607,7 +607,11 @@ static QMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name)
unsigned char *data = 0;
int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
info.insertMulti(name, QString::fromUtf8((char*)data, size));
#if QT_CONFIG(opensslv11)
q_CRYPTO_free(data, 0, 0);
#else
q_CRYPTO_free(data);
#endif
}
return info;
@ -619,8 +623,9 @@ QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
if (!x509 || !QSslSocket::supportsSsl())
return certificate;
ASN1_TIME *nbef = q_X509_get_notBefore(x509);
ASN1_TIME *naft = q_X509_get_notAfter(x509);
ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
ASN1_TIME *naft = q_X509_getm_notAfter(x509);
certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
certificate.d->notValidAfter = q_getTimeFromASN1(naft);
certificate.d->null = false;

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Contact: https://www.qt.io/licensing/
@ -41,22 +41,14 @@
#include <QtNetwork/qsslsocket.h>
#include <QtNetwork/qssldiffiehellmanparameters.h>
#include <QtCore/qmutex.h>
#include "private/qssl_p.h"
#include "private/qsslcontext_openssl_p.h"
#include "private/qsslsocket_p.h"
#include "private/qsslsocket_openssl_p.h"
#include "private/qsslsocket_openssl_symbols_p.h"
#include "private/qssldiffiehellmanparameters_p.h"
QT_BEGIN_NAMESPACE
// defined in qsslsocket_openssl.cpp:
extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
extern QString getErrorsFromOpenSsl();
QSslContext::QSslContext()
: ctx(0),
pkey(0),
@ -78,301 +70,6 @@ QSslContext::~QSslContext()
q_SSL_SESSION_free(session);
}
static inline QString msgErrorSettingEllipticCurves(const QString &why)
{
return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
}
// static
void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
{
sslContext->sslConfiguration = configuration;
sslContext->errorCode = QSslError::NoError;
bool client = (mode == QSslSocket::SslClientMode);
bool reinitialized = false;
bool unsupportedProtocol = false;
init_context:
switch (sslContext->sslConfiguration.protocol()) {
case QSsl::SslV2:
#ifndef OPENSSL_NO_SSL2
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method());
#else
// SSL 2 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::SslV3:
#ifndef OPENSSL_NO_SSL3_METHOD
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method());
#else
// SSL 3 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::SecureProtocols:
// SSLv2 and SSLv3 will be disabled by SSL options
// But we need q_SSLv23_server_method() otherwise AnyProtocol will be unable to connect on Win32.
case QSsl::TlsV1SslV3:
// SSLv2 will will be disabled by SSL options
case QSsl::AnyProtocol:
default:
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
break;
case QSsl::TlsV1_0:
sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method());
break;
case QSsl::TlsV1_1:
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_1_client_method() : q_TLSv1_1_server_method());
#else
// TLS 1.1 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::TlsV1_2:
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_2_client_method() : q_TLSv1_2_server_method());
#else
// TLS 1.2 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::TlsV1_0OrLater:
// Specific protocols will be specified via SSL options.
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
break;
case QSsl::TlsV1_1OrLater:
case QSsl::TlsV1_2OrLater:
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
// Specific protocols will be specified via SSL options.
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
#else
// TLS 1.1/1.2 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
}
if (!sslContext->ctx) {
// After stopping Flash 10 the SSL library looses its ciphers. Try re-adding them
// by re-initializing the library.
if (!reinitialized) {
reinitialized = true;
if (q_SSL_library_init() == 1)
goto init_context;
}
sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QSslSocketBackendPrivate::getErrorsFromOpenSsl()
);
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// Enable bug workarounds.
long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
q_SSL_CTX_set_options(sslContext->ctx, options);
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
// Tell OpenSSL to release memory early
// http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
if (q_SSLeay() >= 0x10000000L)
q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
// Initialize ciphers
QByteArray cipherString;
bool first = true;
QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
if (ciphers.isEmpty())
ciphers = QSslSocketPrivate::defaultCiphers();
for (const QSslCipher &cipher : qAsConst(ciphers)) {
if (first)
first = false;
else
cipherString.append(':');
cipherString.append(cipher.name().toLatin1());
}
if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, cipherString.data())) {
sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
const QDateTime now = QDateTime::currentDateTimeUtc();
// Add all our CAs to this store.
const auto caCertificates = sslContext->sslConfiguration.caCertificates();
for (const QSslCertificate &caCertificate : caCertificates) {
// From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
//
// If several CA certificates matching the name, key identifier, and
// serial number condition are available, only the first one will be
// examined. This may lead to unexpected results if the same CA
// certificate is available with different expiration dates. If a
// ``certificate expired'' verification error occurs, no other
// certificate will be searched. Make sure to not have expired
// certificates mixed with valid ones.
//
// See also: QSslSocketBackendPrivate::verify()
if (caCertificate.expiryDate() >= now) {
q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle());
}
}
if (QSslSocketPrivate::s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
// tell OpenSSL the directories where to look up the root certs on demand
const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
for (const QByteArray &unixDir : unixDirs)
q_SSL_CTX_load_verify_locations(sslContext->ctx, 0, unixDir.constData());
}
if (!sslContext->sslConfiguration.localCertificate().isNull()) {
// Require a private key as well.
if (sslContext->sslConfiguration.privateKey().isNull()) {
sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// Load certificate
if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
} else {
// Load private key
sslContext->pkey = q_EVP_PKEY_new();
// before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
// this lead to a memory leak. Now we use the *_set1_* functions which do not
// take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
#ifndef OPENSSL_NO_EC
else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
#endif
}
if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, sslContext->pkey)) {
sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
sslContext->pkey = 0; // Don't free the private key, it belongs to QSslKey
// Check if the certificate matches the private key.
if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// If we have any intermediate certificates then we need to add them to our chain
bool first = true;
for (const QSslCertificate &cert : qAsConst(configuration.d->localCertificateChain)) {
if (first) {
first = false;
continue;
}
q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
}
}
// Initialize peer verification.
if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, 0);
} else {
q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_PEER, q_X509Callback);
}
// Set verification depth.
if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
// set persisted session if the user set it
if (!configuration.sessionTicket().isEmpty())
sslContext->setSessionASN1(configuration.sessionTicket());
// Set temp DH params
QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
if (!dhparams.isValid()) {
sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid");
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (!dhparams.isEmpty()) {
const QByteArray &params = dhparams.d->derData;
const char *ptr = params.constData();
DH *dh = q_d2i_DHparams(NULL, reinterpret_cast<const unsigned char **>(&ptr), params.length());
if (dh == NULL)
qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
q_DH_free(dh);
}
#ifndef OPENSSL_NO_EC
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L) {
q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL);
} else
#endif
{
// Set temp ECDH params
EC_KEY *ecdh = 0;
ecdh = q_EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
q_SSL_CTX_set_tmp_ecdh(sslContext->ctx, ecdh);
q_EC_KEY_free(ecdh);
}
#endif // OPENSSL_NO_EC
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
if (!client)
q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
#endif // OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
const QVector<QSslEllipticCurve> qcurves = sslContext->sslConfiguration.ellipticCurves();
if (!qcurves.isEmpty()) {
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
// Set the curves to be used
if (q_SSLeay() >= 0x10002000L) {
// SSL_CTX_ctrl wants a non-const pointer as last argument,
// but let's avoid a copy into a temporary array
if (!q_SSL_CTX_ctrl(sslContext->ctx,
SSL_CTRL_SET_CURVES,
qcurves.size(),
const_cast<int *>(reinterpret_cast<const int *>(qcurves.data())))) {
sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
}
} else
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
{
// specific curves requested, but not possible to set -> error
sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version too old, need at least v1.0.2"));
sslContext->errorCode = QSslError::UnspecifiedError;
}
}
}
QSslContext* QSslContext::fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
{
QSslContext *sslContext = new QSslContext();
@ -463,7 +160,7 @@ SSL* QSslContext::createSsl()
m_npnContext.len = m_supportedNPNVersions.count();
m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L) {
if (QSslSocket::sslLibraryVersionNumber() >= 0x10002000L) {
// Callback's type has a parameter 'const unsigned char ** out'
// since it was introduced in 1.0.2. Internally, OpenSSL's own code
// (tests/examples) cast it to unsigned char * (since it's 'out').
@ -508,7 +205,7 @@ bool QSslContext::cacheSession(SSL* ssl)
unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data());
if (!q_i2d_SSL_SESSION(session, &data))
qCWarning(lcSsl, "could not store persistent version of SSL session");
m_sessionTicketLifeTimeHint = session->tlsext_tick_lifetime_hint;
m_sessionTicketLifeTimeHint = q_SSL_SESSION_get_ticket_lifetime_hint(session);
}
}

View File

@ -0,0 +1,277 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtNetwork/qsslsocket.h>
#include <QtNetwork/qssldiffiehellmanparameters.h>
#include "private/qssl_p.h"
#include "private/qsslcontext_openssl_p.h"
#include "private/qsslsocket_p.h"
#include "private/qsslsocket_openssl_p.h"
#include "private/qsslsocket_openssl_symbols_p.h"
#include "private/qssldiffiehellmanparameters_p.h"
#include <vector>
QT_BEGIN_NAMESPACE
// defined in qsslsocket_openssl.cpp:
extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
extern QString getErrorsFromOpenSsl();
static inline QString msgErrorSettingEllipticCurves(const QString &why)
{
return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
}
// static
void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
{
sslContext->sslConfiguration = configuration;
sslContext->errorCode = QSslError::NoError;
bool client = (mode == QSslSocket::SslClientMode);
bool reinitialized = false;
bool unsupportedProtocol = false;
init_context:
if (sslContext->sslConfiguration.protocol() == QSsl::SslV2) {
// SSL 2 is no longer supported, but chosen deliberately -> error
sslContext->ctx = nullptr;
unsupportedProtocol = true;
} else {
// The ssl options will actually control the supported methods
sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method());
}
if (!sslContext->ctx) {
// After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them
// by re-initializing the library.
if (!reinitialized) {
reinitialized = true;
if (q_OPENSSL_init_ssl(0, nullptr) == 1)
goto init_context;
}
sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QSslSocketBackendPrivate::getErrorsFromOpenSsl()
);
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// Enable bug workarounds.
long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
q_SSL_CTX_set_options(sslContext->ctx, options);
// Tell OpenSSL to release memory early
// http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
// Initialize ciphers
QByteArray cipherString;
bool first = true;
QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
if (ciphers.isEmpty())
ciphers = QSslSocketPrivate::defaultCiphers();
for (const QSslCipher &cipher : qAsConst(ciphers)) {
if (first)
first = false;
else
cipherString.append(':');
cipherString.append(cipher.name().toLatin1());
}
if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, cipherString.data())) {
sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
const QDateTime now = QDateTime::currentDateTimeUtc();
// Add all our CAs to this store.
const auto caCertificates = sslContext->sslConfiguration.caCertificates();
for (const QSslCertificate &caCertificate : caCertificates) {
// From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
//
// If several CA certificates matching the name, key identifier, and
// serial number condition are available, only the first one will be
// examined. This may lead to unexpected results if the same CA
// certificate is available with different expiration dates. If a
// ``certificate expired'' verification error occurs, no other
// certificate will be searched. Make sure to not have expired
// certificates mixed with valid ones.
//
// See also: QSslSocketBackendPrivate::verify()
if (caCertificate.expiryDate() >= now) {
q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle());
}
}
if (QSslSocketPrivate::s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
// tell OpenSSL the directories where to look up the root certs on demand
const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
for (const QByteArray &unixDir : unixDirs)
q_SSL_CTX_load_verify_locations(sslContext->ctx, nullptr, unixDir.constData());
}
if (!sslContext->sslConfiguration.localCertificate().isNull()) {
// Require a private key as well.
if (sslContext->sslConfiguration.privateKey().isNull()) {
sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// Load certificate
if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
} else {
// Load private key
sslContext->pkey = q_EVP_PKEY_new();
// before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
// this lead to a memory leak. Now we use the *_set1_* functions which do not
// take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
#ifndef OPENSSL_NO_EC
else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
#endif
}
if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, sslContext->pkey)) {
sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
// Check if the certificate matches the private key.
if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// If we have any intermediate certificates then we need to add them to our chain
bool first = true;
for (const QSslCertificate &cert : qAsConst(configuration.d->localCertificateChain)) {
if (first) {
first = false;
continue;
}
q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
}
}
// Initialize peer verification.
if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, nullptr);
} else {
q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_PEER, q_X509Callback);
}
// Set verification depth.
if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
// set persisted session if the user set it
if (!configuration.sessionTicket().isEmpty())
sslContext->setSessionASN1(configuration.sessionTicket());
// Set temp DH params
QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
if (!dhparams.isValid()) {
sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid");
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (!dhparams.isEmpty()) {
const QByteArray &params = dhparams.d->derData;
const char *ptr = params.constData();
DH *dh = q_d2i_DHparams(NULL, reinterpret_cast<const unsigned char **>(&ptr), params.length());
if (dh == NULL)
qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
q_DH_free(dh);
}
#ifndef OPENSSL_NO_PSK
if (!client)
q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
#endif // !OPENSSL_NO_PSK
const QVector<QSslEllipticCurve> qcurves = sslContext->sslConfiguration.ellipticCurves();
if (!qcurves.isEmpty()) {
#ifdef OPENSSL_NO_EC
sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves"));
sslContext->errorCode = QSslError::UnspecifiedError;
#else
// Set the curves to be used.
std::vector<int> curves;
curves.reserve(qcurves.size());
for (const auto &sslCurve : qcurves)
curves.push_back(sslCurve.id);
if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) {
sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
}
#endif
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,354 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtNetwork/qsslsocket.h>
#include <QtNetwork/qssldiffiehellmanparameters.h>
#include "private/qssl_p.h"
#include "private/qsslcontext_openssl_p.h"
#include "private/qsslsocket_p.h"
#include "private/qsslsocket_openssl_p.h"
#include "private/qsslsocket_openssl_symbols_p.h"
#include "private/qssldiffiehellmanparameters_p.h"
QT_BEGIN_NAMESPACE
// defined in qsslsocket_openssl.cpp:
extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
extern QString getErrorsFromOpenSsl();
static inline QString msgErrorSettingEllipticCurves(const QString &why)
{
return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
}
// static
void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
{
sslContext->sslConfiguration = configuration;
sslContext->errorCode = QSslError::NoError;
bool client = (mode == QSslSocket::SslClientMode);
bool reinitialized = false;
bool unsupportedProtocol = false;
init_context:
switch (sslContext->sslConfiguration.protocol()) {
case QSsl::SslV2:
#ifndef OPENSSL_NO_SSL2
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method());
#else
// SSL 2 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::SslV3:
#ifndef OPENSSL_NO_SSL3_METHOD
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method());
#else
// SSL 3 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::SecureProtocols:
// SSLv2 and SSLv3 will be disabled by SSL options
// But we need q_SSLv23_server_method() otherwise AnyProtocol will be unable to connect on Win32.
case QSsl::TlsV1SslV3:
// SSLv2 will will be disabled by SSL options
case QSsl::AnyProtocol:
default:
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
break;
case QSsl::TlsV1_0:
sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method());
break;
case QSsl::TlsV1_1:
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_1_client_method() : q_TLSv1_1_server_method());
#else
// TLS 1.1 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::TlsV1_2:
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_2_client_method() : q_TLSv1_2_server_method());
#else
// TLS 1.2 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
case QSsl::TlsV1_0OrLater:
// Specific protocols will be specified via SSL options.
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
break;
case QSsl::TlsV1_1OrLater:
case QSsl::TlsV1_2OrLater:
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
// Specific protocols will be specified via SSL options.
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
#else
// TLS 1.1/1.2 not supported by the system, but chosen deliberately -> error
sslContext->ctx = 0;
unsupportedProtocol = true;
#endif
break;
}
if (!sslContext->ctx) {
// After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them
// by re-initializing the library.
if (!reinitialized) {
reinitialized = true;
if (q_SSL_library_init() == 1)
goto init_context;
}
sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QSslSocketBackendPrivate::getErrorsFromOpenSsl()
);
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// Enable bug workarounds.
long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
q_SSL_CTX_set_options(sslContext->ctx, options);
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
// Tell OpenSSL to release memory early
// http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
if (q_SSLeay() >= 0x10000000L)
q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
// Initialize ciphers
QByteArray cipherString;
bool first = true;
QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
if (ciphers.isEmpty())
ciphers = QSslSocketPrivate::defaultCiphers();
for (const QSslCipher &cipher : qAsConst(ciphers)) {
if (first)
first = false;
else
cipherString.append(':');
cipherString.append(cipher.name().toLatin1());
}
if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, cipherString.data())) {
sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
const QDateTime now = QDateTime::currentDateTimeUtc();
// Add all our CAs to this store.
const auto caCertificates = sslContext->sslConfiguration.caCertificates();
for (const QSslCertificate &caCertificate : caCertificates) {
// From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
//
// If several CA certificates matching the name, key identifier, and
// serial number condition are available, only the first one will be
// examined. This may lead to unexpected results if the same CA
// certificate is available with different expiration dates. If a
// ``certificate expired'' verification error occurs, no other
// certificate will be searched. Make sure to not have expired
// certificates mixed with valid ones.
//
// See also: QSslSocketBackendPrivate::verify()
if (caCertificate.expiryDate() >= now) {
q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle());
}
}
if (QSslSocketPrivate::s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
// tell OpenSSL the directories where to look up the root certs on demand
const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
for (const QByteArray &unixDir : unixDirs)
q_SSL_CTX_load_verify_locations(sslContext->ctx, 0, unixDir.constData());
}
if (!sslContext->sslConfiguration.localCertificate().isNull()) {
// Require a private key as well.
if (sslContext->sslConfiguration.privateKey().isNull()) {
sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// Load certificate
if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
} else {
// Load private key
sslContext->pkey = q_EVP_PKEY_new();
// before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
// this lead to a memory leak. Now we use the *_set1_* functions which do not
// take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
#ifndef OPENSSL_NO_EC
else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
#endif
}
if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, sslContext->pkey)) {
sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
sslContext->pkey = 0; // Don't free the private key, it belongs to QSslKey
// Check if the certificate matches the private key.
if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
// If we have any intermediate certificates then we need to add them to our chain
bool first = true;
for (const QSslCertificate &cert : qAsConst(configuration.d->localCertificateChain)) {
if (first) {
first = false;
continue;
}
q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
}
}
// Initialize peer verification.
if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, 0);
} else {
q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_PEER, q_X509Callback);
}
// Set verification depth.
if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
// set persisted session if the user set it
if (!configuration.sessionTicket().isEmpty())
sslContext->setSessionASN1(configuration.sessionTicket());
// Set temp DH params
QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
if (!dhparams.isValid()) {
sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid");
sslContext->errorCode = QSslError::UnspecifiedError;
return;
}
if (!dhparams.isEmpty()) {
const QByteArray &params = dhparams.d->derData;
const char *ptr = params.constData();
DH *dh = q_d2i_DHparams(NULL, reinterpret_cast<const unsigned char **>(&ptr), params.length());
if (dh == NULL)
qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
q_DH_free(dh);
}
#ifndef OPENSSL_NO_EC
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L) {
q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL);
} else
#endif
{
// Set temp ECDH params
EC_KEY *ecdh = 0;
ecdh = q_EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
q_SSL_CTX_set_tmp_ecdh(sslContext->ctx, ecdh);
q_EC_KEY_free(ecdh);
}
#endif // OPENSSL_NO_EC
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
if (!client)
q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
#endif // OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
const QVector<QSslEllipticCurve> qcurves = sslContext->sslConfiguration.ellipticCurves();
if (!qcurves.isEmpty()) {
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
// Set the curves to be used
if (q_SSLeay() >= 0x10002000L) {
// SSL_CTX_ctrl wants a non-const pointer as last argument,
// but let's avoid a copy into a temporary array
if (!q_SSL_CTX_ctrl(sslContext->ctx,
SSL_CTRL_SET_CURVES,
qcurves.size(),
const_cast<int *>(reinterpret_cast<const int *>(qcurves.data())))) {
sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
sslContext->errorCode = QSslError::UnspecifiedError;
}
} else
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
{
// specific curves requested, but not possible to set -> error
sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version too old, need at least v1.0.2"));
sslContext->errorCode = QSslError::UnspecifiedError;
}
}
}
QT_END_NAMESPACE

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -50,8 +51,8 @@
#include <QtCore/qdebug.h>
#endif
// For q_BN_is_word.
#include <openssl/bn.h>
#include <openssl/dh.h>
QT_BEGIN_NAMESPACE
@ -62,13 +63,6 @@ static bool isSafeDH(DH *dh)
QSslSocketPrivate::ensureInitialized();
// Mark p < 1024 bits as unsafe.
if (q_BN_num_bits(dh->p) < 1024) {
return false;
}
if (q_DH_check(dh, &status) != 1)
return false;
// From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters:
//
@ -81,11 +75,39 @@ static bool isSafeDH(DH *dh)
// Without the test, the IETF parameters would
// fail validation. For details, see Diffie-Hellman
// Parameter Check (when g = 2, must p mod 24 == 11?).
#if QT_CONFIG(opensslv11)
// Mark p < 1024 bits as unsafe.
if (q_DH_bits(dh) < 1024)
return false;
if (q_DH_check(dh, &status) != 1)
return false;
const BIGNUM *p = nullptr;
const BIGNUM *q = nullptr;
const BIGNUM *g = nullptr;
q_DH_get0_pqg(dh, &p, &q, &g);
if (q_BN_is_word(const_cast<BIGNUM *>(g), DH_GENERATOR_2)) {
long residue = q_BN_mod_word(p, 24);
if (residue == 11 || residue == 23)
status &= ~DH_NOT_SUITABLE_GENERATOR;
}
#else
// Mark p < 1024 bits as unsafe.
if (q_BN_num_bits(dh->p) < 1024)
return false;
if (q_DH_check(dh, &status) != 1)
return false;
if (q_BN_is_word(dh->g, DH_GENERATOR_2)) {
long residue = q_BN_mod_word(dh->p, 24);
if (residue == 11 || residue == 23)
status &= ~DH_NOT_SUITABLE_GENERATOR;
}
#endif
bad |= DH_CHECK_P_NOT_PRIME;
bad |= DH_CHECK_P_NOT_SAFE_PRIME;

View File

@ -80,6 +80,7 @@ private:
friend Q_DECL_CONSTEXPR bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) Q_DECL_NOTHROW;
friend Q_DECL_CONSTEXPR uint qHash(QSslEllipticCurve curve, uint seed) Q_DECL_NOTHROW;
friend class QSslContext;
friend class QSslSocketPrivate;
friend class QSslSocketBackendPrivate;
};

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -78,17 +79,18 @@ QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
QSslEllipticCurve result;
#ifndef OPENSSL_NO_EC
const QByteArray curveNameLatin1 = name.toLatin1();
const QByteArray curveNameLatin1 = name.toLatin1();
int nid = q_OBJ_sn2nid(curveNameLatin1.data());
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (nid == 0 && q_SSLeay() >= 0x10002000L)
if (nid == 0 && QSslSocket::sslLibraryVersionNumber() >= 0x10002000L)
nid = q_EC_curve_nist2nid(curveNameLatin1.data());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
result.id = nid;
#endif
#endif // !OPENSSL_NO_EC
return result;
}

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -84,33 +85,30 @@ void QSslKeyPrivate::clear(bool deep)
bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
{
if (pkey->type == EVP_PKEY_RSA) {
#if QT_CONFIG(opensslv11)
const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
#else
const int keyType = pkey->type;
#endif
if (keyType == EVP_PKEY_RSA) {
isNull = false;
algorithm = QSsl::Rsa;
type = QSsl::PrivateKey;
rsa = q_RSA_new();
memcpy(rsa, q_EVP_PKEY_get1_RSA(pkey), sizeof(RSA));
rsa = q_EVP_PKEY_get1_RSA(pkey);
return true;
}
else if (pkey->type == EVP_PKEY_DSA) {
} else if (keyType == EVP_PKEY_DSA) {
isNull = false;
algorithm = QSsl::Dsa;
type = QSsl::PrivateKey;
dsa = q_DSA_new();
memcpy(dsa, q_EVP_PKEY_get1_DSA(pkey), sizeof(DSA));
dsa = q_EVP_PKEY_get1_DSA(pkey);
return true;
}
#ifndef OPENSSL_NO_EC
else if (pkey->type == EVP_PKEY_EC) {
else if (keyType == EVP_PKEY_EC) {
isNull = false;
algorithm = QSsl::Ec;
type = QSsl::PrivateKey;
ec = q_EC_KEY_dup(q_EVP_PKEY_get1_EC_KEY(pkey));
ec = q_EVP_PKEY_get1_EC_KEY(pkey);
return true;
}
#endif
@ -178,8 +176,8 @@ int QSslKeyPrivate::length() const
return -1;
switch (algorithm) {
case QSsl::Rsa: return q_BN_num_bits(rsa->n);
case QSsl::Dsa: return q_BN_num_bits(dsa->p);
case QSsl::Rsa: return q_RSA_bits(rsa);
case QSsl::Dsa: return q_DSA_bits(dsa);
#ifndef OPENSSL_NO_EC
case QSsl::Ec: return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec));
#endif
@ -273,7 +271,13 @@ Qt::HANDLE QSslKeyPrivate::handle() const
static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, int enc)
{
EVP_CIPHER_CTX ctx;
#if QT_CONFIG(opensslv11)
EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new();
#else
EVP_CIPHER_CTX evpCipherContext;
EVP_CIPHER_CTX *ctx = &evpCipherContext;
#endif
const EVP_CIPHER* type = 0;
int i = 0, len = 0;
@ -291,21 +295,44 @@ static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
QByteArray output;
output.resize(data.size() + EVP_MAX_BLOCK_LENGTH);
q_EVP_CIPHER_CTX_init(&ctx);
q_EVP_CipherInit(&ctx, type, NULL, NULL, enc);
q_EVP_CIPHER_CTX_set_key_length(&ctx, key.size());
#if QT_CONFIG(opensslv11)
q_EVP_CIPHER_CTX_reset(ctx);
#else
q_EVP_CIPHER_CTX_init(ctx);
#endif
q_EVP_CipherInit(ctx, type, NULL, NULL, enc);
q_EVP_CIPHER_CTX_set_key_length(ctx, key.size());
if (cipher == QSslKeyPrivate::Rc2Cbc)
q_EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), NULL);
q_EVP_CipherInit(&ctx, NULL,
q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), NULL);
#if QT_CONFIG(opensslv11)
// EVP_CipherInit in 1.1 resets the context thus making the calls above useless.
// We call EVP_CipherInit_ex instead.
q_EVP_CipherInit_ex(ctx, nullptr, nullptr,
reinterpret_cast<const unsigned char *>(key.constData()),
reinterpret_cast<const unsigned char *>(iv.constData()),
enc);
#else
q_EVP_CipherInit(ctx, NULL,
reinterpret_cast<const unsigned char *>(key.constData()),
reinterpret_cast<const unsigned char *>(iv.constData()), enc);
q_EVP_CipherUpdate(&ctx,
#endif // opensslv11
q_EVP_CipherUpdate(ctx,
reinterpret_cast<unsigned char *>(output.data()), &len,
reinterpret_cast<const unsigned char *>(data.constData()), data.size());
q_EVP_CipherFinal(&ctx,
q_EVP_CipherFinal(ctx,
reinterpret_cast<unsigned char *>(output.data()) + len, &i);
len += i;
q_EVP_CIPHER_CTX_cleanup(&ctx);
#if QT_CONFIG(opensslv11)
q_EVP_CIPHER_CTX_reset(ctx);
q_EVP_CIPHER_CTX_free(ctx);
#else
q_EVP_CIPHER_CTX_cleanup(ctx);
#endif
return output.left(len);
}

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 Governikus GmbH & Co. KG
** Contact: https://www.qt.io/licensing/
**
@ -97,70 +97,6 @@ bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
int QSslSocketBackendPrivate::s_indexForSSLExtraData = -1;
#endif
/* \internal
From OpenSSL's thread(3) manual page:
OpenSSL can safely be used in multi-threaded applications provided that at
least two callback functions are set.
locking_function(int mode, int n, const char *file, int line) is needed to
perform locking on shared data structures. (Note that OpenSSL uses a
number of global data structures that will be implicitly shared
whenever multiple threads use OpenSSL.) Multi-threaded
applications will crash at random if it is not set. ...
...
id_function(void) is a function that returns a thread ID. It is not
needed on Windows nor on platforms where getpid() returns a different
ID for each thread (most notably Linux)
*/
class QOpenSslLocks
{
public:
inline QOpenSslLocks()
: initLocker(QMutex::Recursive),
locksLocker(QMutex::Recursive)
{
QMutexLocker locker(&locksLocker);
int numLocks = q_CRYPTO_num_locks();
locks = new QMutex *[numLocks];
memset(locks, 0, numLocks * sizeof(QMutex *));
}
inline ~QOpenSslLocks()
{
QMutexLocker locker(&locksLocker);
for (int i = 0; i < q_CRYPTO_num_locks(); ++i)
delete locks[i];
delete [] locks;
QSslSocketPrivate::deinitialize();
}
inline QMutex *lock(int num)
{
QMutexLocker locker(&locksLocker);
QMutex *tmp = locks[num];
if (!tmp)
tmp = locks[num] = new QMutex(QMutex::Recursive);
return tmp;
}
QMutex *globalLock()
{
return &locksLocker;
}
QMutex *initLock()
{
return &initLocker;
}
private:
QMutex initLocker;
QMutex locksLocker;
QMutex **locks;
};
Q_GLOBAL_STATIC(QOpenSslLocks, openssl_locks)
QString QSslSocketBackendPrivate::getErrorsFromOpenSsl()
{
QString errorString;
@ -175,20 +111,6 @@ QString QSslSocketBackendPrivate::getErrorsFromOpenSsl()
}
extern "C" {
static void locking_function(int mode, int lockNumber, const char *, int)
{
QMutex *mutex = openssl_locks()->lock(lockNumber);
// Lock or unlock it
if (mode & CRYPTO_LOCK)
mutex->lock();
else
mutex->unlock();
}
static unsigned long id_function()
{
return (quintptr)QThread::currentThreadId();
}
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
static unsigned int q_ssl_psk_client_callback(SSL *ssl,
@ -212,48 +134,6 @@ 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),
@ -269,7 +149,7 @@ QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
destroySslContext();
}
QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher)
QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher)
{
QSslCipher ciph;
@ -310,7 +190,8 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *ciph
}
// static
inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx) {
inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
{
return {
q_X509_STORE_CTX_get_error(ctx),
q_X509_STORE_CTX_get_error_depth(ctx)
@ -324,6 +205,7 @@ struct QSslErrorList
QMutex mutex;
QVector<QSslErrorEntry> errors;
};
Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList)
int q_X509Callback(int ok, X509_STORE_CTX *ctx)
@ -353,7 +235,7 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx)
}
#endif
}
// Always return OK to allow verification to continue. We're handle the
// Always return OK to allow verification to continue. We handle the
// errors gracefully after collecting all errors, after verification has
// completed.
return 1;
@ -438,7 +320,7 @@ bool QSslSocketBackendPrivate::initSslContext()
if (configuration.protocol != QSsl::SslV2 &&
configuration.protocol != QSsl::SslV3 &&
configuration.protocol != QSsl::UnknownProtocol &&
mode == QSslSocket::SslClientMode && q_SSLeay() >= 0x00090806fL) {
mode == QSslSocket::SslClientMode && QSslSocket::sslLibraryVersionNumber() >= 0x00090806fL) {
// Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
if (tlsHostName.isEmpty())
@ -479,13 +361,13 @@ bool QSslSocketBackendPrivate::initSslContext()
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
// Save a pointer to this object into the SSL structure.
if (q_SSLeay() >= 0x10001000L)
if (QSslSocket::sslLibraryVersionNumber() >= 0x10001000L)
q_SSL_set_ex_data(ssl, s_indexForSSLExtraData, this);
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
// Set the client callback for PSK
if (q_SSLeay() >= 0x10001000L) {
if (QSslSocket::sslLibraryVersionNumber() >= 0x10001000L) {
if (mode == QSslSocket::SslClientMode)
q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
else if (mode == QSslSocket::SslServerMode)
@ -505,16 +387,6 @@ void QSslSocketBackendPrivate::destroySslContext()
sslContextPointer.clear();
}
/*!
\internal
*/
void QSslSocketPrivate::deinitialize()
{
q_CRYPTO_set_id_callback(0);
q_CRYPTO_set_locking_callback(0);
q_ERR_free_strings();
}
/*!
\internal
@ -527,91 +399,6 @@ bool QSslSocketPrivate::supportsSsl()
return ensureLibraryLoaded();
}
bool QSslSocketPrivate::ensureLibraryLoaded()
{
if (!q_resolveOpenSslSymbols())
return false;
// Check if the library itself needs to be initialized.
QMutexLocker locker(openssl_locks()->initLock());
if (!s_libraryLoaded) {
s_libraryLoaded = true;
// Initialize OpenSSL.
q_CRYPTO_set_id_callback(id_function);
q_CRYPTO_set_locking_callback(locking_function);
if (q_SSL_library_init() != 1)
return false;
q_SSL_load_error_strings();
q_OpenSSL_add_all_algorithms_safe();
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
if (q_SSLeay() >= 0x10001000L)
QSslSocketBackendPrivate::s_indexForSSLExtraData = q_SSL_get_ex_new_index(0L, NULL, NULL, NULL, NULL);
#endif
// Initialize OpenSSL's random seed.
if (!q_RAND_status()) {
qWarning("Random number generator not seeded, disabling SSL support");
return false;
}
}
return true;
}
void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
{
QMutexLocker locker(openssl_locks()->initLock());
if (s_loadedCiphersAndCerts)
return;
s_loadedCiphersAndCerts = true;
resetDefaultCiphers();
resetDefaultEllipticCurves();
#if QT_CONFIG(library)
//load symbols needed to receive certificates from system store
#if defined(Q_OS_WIN)
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
if (hLib) {
ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW");
ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore");
ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore");
if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore)
qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen
} else {
qCWarning(lcSsl, "could not load crypt32 library"); // should never happen
}
#elif defined(Q_OS_QNX)
s_loadRootCertsOnDemand = true;
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
// check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
QList<QByteArray> dirs = unixRootCertDirectories();
QStringList symLinkFilter;
symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
for (int a = 0; a < dirs.count(); ++a) {
QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
if (iterator.hasNext()) {
s_loadRootCertsOnDemand = true;
break;
}
}
#endif
#endif // QT_CONFIG(library)
// if on-demand loading was not enabled, load the certs now
if (!s_loadRootCertsOnDemand)
setDefaultCaCertificates(systemCaCertificates());
#ifdef Q_OS_WIN
//Enabled for fetching additional root certs from windows update on windows 6+
//This flag is set false by setDefaultCaCertificates() indicating the app uses
//its own cert bundle rather than the system one.
//Same logic that disables the unix on demand cert loading.
//Unlike unix, we do preload the certificates from the cert store.
if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_6_0)
s_loadRootCertsOnDemand = true;
#endif
}
/*!
\internal
@ -628,26 +415,6 @@ void QSslSocketPrivate::ensureInitialized()
ensureCiphersAndCertsLoaded();
}
long QSslSocketPrivate::sslLibraryVersionNumber()
{
if (!supportsSsl())
return 0;
return q_SSLeay();
}
QString QSslSocketPrivate::sslLibraryVersionString()
{
if (!supportsSsl())
return QString();
const char *versionString = q_SSLeay_version(SSLEAY_VERSION);
if (!versionString)
return QString();
return QString::fromLatin1(versionString);
}
long QSslSocketPrivate::sslLibraryBuildVersionNumber()
{
return OPENSSL_VERSION_NUMBER;
@ -669,7 +436,11 @@ QString QSslSocketPrivate::sslLibraryBuildVersionString()
*/
void QSslSocketPrivate::resetDefaultCiphers()
{
#if QT_CONFIG(opensslv11)
SSL_CTX *myCtx = q_SSL_CTX_new(q_TLS_client_method());
#else
SSL_CTX *myCtx = q_SSL_CTX_new(q_SSLv23_client_method());
#endif
SSL *mySsl = q_SSL_new(myCtx);
QList<QSslCipher> ciphers;
@ -705,7 +476,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves()
QVector<QSslEllipticCurve> curves;
#ifndef OPENSSL_NO_EC
const size_t curveCount = q_EC_get_builtin_curves(NULL, 0);
const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0);
QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount));
@ -739,13 +510,14 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) {
HCERTSTORE hSystemStore;
hSystemStore = ptrCertOpenSystemStoreW(0, L"ROOT");
if(hSystemStore) {
PCCERT_CONTEXT pc = NULL;
while(1) {
pc = ptrCertFindCertificateInStore( hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pc);
if(!pc)
if (hSystemStore) {
PCCERT_CONTEXT pc = nullptr;
while (1) {
pc = ptrCertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc);
if (!pc)
break;
QByteArray der((const char *)(pc->pbCertEncoded), static_cast<int>(pc->cbCertEncoded));
QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded),
static_cast<int>(pc->cbCertEncoded));
QSslCertificate cert(der, QSsl::Der);
systemCerts.append(cert);
}
@ -1543,14 +1315,8 @@ QSslCipher QSslSocketBackendPrivate::sessionCipher() const
{
if (!ssl)
return QSslCipher();
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
// FIXME This is fairly evil, but needed to keep source level compatibility
// with the OpenSSL 0.9.x implementation at maximum -- some other functions
// don't take a const SSL_CIPHER* when they should
SSL_CIPHER *sessionCipher = const_cast<SSL_CIPHER *>(q_SSL_get_current_cipher(ssl));
#else
SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
#endif
const SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();
}
@ -1576,112 +1342,6 @@ QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
return QSsl::UnknownProtocol;
}
void QSslSocketBackendPrivate::continueHandshake()
{
Q_Q(QSslSocket);
// if we have a max read buffer size, reset the plain socket's to match
if (readBufferMaxSize)
plainSocket->setReadBufferSize(readBufferMaxSize);
if (q_SSL_ctrl((ssl), SSL_CTRL_GET_SESSION_REUSED, 0, NULL))
configuration.peerSessionShared = true;
#ifdef QT_DECRYPT_SSL_TRAFFIC
if (ssl->session && ssl->s3) {
const char *mk = reinterpret_cast<const char *>(ssl->session->master_key);
QByteArray masterKey(mk, ssl->session->master_key_length);
const char *random = reinterpret_cast<const char *>(ssl->s3->client_random);
QByteArray clientRandom(random, SSL3_RANDOM_SIZE);
// different format, needed for e.g. older Wireshark versions:
// const char *sid = reinterpret_cast<const char *>(ssl->session->session_id);
// QByteArray sessionID(sid, ssl->session->session_id_length);
// QByteArray debugLineRSA("RSA Session-ID:");
// debugLineRSA.append(sessionID.toHex().toUpper());
// debugLineRSA.append(" Master-Key:");
// debugLineRSA.append(masterKey.toHex().toUpper());
// debugLineRSA.append("\n");
QByteArray debugLineClientRandom("CLIENT_RANDOM ");
debugLineClientRandom.append(clientRandom.toHex().toUpper());
debugLineClientRandom.append(" ");
debugLineClientRandom.append(masterKey.toHex().toUpper());
debugLineClientRandom.append("\n");
QString sslKeyFile = QDir::tempPath() + QLatin1String("/qt-ssl-keys");
QFile file(sslKeyFile);
if (!file.open(QIODevice::Append))
qCWarning(lcSsl) << "could not open file" << sslKeyFile << "for appending";
if (!file.write(debugLineClientRandom))
qCWarning(lcSsl) << "could not write to file" << sslKeyFile;
file.close();
} else {
qCWarning(lcSsl, "could not decrypt SSL traffic");
}
#endif
// Cache this SSL session inside the QSslContext
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) {
if (!sslContextPointer->cacheSession(ssl)) {
sslContextPointer.clear(); // we could not cache the session
} else {
// Cache the session for permanent usage as well
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) {
if (!sslContextPointer->sessionASN1().isEmpty())
configuration.sslSession = sslContextPointer->sessionASN1();
configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint();
}
}
}
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG)
configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
// we could not agree -> be conservative and use HTTP/1.1
configuration.nextNegotiatedProtocol = QByteArrayLiteral("http/1.1");
} else {
const unsigned char *proto = 0;
unsigned int proto_len = 0;
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L) {
q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
if (proto_len && mode == QSslSocket::SslClientMode) {
// Client does not have a callback that sets it ...
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
}
}
if (!proto_len) { // Test if NPN was more lucky ...
#else
{
#endif
q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
}
if (proto_len)
configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len);
else
configuration.nextNegotiatedProtocol.clear();
}
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L && mode == QSslSocket::SslClientMode) {
EVP_PKEY *key;
if (q_SSL_get_server_tmp_key(ssl, &key))
configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey);
}
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ...
connectionEncrypted = true;
emit q->encrypted();
if (autoStartHandshake && pendingClose) {
pendingClose = false;
q->disconnectFromHost();
}
}
QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509)
{
ensureInitialized();
@ -1735,12 +1395,12 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &
QMutexLocker sslErrorListMutexLocker(&_q_sslErrorList()->mutex);
// Register a custom callback to get all verification errors.
X509_STORE_set_verify_cb_func(certStore, q_X509Callback);
q_X509_STORE_set_verify_cb(certStore, q_X509Callback);
// Build the chain of intermediate certificates
STACK_OF(X509) *intermediates = 0;
if (certificateChain.length() > 1) {
intermediates = (STACK_OF(X509) *) q_sk_new_null();
intermediates = (STACK_OF(X509) *) q_OPENSSL_sk_new_null();
if (!intermediates) {
q_X509_STORE_free(certStore);
@ -1754,11 +1414,8 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &
first = false;
continue;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
q_sk_push( (_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle()));
#else
q_sk_push( (STACK *)intermediates, reinterpret_cast<char *>(cert.handle()));
#endif
q_OPENSSL_sk_push((OPENSSL_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle()));
}
}
@ -1782,11 +1439,7 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &
(void) q_X509_verify_cert(storeContext);
q_X509_STORE_CTX_free(storeContext);
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
q_sk_free( (_STACK *) intermediates);
#else
q_sk_free( (STACK *) intermediates);
#endif
q_OPENSSL_sk_free((OPENSSL_STACK *)intermediates);
// Now process the errors
const auto errorList = std::move(_q_sslErrorList()->errors);
@ -1860,7 +1513,8 @@ bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
// Convert to Qt types
if (!key->d->fromEVP_PKEY(pkey)) {
qCWarning(lcSsl, "Unable to convert private key");
q_sk_pop_free(reinterpret_cast<STACK *>(ca), reinterpret_cast<void(*)(void*)>(q_sk_free));
q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
reinterpret_cast<void (*)(void *)>(q_OPENSSL_sk_free));
q_X509_free(x509);
q_EVP_PKEY_free(pkey);
q_PKCS12_free(p12);
@ -1875,7 +1529,11 @@ bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
*caCertificates = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(ca);
// Clean up
q_sk_pop_free(reinterpret_cast<STACK *>(ca), reinterpret_cast<void(*)(void*)>(q_sk_free));
// TODO: verify ASAP, in the past we had sk_pop_free with q_OPENSSL_sk_free
// which seems to be blatantly wrong and even crashes with 1.1.
q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
reinterpret_cast<void (*)(void *)>(q_X509_free));
q_X509_free(x509);
q_EVP_PKEY_free(pkey);
q_PKCS12_free(p12);

View File

@ -0,0 +1,285 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 Governikus GmbH & Co. KG
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
/****************************************************************************
**
** In addition, as a special exception, the copyright holders listed above give
** permission to link the code of its release of Qt with the OpenSSL project's
** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
** same license as the original version), and distribute the linked executables.
**
** You must comply with the GNU General Public License version 2 in all
** respects for all of the code used other than the "OpenSSL" code. If you
** modify this file, you may extend this exception to your version of the file,
** but you are not obligated to do so. If you do not wish to do so, delete
** this exception statement from your version of this file.
**
****************************************************************************/
//#define QT_DECRYPT_SSL_TRAFFIC
#include "qssl_p.h"
#include "qsslsocket_openssl_p.h"
#include "qsslsocket_openssl_symbols_p.h"
#include "qsslsocket.h"
#include "qsslkey.h"
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
#include <QtCore/qmutex.h>
#include <QtCore/qlibrary.h>
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_opensslInitMutex, (QMutex::Recursive))
/*!
\internal
*/
void QSslSocketPrivate::deinitialize()
{
// This function exists only for compatibility with the pre-11 code,
// where deinitialize() actually does some cleanup. To be discarded
// once we retire < 1.1.
}
bool QSslSocketPrivate::ensureLibraryLoaded()
{
if (!q_resolveOpenSslSymbols())
return false;
const QMutexLocker locker(qt_opensslInitMutex);
if (!s_libraryLoaded) {
s_libraryLoaded = true;
// Initialize OpenSSL.
if (q_OPENSSL_init_ssl(0, nullptr) != 1)
return false;
q_SSL_load_error_strings();
q_OpenSSL_add_all_algorithms();
QSslSocketBackendPrivate::s_indexForSSLExtraData
= q_CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, 0L, nullptr, nullptr,
nullptr, nullptr);
// Initialize OpenSSL's random seed.
if (!q_RAND_status()) {
qWarning("Random number generator not seeded, disabling SSL support");
return false;
}
}
return true;
}
void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
{
const QMutexLocker locker(qt_opensslInitMutex);
if (s_loadedCiphersAndCerts)
return;
s_loadedCiphersAndCerts = true;
resetDefaultCiphers();
resetDefaultEllipticCurves();
#if QT_CONFIG(library)
//load symbols needed to receive certificates from system store
#if defined(Q_OS_WIN)
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
if (hLib) {
ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW");
ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore");
ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore");
if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore)
qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen
} else {
qCWarning(lcSsl, "could not load crypt32 library"); // should never happen
}
#elif defined(Q_OS_QNX)
s_loadRootCertsOnDemand = true;
#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
// check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
QList<QByteArray> dirs = unixRootCertDirectories();
QStringList symLinkFilter;
symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
for (int a = 0; a < dirs.count(); ++a) {
QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
if (iterator.hasNext()) {
s_loadRootCertsOnDemand = true;
break;
}
}
#endif
#endif // QT_CONFIG(library)
// if on-demand loading was not enabled, load the certs now
if (!s_loadRootCertsOnDemand)
setDefaultCaCertificates(systemCaCertificates());
#ifdef Q_OS_WIN
//Enabled for fetching additional root certs from windows update on windows 6+
//This flag is set false by setDefaultCaCertificates() indicating the app uses
//its own cert bundle rather than the system one.
//Same logic that disables the unix on demand cert loading.
//Unlike unix, we do preload the certificates from the cert store.
if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_6_0)
s_loadRootCertsOnDemand = true;
#endif
}
long QSslSocketPrivate::sslLibraryVersionNumber()
{
if (!supportsSsl())
return 0;
return q_OpenSSL_version_num();
}
QString QSslSocketPrivate::sslLibraryVersionString()
{
if (!supportsSsl())
return QString();
const char *versionString = q_OpenSSL_version(OPENSSL_VERSION);
if (!versionString)
return QString();
return QString::fromLatin1(versionString);
}
void QSslSocketBackendPrivate::continueHandshake()
{
Q_Q(QSslSocket);
// if we have a max read buffer size, reset the plain socket's to match
if (readBufferMaxSize)
plainSocket->setReadBufferSize(readBufferMaxSize);
if (q_SSL_session_reused(ssl))
configuration.peerSessionShared = true;
#ifdef QT_DECRYPT_SSL_TRAFFIC
if (q_SSL_get_session(ssl)) {
size_t master_key_len = q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl), 0, 0);
size_t client_random_len = q_SSL_get_client_random(ssl, 0, 0);
QByteArray masterKey(int(master_key_len), 0); // Will not overflow
QByteArray clientRandom(int(client_random_len), 0); // Will not overflow
q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl),
reinterpret_cast<unsigned char*>(masterKey.data()),
masterKey.size());
q_SSL_get_client_random(ssl, reinterpret_cast<unsigned char *>(clientRandom.data()),
clientRandom.size());
QByteArray debugLineClientRandom("CLIENT_RANDOM ");
debugLineClientRandom.append(clientRandom.toHex().toUpper());
debugLineClientRandom.append(" ");
debugLineClientRandom.append(masterKey.toHex().toUpper());
debugLineClientRandom.append("\n");
QString sslKeyFile = QDir::tempPath() + QLatin1String("/qt-ssl-keys");
QFile file(sslKeyFile);
if (!file.open(QIODevice::Append))
qCWarning(lcSsl) << "could not open file" << sslKeyFile << "for appending";
if (!file.write(debugLineClientRandom))
qCWarning(lcSsl) << "could not write to file" << sslKeyFile;
file.close();
} else {
qCWarning(lcSsl, "could not decrypt SSL traffic");
}
#endif
// Cache this SSL session inside the QSslContext
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) {
if (!sslContextPointer->cacheSession(ssl)) {
sslContextPointer.clear(); // we could not cache the session
} else {
// Cache the session for permanent usage as well
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) {
if (!sslContextPointer->sessionASN1().isEmpty())
configuration.sslSession = sslContextPointer->sessionASN1();
configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint();
}
}
}
#if !defined(OPENSSL_NO_NEXTPROTONEG)
configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
// we could not agree -> be conservative and use HTTP/1.1
configuration.nextNegotiatedProtocol = QByteArrayLiteral("http/1.1");
} else {
const unsigned char *proto = 0;
unsigned int proto_len = 0;
q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
if (proto_len && mode == QSslSocket::SslClientMode) {
// Client does not have a callback that sets it ...
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
}
if (!proto_len) { // Test if NPN was more lucky ...
q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
}
if (proto_len)
configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len);
else
configuration.nextNegotiatedProtocol.clear();
}
#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
if (mode == QSslSocket::SslClientMode) {
EVP_PKEY *key;
if (q_SSL_get_server_tmp_key(ssl, &key))
configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey);
}
connectionEncrypted = true;
emit q->encrypted();
if (autoStartHandshake && pendingClose) {
pendingClose = false;
q->disconnectFromHost();
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,132 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
/****************************************************************************
**
** In addition, as a special exception, the copyright holders listed above give
** permission to link the code of its release of Qt with the OpenSSL project's
** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
** same license as the original version), and distribute the linked executables.
**
** You must comply with the GNU General Public License version 2 in all
** respects for all of the code used other than the "OpenSSL" code. If you
** modify this file, you may extend this exception to your version of the file,
** but you are not obligated to do so. If you do not wish to do so, delete
** this exception statement from your version of this file.
**
****************************************************************************/
#ifndef QSSLSOCKET_OPENSSL11_SYMBOLS_P_H
#define QSSLSOCKET_OPENSSL11_SYMBOLS_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
// Note: this file does not have QT_BEGIN_NAMESPACE/QT_END_NAMESPACE, it's done
// in qsslsocket_openssl_symbols_p.h.
#ifndef QSSLSOCKET_OPENSSL_SYMBOLS_P_H
#error "You are not supposed to use this header file, include qsslsocket_openssl_symbols_p.h instead"
#endif
const unsigned char * q_ASN1_STRING_get0_data(const ASN1_STRING *x);
Q_AUTOTEST_EXPORT BIO *q_BIO_new(const BIO_METHOD *a);
Q_AUTOTEST_EXPORT const BIO_METHOD *q_BIO_s_mem();
int q_DSA_bits(DSA *a);
int q_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c);
int q_EVP_PKEY_base_id(EVP_PKEY *a);
int q_RSA_bits(RSA *a);
int q_OPENSSL_sk_num(OPENSSL_STACK *a);
void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *));
OPENSSL_STACK *q_OPENSSL_sk_new_null();
void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data);
void q_OPENSSL_sk_free(OPENSSL_STACK *a);
void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b);
int q_SSL_session_reused(SSL *a);
unsigned long q_SSL_CTX_set_options(SSL_CTX *ctx, unsigned long op);
int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
size_t q_SSL_get_client_random(SSL *a, unsigned char *out, size_t outlen);
size_t q_SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *out, size_t outlen);
int q_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
const SSL_METHOD *q_TLS_method();
const SSL_METHOD *q_TLS_client_method();
const SSL_METHOD *q_TLS_server_method();
ASN1_TIME *q_X509_getm_notBefore(X509 *a);
ASN1_TIME *q_X509_getm_notAfter(X509 *a);
long q_X509_get_version(X509 *a);
EVP_PKEY *q_X509_get_pubkey(X509 *a);
void q_X509_STORE_set_verify_cb(X509_STORE *ctx, X509_STORE_CTX_verify_cb verify_cb);
STACK_OF(X509) *q_X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
int q_DH_bits(DH *dh);
# define q_SSL_load_error_strings() q_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_OPENSSL_sk_num)(st)
#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_OPENSSL_sk_value)(st, i)
#define q_OPENSSL_add_all_algorithms_conf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
| OPENSSL_INIT_ADD_ALL_DIGESTS \
| OPENSSL_INIT_LOAD_CONFIG, NULL)
#define q_OPENSSL_add_all_algorithms_noconf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
| OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)
int q_OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
void q_CRYPTO_free(void *str, const char *file, int line);
long q_OpenSSL_version_num();
const char *q_OpenSSL_version(int type);
unsigned long q_SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session);
#endif

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -98,8 +98,8 @@
#include <openssl/crypto.h>
#include <openssl/tls1.h>
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
typedef _STACK STACK;
#if QT_CONFIG(opensslv11)
#include <openssl/dh.h>
#endif
QT_BEGIN_NAMESPACE
@ -151,7 +151,7 @@ public:
#endif
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher);
static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName);
static QString getErrorsFromOpenSsl();

View File

@ -1,7 +1,8 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -136,110 +137,78 @@ void qsslSocketCannotResolveSymbolWarning(const char *functionName)
#endif // QT_LINKED_OPENSSL
#if QT_CONFIG(opensslv11)
// Below are the functions first introduced in version 1.1:
DEFINEFUNC(const unsigned char *, ASN1_STRING_get0_data, const ASN1_STRING *a, a, return 0, return)
DEFINEFUNC2(int, OPENSSL_init_ssl, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
DEFINEFUNC2(int, OPENSSL_init_crypto, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
DEFINEFUNC(BIO *, BIO_new, const BIO_METHOD *a, a, return 0, return)
DEFINEFUNC(const BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return 0, return)
DEFINEFUNC2(int, BN_is_word, BIGNUM *a, a, BN_ULONG w, w, return 0, return)
DEFINEFUNC(int, EVP_CIPHER_CTX_reset, EVP_CIPHER_CTX *c, c, return 0, return)
DEFINEFUNC(int, EVP_PKEY_base_id, EVP_PKEY *a, a, return NID_undef, return)
DEFINEFUNC(int, RSA_bits, RSA *a, a, return 0, return)
DEFINEFUNC(int, DSA_bits, DSA *a, a, return 0, return)
DEFINEFUNC(int, OPENSSL_sk_num, OPENSSL_STACK *a, a, return -1, return)
DEFINEFUNC2(void, OPENSSL_sk_pop_free, OPENSSL_STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
DEFINEFUNC(OPENSSL_STACK *, OPENSSL_sk_new_null, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC2(void, OPENSSL_sk_push, OPENSSL_STACK *a, a, void *b, b, return, DUMMYARG)
DEFINEFUNC(void, OPENSSL_sk_free, OPENSSL_STACK *a, a, return, DUMMYARG)
DEFINEFUNC2(void *, OPENSSL_sk_value, OPENSSL_STACK *a, a, int b, b, return 0, return)
DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long op, op, return 0, return)
DEFINEFUNC3(size_t, SSL_get_client_random, SSL *a, a, unsigned char *out, out, size_t outlen, outlen, return 0, return)
DEFINEFUNC3(size_t, SSL_SESSION_get_master_key, const SSL_SESSION *ses, ses, unsigned char *out, out, size_t outlen, outlen, return 0, return)
DEFINEFUNC6(int, CRYPTO_get_ex_new_index, int class_index, class_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return)
DEFINEFUNC(const SSL_METHOD *, TLS_method, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const SSL_METHOD *, TLS_client_method, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const SSL_METHOD *, TLS_server_method, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(ASN1_TIME *, X509_getm_notBefore, X509 *a, a, return 0, return)
DEFINEFUNC(ASN1_TIME *, X509_getm_notAfter, X509 *a, a, return 0, return)
DEFINEFUNC(long, X509_get_version, X509 *a, a, return -1, return)
DEFINEFUNC(EVP_PKEY *, X509_get_pubkey, X509 *a, a, return 0, return)
DEFINEFUNC2(void, X509_STORE_set_verify_cb, X509_STORE *a, a, X509_STORE_CTX_verify_cb verify_cb, verify_cb, return, DUMMYARG)
DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get0_chain, X509_STORE_CTX *a, a, return 0, return)
DEFINEFUNC3(void, CRYPTO_free, void *str, str, const char *file, file, int line, line, return, DUMMYARG)
DEFINEFUNC(long, OpenSSL_version_num, void, DUMMYARG, return 0, return)
DEFINEFUNC(const char *, OpenSSL_version, int a, a, return 0, return)
DEFINEFUNC(unsigned long, SSL_SESSION_get_ticket_lifetime_hint, const SSL_SESSION *session, session, return 0, return)
DEFINEFUNC4(void, DH_get0_pqg, const DH *dh, dh, const BIGNUM **p, p, const BIGNUM **q, q, const BIGNUM **g, g, return, DUMMYARG)
DEFINEFUNC(int, DH_bits, DH *dh, dh, return 0, return)
#else // QT_CONFIG(opensslv11)
// Functions below are either deprecated or removed in OpenSSL >= 1.1:
DEFINEFUNC(unsigned char *, ASN1_STRING_data, ASN1_STRING *a, a, return 0, return)
#ifdef SSLEAY_MACROS
DEFINEFUNC3(void *, ASN1_dup, i2d_of_void *a, a, d2i_of_void *b, b, char *c, c, return 0, return)
#endif
DEFINEFUNC(long, ASN1_INTEGER_get, ASN1_INTEGER *a, a, return 0, return)
DEFINEFUNC(unsigned char *, ASN1_STRING_data, ASN1_STRING *a, a, return 0, return)
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)
DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
DEFINEFUNC(BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return 0, return)
DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
DEFINEFUNC2(int, BN_is_word, BIGNUM *a, a, BN_ULONG w, w, return 0, return)
#endif
DEFINEFUNC2(BN_ULONG, BN_mod_word, const BIGNUM *a, a, BN_ULONG w, w, return static_cast<BN_ULONG>(-1), return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC(const EC_GROUP*, EC_KEY_get0_group, const EC_KEY* k, k, return 0, return)
DEFINEFUNC(int, EC_GROUP_get_degree, const EC_GROUP* g, g, return 0, return)
#endif
DEFINEFUNC(int, CRYPTO_num_locks, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, CRYPTO_set_locking_callback, void (*a)(int, int, const char *, int), a, return, DUMMYARG)
DEFINEFUNC(void, CRYPTO_set_id_callback, unsigned long (*a)(), a, return, DUMMYARG)
DEFINEFUNC(void, CRYPTO_free, void *a, a, return, DUMMYARG)
DEFINEFUNC(DSA *, DSA_new, DUMMYARG, DUMMYARG, return 0, return)
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)
DEFINEFUNC4(int, EVP_CIPHER_CTX_ctrl, EVP_CIPHER_CTX *ctx, ctx, int type, type, int arg, arg, void *ptr, ptr, return 0, return);
DEFINEFUNC2(int, EVP_CIPHER_CTX_set_key_length, EVP_CIPHER_CTX *ctx, ctx, int keylen, keylen, return 0, return)
DEFINEFUNC5(int, EVP_CipherInit, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *type, type, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return);
DEFINEFUNC5(int, EVP_CipherUpdate, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, const unsigned char *in, in, int inl, inl, return 0, return);
DEFINEFUNC3(int, EVP_CipherFinal, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, return 0, return);
DEFINEFUNC(const EVP_CIPHER *, EVP_des_cbc, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const EVP_CIPHER *, EVP_rc2_cbc, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return)
DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return)
#endif
DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return 0, return)
DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return 0, return)
#endif
DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(int, EVP_PKEY_type, int a, a, return NID_undef, return)
DEFINEFUNC2(int, i2d_X509, X509 *a, a, unsigned char **b, b, return -1, return)
DEFINEFUNC(const char *, OBJ_nid2sn, int a, a, return 0, return)
DEFINEFUNC(const char *, OBJ_nid2ln, int a, a, return 0, return)
DEFINEFUNC(int, OBJ_sn2nid, const char *s, s, return 0, return)
DEFINEFUNC(int, OBJ_ln2nid, const char *s, s, return 0, return)
DEFINEFUNC3(int, i2t_ASN1_OBJECT, char *a, a, int b, b, ASN1_OBJECT *c, c, return -1, return)
DEFINEFUNC4(int, OBJ_obj2txt, char *a, a, int b, b, ASN1_OBJECT *c, c, int d, d, return -1, return)
DEFINEFUNC(int, OBJ_obj2nid, const ASN1_OBJECT *a, a, return NID_undef, return)
#ifdef SSLEAY_MACROS
DEFINEFUNC6(void *, PEM_ASN1_read_bio, d2i_of_void *a, a, const char *b, b, BIO *c, c, void **d, d, pem_password_cb *e, e, void *f, f, return 0, return)
DEFINEFUNC6(void *, PEM_ASN1_write_bio, d2i_of_void *a, a, const char *b, b, BIO *c, c, void **d, d, pem_password_cb *e, e, void *f, f, return 0, return)
#else
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PrivateKey, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#endif
DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
#endif
#endif
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PUBKEY, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#endif
DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
#endif
DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
DEFINEFUNC(RSA *, RSA_new, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
#endif // SSLEAY_MACROS
DEFINEFUNC(int, sk_num, STACK *a, a, return -1, return)
DEFINEFUNC2(void, sk_pop_free, STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
DEFINEFUNC(_STACK *, sk_new_null, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC2(void, sk_push, _STACK *a, a, void *b, b, return, DUMMYARG)
@ -250,70 +219,15 @@ DEFINEFUNC(STACK *, sk_new_null, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC2(void, sk_push, STACK *a, a, char *b, b, return, DUMMYARG)
DEFINEFUNC(void, sk_free, STACK *a, a, return, DUMMYARG)
DEFINEFUNC2(char *, sk_value, STACK *a, a, int b, b, return 0, return)
#endif
DEFINEFUNC(int, SSL_accept, SSL *a, a, return -1, return)
DEFINEFUNC(int, SSL_clear, SSL *a, a, return -1, return)
DEFINEFUNC3(char *, SSL_CIPHER_description, SSL_CIPHER *a, a, char *b, b, int c, c, return 0, return)
DEFINEFUNC2(int, SSL_CIPHER_get_bits, SSL_CIPHER *a, a, int *b, b, return 0, return)
DEFINEFUNC(int, SSL_connect, SSL *a, a, return -1, return)
DEFINEFUNC(int, SSL_CTX_check_private_key, const SSL_CTX *a, a, return -1, return)
DEFINEFUNC4(long, SSL_CTX_ctrl, SSL_CTX *a, a, int b, b, long c, c, void *d, d, return -1, return)
DEFINEFUNC(void, SSL_CTX_free, SSL_CTX *a, a, return, DUMMYARG)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
DEFINEFUNC(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a, a, return 0, return)
#else
DEFINEFUNC(SSL_CTX *, SSL_CTX_new, SSL_METHOD *a, a, return 0, return)
#endif
DEFINEFUNC2(int, SSL_CTX_set_cipher_list, SSL_CTX *a, a, const char *b, b, return -1, return)
DEFINEFUNC(int, SSL_CTX_set_default_verify_paths, SSL_CTX *a, a, return -1, return)
DEFINEFUNC3(void, SSL_CTX_set_verify, SSL_CTX *a, a, int b, b, int (*c)(int, X509_STORE_CTX *), c, return, DUMMYARG)
DEFINEFUNC2(void, SSL_CTX_set_verify_depth, SSL_CTX *a, a, int b, b, return, DUMMYARG)
DEFINEFUNC2(int, SSL_CTX_use_certificate, SSL_CTX *a, a, X509 *b, b, return -1, return)
DEFINEFUNC3(int, SSL_CTX_use_certificate_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
DEFINEFUNC2(int, SSL_CTX_use_PrivateKey, SSL_CTX *a, a, EVP_PKEY *b, b, return -1, return)
DEFINEFUNC2(int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *a, a, RSA *b, b, return -1, return)
DEFINEFUNC3(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *a, a, return 0, return)
DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG)
DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
#else
DEFINEFUNC(SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
#endif
DEFINEFUNC(int, SSL_version, const SSL *a, a, return 0, return)
DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return)
DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return 0, return)
DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
// 0.9.8 broke SC and BC by changing this function's signature.
DEFINEFUNC(long, SSL_get_verify_result, const SSL *a, a, return -1, return)
#else
DEFINEFUNC(long, SSL_get_verify_result, SSL *a, a, return -1, return)
#endif
#endif // OPENSSL_VERSION_NUMBER >= 0x10000000L
DEFINEFUNC(int, SSL_library_init, void, DUMMYARG, return -1, return)
DEFINEFUNC(void, SSL_load_error_strings, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return 0, return)
DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, void *parg, parg, return -1, return)
DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return)
DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG)
DEFINEFUNC(void, SSL_set_accept_state, SSL *a, a, return, DUMMYARG)
DEFINEFUNC(void, SSL_set_connect_state, SSL *a, a, return, DUMMYARG)
DEFINEFUNC(int, SSL_shutdown, SSL *a, a, return -1, return)
DEFINEFUNC2(int, SSL_set_session, SSL* to, to, SSL_SESSION *session, session, return -1, return)
DEFINEFUNC(void, SSL_SESSION_free, SSL_SESSION *ses, ses, return, DUMMYARG)
DEFINEFUNC(SSL_SESSION*, SSL_get1_session, SSL *ssl, ssl, return 0, return)
DEFINEFUNC(SSL_SESSION*, SSL_get_session, const SSL *ssl, ssl, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
DEFINEFUNC5(int, SSL_get_ex_new_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return)
DEFINEFUNC3(int, SSL_set_ex_data, SSL *ssl, ssl, int idx, idx, void *arg, arg, return 0, return)
DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return NULL, return)
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
DEFINEFUNC2(void, SSL_set_psk_client_callback, SSL* ssl, ssl, q_psk_client_callback_t callback, callback, return, DUMMYARG)
DEFINEFUNC2(void, SSL_set_psk_server_callback, SSL* ssl, ssl, q_psk_server_callback_t callback, callback, return, DUMMYARG)
DEFINEFUNC2(int, SSL_CTX_use_psk_identity_hint, SSL_CTX* ctx, ctx, const char *hint, hint, return 0, return)
#endif
#endif // OPENSSL_VERSION_NUMBER >= 0x10001000L
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_SSL2
DEFINEFUNC(const SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return 0, return)
@ -357,8 +271,177 @@ DEFINEFUNC(SSL_METHOD *, SSLv3_server_method, DUMMYARG, DUMMYARG, return 0, retu
DEFINEFUNC(SSL_METHOD *, SSLv23_server_method, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(SSL_METHOD *, TLSv1_server_method, DUMMYARG, DUMMYARG, return 0, return)
#endif
DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get_chain, X509_STORE_CTX *a, a, return 0, return)
#ifdef SSLEAY_MACROS
DEFINEFUNC2(int, i2d_DSAPrivateKey, const DSA *a, a, unsigned char **b, b, return -1, return)
DEFINEFUNC2(int, i2d_RSAPrivateKey, const RSA *a, a, unsigned char **b, b, return -1, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, i2d_ECPrivateKey, const EC_KEY *a, a, unsigned char **b, b, return -1, return)
#endif
DEFINEFUNC3(RSA *, d2i_RSAPrivateKey, RSA **a, a, unsigned char **b, b, long c, c, return 0, return)
DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, c, return 0, return)
#ifndef OPENSSL_NO_EC
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)
DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return)
DEFINEFUNC(const char *, SSLeay_version, int a, a, return 0, return)
#endif // QT_CONFIG(opensslv11)
DEFINEFUNC(long, ASN1_INTEGER_get, ASN1_INTEGER *a, a, return 0, return)
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)
DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return)
DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return 0, return)
DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
DEFINEFUNC2(BN_ULONG, BN_mod_word, const BIGNUM *a, a, BN_ULONG w, w, return static_cast<BN_ULONG>(-1), return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC(const EC_GROUP*, EC_KEY_get0_group, const EC_KEY* k, k, return 0, return)
DEFINEFUNC(int, EC_GROUP_get_degree, const EC_GROUP* g, g, return 0, return)
#endif
DEFINEFUNC(DSA *, DSA_new, DUMMYARG, DUMMYARG, return 0, return)
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(EVP_CIPHER_CTX *, EVP_CIPHER_CTX_new, void, DUMMYARG, return 0, return)
DEFINEFUNC(void, EVP_CIPHER_CTX_free, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
DEFINEFUNC4(int, EVP_CIPHER_CTX_ctrl, EVP_CIPHER_CTX *ctx, ctx, int type, type, int arg, arg, void *ptr, ptr, return 0, return)
DEFINEFUNC2(int, EVP_CIPHER_CTX_set_key_length, EVP_CIPHER_CTX *ctx, ctx, int keylen, keylen, return 0, return)
DEFINEFUNC5(int, EVP_CipherInit, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *type, type, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
DEFINEFUNC6(int, EVP_CipherInit_ex, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *cipher, cipher, ENGINE *impl, impl, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
DEFINEFUNC5(int, EVP_CipherUpdate, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, const unsigned char *in, in, int inl, inl, return 0, return)
DEFINEFUNC3(int, EVP_CipherFinal, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, return 0, return)
DEFINEFUNC(const EVP_CIPHER *, EVP_des_cbc, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const EVP_CIPHER *, EVP_rc2_cbc, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return)
DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return)
#endif
DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return 0, return)
DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return 0, return)
#endif
DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(int, EVP_PKEY_type, int a, a, return NID_undef, return)
DEFINEFUNC2(int, i2d_X509, X509 *a, a, unsigned char **b, b, return -1, return)
DEFINEFUNC(const char *, OBJ_nid2sn, int a, a, return 0, return)
DEFINEFUNC(const char *, OBJ_nid2ln, int a, a, return 0, return)
DEFINEFUNC(int, OBJ_sn2nid, const char *s, s, return 0, return)
DEFINEFUNC(int, OBJ_ln2nid, const char *s, s, return 0, return)
DEFINEFUNC3(int, i2t_ASN1_OBJECT, char *a, a, int b, b, ASN1_OBJECT *c, c, return -1, return)
DEFINEFUNC4(int, OBJ_obj2txt, char *a, a, int b, b, ASN1_OBJECT *c, c, int d, d, return -1, return)
DEFINEFUNC(int, OBJ_obj2nid, const ASN1_OBJECT *a, a, return NID_undef, return)
#ifndef SSLEAY_MACROS
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PrivateKey, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#endif
DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
#endif
#endif // !SSLEAY_MACROS
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PUBKEY, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
#endif
DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
#endif
DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
DEFINEFUNC(RSA *, RSA_new, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
DEFINEFUNC(int, SSL_accept, SSL *a, a, return -1, return)
DEFINEFUNC(int, SSL_clear, SSL *a, a, return -1, return)
DEFINEFUNC3(char *, SSL_CIPHER_description, const SSL_CIPHER *a, a, char *b, b, int c, c, return 0, return)
DEFINEFUNC2(int, SSL_CIPHER_get_bits, const SSL_CIPHER *a, a, int *b, b, return 0, return)
DEFINEFUNC(int, SSL_connect, SSL *a, a, return -1, return)
DEFINEFUNC(int, SSL_CTX_check_private_key, const SSL_CTX *a, a, return -1, return)
DEFINEFUNC4(long, SSL_CTX_ctrl, SSL_CTX *a, a, int b, b, long c, c, void *d, d, return -1, return)
DEFINEFUNC(void, SSL_CTX_free, SSL_CTX *a, a, return, DUMMYARG)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
DEFINEFUNC(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a, a, return 0, return)
#else
DEFINEFUNC(SSL_CTX *, SSL_CTX_new, SSL_METHOD *a, a, return 0, return)
#endif
DEFINEFUNC2(int, SSL_CTX_set_cipher_list, SSL_CTX *a, a, const char *b, b, return -1, return)
DEFINEFUNC(int, SSL_CTX_set_default_verify_paths, SSL_CTX *a, a, return -1, return)
DEFINEFUNC3(void, SSL_CTX_set_verify, SSL_CTX *a, a, int b, b, int (*c)(int, X509_STORE_CTX *), c, return, DUMMYARG)
DEFINEFUNC2(void, SSL_CTX_set_verify_depth, SSL_CTX *a, a, int b, b, return, DUMMYARG)
DEFINEFUNC2(int, SSL_CTX_use_certificate, SSL_CTX *a, a, X509 *b, b, return -1, return)
DEFINEFUNC3(int, SSL_CTX_use_certificate_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
DEFINEFUNC2(int, SSL_CTX_use_PrivateKey, SSL_CTX *a, a, EVP_PKEY *b, b, return -1, return)
DEFINEFUNC2(int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *a, a, RSA *b, b, return -1, return)
DEFINEFUNC3(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *a, a, return 0, return)
DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG)
DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
#else
DEFINEFUNC(SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
#endif
DEFINEFUNC(int, SSL_version, const SSL *a, a, return 0, return)
DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return)
DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return 0, return)
DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
// 0.9.8 broke SC and BC by changing this function's signature.
DEFINEFUNC(long, SSL_get_verify_result, const SSL *a, a, return -1, return)
#else
DEFINEFUNC(long, SSL_get_verify_result, SSL *a, a, return -1, return)
#endif
DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return 0, return)
DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, void *parg, parg, return -1, return)
DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return)
DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG)
DEFINEFUNC(void, SSL_set_accept_state, SSL *a, a, return, DUMMYARG)
DEFINEFUNC(void, SSL_set_connect_state, SSL *a, a, return, DUMMYARG)
DEFINEFUNC(int, SSL_shutdown, SSL *a, a, return -1, return)
DEFINEFUNC2(int, SSL_set_session, SSL* to, to, SSL_SESSION *session, session, return -1, return)
DEFINEFUNC(void, SSL_SESSION_free, SSL_SESSION *ses, ses, return, DUMMYARG)
DEFINEFUNC(SSL_SESSION*, SSL_get1_session, SSL *ssl, ssl, return 0, return)
DEFINEFUNC(SSL_SESSION*, SSL_get_session, const SSL *ssl, ssl, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
DEFINEFUNC3(int, SSL_set_ex_data, SSL *ssl, ssl, int idx, idx, void *arg, arg, return 0, return)
DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return NULL, return)
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
DEFINEFUNC2(void, SSL_set_psk_client_callback, SSL* ssl, ssl, q_psk_client_callback_t callback, callback, return, DUMMYARG)
DEFINEFUNC2(void, SSL_set_psk_server_callback, SSL* ssl, ssl, q_psk_server_callback_t callback, callback, return, DUMMYARG)
DEFINEFUNC2(int, SSL_CTX_use_psk_identity_hint, SSL_CTX* ctx, ctx, const char *hint, hint, return 0, return)
#endif
DEFINEFUNC3(int, SSL_write, SSL *a, a, const void *b, b, int c, c, return -1, return)
DEFINEFUNC2(int, X509_cmp, X509 *a, a, X509 *b, b, return -1, return)
DEFINEFUNC4(int, X509_digest, const X509 *x509, x509, const EVP_MD *type, type, unsigned char *md, md, unsigned int *len, len, return -1, return)
#ifndef SSLEAY_MACROS
DEFINEFUNC(X509 *, X509_dup, X509 *a, a, return 0, return)
#endif
@ -382,6 +465,7 @@ DEFINEFUNC2(int, ASN1_STRING_print, BIO *a, a, ASN1_STRING *b, b, return 0, retu
DEFINEFUNC2(int, X509_check_issued, X509 *a, a, X509 *b, b, return -1, return)
DEFINEFUNC(X509_NAME *, X509_get_issuer_name, X509 *a, a, return 0, return)
DEFINEFUNC(X509_NAME *, X509_get_subject_name, X509 *a, a, return 0, return)
DEFINEFUNC(ASN1_INTEGER *, X509_get_serialNumber, X509 *a, a, return 0, return)
DEFINEFUNC(int, X509_verify_cert, X509_STORE_CTX *a, a, return -1, return)
DEFINEFUNC(int, X509_NAME_entry_count, X509_NAME *a, a, return 0, return)
DEFINEFUNC2(X509_NAME_ENTRY *, X509_NAME_get_entry, X509_NAME *a, a, int b, b, return 0, return)
@ -397,26 +481,8 @@ DEFINEFUNC2(int, X509_STORE_CTX_set_purpose, X509_STORE_CTX *a, a, int b, b, ret
DEFINEFUNC(int, X509_STORE_CTX_get_error, X509_STORE_CTX *a, a, return -1, return)
DEFINEFUNC(int, X509_STORE_CTX_get_error_depth, X509_STORE_CTX *a, a, return -1, return)
DEFINEFUNC(X509 *, X509_STORE_CTX_get_current_cert, X509_STORE_CTX *a, a, return 0, return)
DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get_chain, X509_STORE_CTX *a, a, return 0, return)
DEFINEFUNC(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return 0, return)
#ifdef SSLEAY_MACROS
DEFINEFUNC2(int, i2d_DSAPrivateKey, const DSA *a, a, unsigned char **b, b, return -1, return)
DEFINEFUNC2(int, i2d_RSAPrivateKey, const RSA *a, a, unsigned char **b, b, return -1, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, i2d_ECPrivateKey, const EC_KEY *a, a, unsigned char **b, b, return -1, return)
#endif
DEFINEFUNC3(RSA *, d2i_RSAPrivateKey, RSA **a, a, unsigned char **b, b, long c, c, return 0, return)
DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, c, return 0, return)
#ifndef OPENSSL_NO_EC
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)
DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return)
DEFINEFUNC(const char *, SSLeay_version, int a, a, return 0, return)
DEFINEFUNC2(int, i2d_SSL_SESSION, SSL_SESSION *in, in, unsigned char **pp, pp, return 0, return)
DEFINEFUNC3(SSL_SESSION *, d2i_SSL_SESSION, SSL_SESSION **a, a, const unsigned char **pp, pp, long length, length, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG)
@ -699,8 +765,8 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl()
#ifndef Q_OS_DARWIN
// second attempt: find the development files libssl.so and libcrypto.so
//
// disabled on OS X/iOS:
// OS X's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third
// disabled on macOS/iOS:
// macOS's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third
// attempt, _after_ <bundle>/Contents/Frameworks has been searched.
// iOS does not ship a system libssl.dylib, libcrypto.dylib in the first place.
libssl->setFileNameAndVersion(QLatin1String("ssl"), -1);
@ -759,7 +825,11 @@ bool q_resolveOpenSslSymbols()
static bool symbolsResolved = false;
static bool triedToResolveSymbols = false;
#ifndef QT_NO_THREAD
#if QT_CONFIG(opensslv11)
QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&q_OPENSSL_init_ssl));
#else
QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&q_SSL_library_init));
#endif
#endif
if (symbolsResolved)
return true;
@ -776,17 +846,148 @@ bool q_resolveOpenSslSymbols()
// failed to load them
return false;
#if QT_CONFIG(opensslv11)
RESOLVEFUNC(OPENSSL_init_ssl)
RESOLVEFUNC(OPENSSL_init_crypto)
RESOLVEFUNC(ASN1_STRING_get0_data)
RESOLVEFUNC(EVP_CIPHER_CTX_reset)
RESOLVEFUNC(EVP_PKEY_base_id)
RESOLVEFUNC(RSA_bits)
RESOLVEFUNC(OPENSSL_sk_new_null)
RESOLVEFUNC(OPENSSL_sk_push)
RESOLVEFUNC(OPENSSL_sk_free)
RESOLVEFUNC(OPENSSL_sk_num)
RESOLVEFUNC(OPENSSL_sk_pop_free)
RESOLVEFUNC(OPENSSL_sk_value)
RESOLVEFUNC(DH_get0_pqg)
RESOLVEFUNC(SSL_CTX_set_options)
RESOLVEFUNC(SSL_get_client_random)
RESOLVEFUNC(SSL_SESSION_get_master_key)
RESOLVEFUNC(SSL_session_reused)
RESOLVEFUNC(SSL_get_session)
RESOLVEFUNC(CRYPTO_get_ex_new_index)
RESOLVEFUNC(TLS_method)
RESOLVEFUNC(TLS_client_method)
RESOLVEFUNC(TLS_server_method)
RESOLVEFUNC(X509_STORE_CTX_get0_chain)
RESOLVEFUNC(X509_getm_notBefore)
RESOLVEFUNC(X509_getm_notAfter)
RESOLVEFUNC(X509_get_version)
RESOLVEFUNC(X509_get_pubkey)
RESOLVEFUNC(X509_STORE_set_verify_cb)
RESOLVEFUNC(CRYPTO_free)
RESOLVEFUNC(OpenSSL_version_num)
RESOLVEFUNC(OpenSSL_version)
if (!_q_OpenSSL_version) {
// Apparently, we were built with OpenSSL 1.1 enabled but are now using
// a wrong library.
delete libs.first;
delete libs.second;
qCWarning(lcSsl, "Incompatible version of OpenSSL");
return false;
}
RESOLVEFUNC(SSL_SESSION_get_ticket_lifetime_hint)
RESOLVEFUNC(DH_bits)
RESOLVEFUNC(DSA_bits)
#else // !opensslv11
RESOLVEFUNC(ASN1_STRING_data)
#ifdef SSLEAY_MACROS
RESOLVEFUNC(ASN1_dup)
#endif // SSLEAY_MACROS
RESOLVEFUNC(BIO_new_file)
RESOLVEFUNC(ERR_clear_error)
RESOLVEFUNC(CRYPTO_free)
RESOLVEFUNC(CRYPTO_num_locks)
RESOLVEFUNC(CRYPTO_set_id_callback)
RESOLVEFUNC(CRYPTO_set_locking_callback)
RESOLVEFUNC(ERR_peek_last_error)
RESOLVEFUNC(ERR_free_strings)
RESOLVEFUNC(EVP_CIPHER_CTX_cleanup)
RESOLVEFUNC(EVP_CIPHER_CTX_init)
#ifdef SSLEAY_MACROS // ### verify
RESOLVEFUNC(PEM_ASN1_read_bio)
#endif // SSLEAY_MACROS
RESOLVEFUNC(sk_new_null)
RESOLVEFUNC(sk_push)
RESOLVEFUNC(sk_free)
RESOLVEFUNC(sk_num)
RESOLVEFUNC(sk_pop_free)
RESOLVEFUNC(sk_value)
RESOLVEFUNC(SSL_library_init)
RESOLVEFUNC(SSL_load_error_strings)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
RESOLVEFUNC(SSL_get_ex_new_index)
#endif
#ifndef OPENSSL_NO_SSL2
RESOLVEFUNC(SSLv2_client_method)
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
RESOLVEFUNC(SSLv3_client_method)
#endif
RESOLVEFUNC(SSLv23_client_method)
RESOLVEFUNC(TLSv1_client_method)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
RESOLVEFUNC(TLSv1_1_client_method)
RESOLVEFUNC(TLSv1_2_client_method)
#endif
#ifndef OPENSSL_NO_SSL2
RESOLVEFUNC(SSLv2_server_method)
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
RESOLVEFUNC(SSLv3_server_method)
#endif
RESOLVEFUNC(SSLv23_server_method)
RESOLVEFUNC(TLSv1_server_method)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
RESOLVEFUNC(TLSv1_1_server_method)
RESOLVEFUNC(TLSv1_2_server_method)
#endif
RESOLVEFUNC(X509_STORE_CTX_get_chain)
#ifdef SSLEAY_MACROS
RESOLVEFUNC(i2d_DSAPrivateKey)
RESOLVEFUNC(i2d_RSAPrivateKey)
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(SSLeay)
if (!_q_SSLeay || q_SSLeay() >= 0x10100000L) {
// OpenSSL 1.1 has deprecated and removed SSLeay. We consider a failure to
// resolve this symbol as a failure to resolve symbols.
// The right operand of '||' above is ... a bit of paranoia.
delete libs.first;
delete libs.second;
qCWarning(lcSsl, "Incompatible version of OpenSSL");
return false;
}
RESOLVEFUNC(SSLeay_version)
#ifndef OPENSSL_NO_EC
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L)
RESOLVEFUNC(EC_curve_nist2nid)
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#endif // OPENSSL_NO_EC
#endif // !opensslv11
RESOLVEFUNC(ASN1_INTEGER_get)
RESOLVEFUNC(ASN1_STRING_data)
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)
@ -802,26 +1003,22 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(BN_is_word)
#endif
RESOLVEFUNC(BN_mod_word)
RESOLVEFUNC(CRYPTO_free)
RESOLVEFUNC(CRYPTO_num_locks)
RESOLVEFUNC(CRYPTO_set_id_callback)
RESOLVEFUNC(CRYPTO_set_locking_callback)
RESOLVEFUNC(DSA_new)
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)
RESOLVEFUNC(EVP_CIPHER_CTX_new)
RESOLVEFUNC(EVP_CIPHER_CTX_free)
RESOLVEFUNC(EVP_CIPHER_CTX_ctrl)
RESOLVEFUNC(EVP_CIPHER_CTX_set_key_length)
RESOLVEFUNC(EVP_CipherInit)
RESOLVEFUNC(EVP_CipherInit_ex)
RESOLVEFUNC(EVP_CipherUpdate)
RESOLVEFUNC(EVP_CipherFinal)
RESOLVEFUNC(EVP_des_cbc)
RESOLVEFUNC(EVP_des_ede3_cbc)
RESOLVEFUNC(EVP_rc2_cbc)
RESOLVEFUNC(EVP_sha1)
RESOLVEFUNC(EVP_PKEY_assign)
RESOLVEFUNC(EVP_PKEY_set1_RSA)
RESOLVEFUNC(EVP_PKEY_set1_DSA)
@ -843,9 +1040,8 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(i2t_ASN1_OBJECT)
RESOLVEFUNC(OBJ_obj2txt)
RESOLVEFUNC(OBJ_obj2nid)
#ifdef SSLEAY_MACROS // ### verify
RESOLVEFUNC(PEM_ASN1_read_bio)
#else
#ifndef SSLEAY_MACROS
RESOLVEFUNC(PEM_read_bio_PrivateKey)
RESOLVEFUNC(PEM_read_bio_DSAPrivateKey)
RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
@ -858,7 +1054,8 @@ bool q_resolveOpenSslSymbols()
#ifndef OPENSSL_NO_EC
RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
#endif
#endif
#endif // !SSLEAY_MACROS
RESOLVEFUNC(PEM_read_bio_PUBKEY)
RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY)
RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
@ -874,12 +1071,6 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(RAND_status)
RESOLVEFUNC(RSA_new)
RESOLVEFUNC(RSA_free)
RESOLVEFUNC(sk_new_null)
RESOLVEFUNC(sk_push)
RESOLVEFUNC(sk_free)
RESOLVEFUNC(sk_num)
RESOLVEFUNC(sk_pop_free)
RESOLVEFUNC(sk_value)
RESOLVEFUNC(SSL_CIPHER_description)
RESOLVEFUNC(SSL_CIPHER_get_bits)
RESOLVEFUNC(SSL_CTX_check_private_key)
@ -907,8 +1098,6 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_get_peer_cert_chain)
RESOLVEFUNC(SSL_get_peer_certificate)
RESOLVEFUNC(SSL_get_verify_result)
RESOLVEFUNC(SSL_library_init)
RESOLVEFUNC(SSL_load_error_strings)
RESOLVEFUNC(SSL_new)
RESOLVEFUNC(SSL_ctrl)
RESOLVEFUNC(SSL_read)
@ -921,7 +1110,6 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_get1_session)
RESOLVEFUNC(SSL_get_session)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
RESOLVEFUNC(SSL_get_ex_new_index)
RESOLVEFUNC(SSL_set_ex_data)
RESOLVEFUNC(SSL_get_ex_data)
#endif
@ -931,30 +1119,6 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_CTX_use_psk_identity_hint)
#endif
RESOLVEFUNC(SSL_write)
#ifndef OPENSSL_NO_SSL2
RESOLVEFUNC(SSLv2_client_method)
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
RESOLVEFUNC(SSLv3_client_method)
#endif
RESOLVEFUNC(SSLv23_client_method)
RESOLVEFUNC(TLSv1_client_method)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
RESOLVEFUNC(TLSv1_1_client_method)
RESOLVEFUNC(TLSv1_2_client_method)
#endif
#ifndef OPENSSL_NO_SSL2
RESOLVEFUNC(SSLv2_server_method)
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
RESOLVEFUNC(SSLv3_server_method)
#endif
RESOLVEFUNC(SSLv23_server_method)
RESOLVEFUNC(TLSv1_server_method)
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
RESOLVEFUNC(TLSv1_1_server_method)
RESOLVEFUNC(TLSv1_2_server_method)
#endif
RESOLVEFUNC(X509_NAME_entry_count)
RESOLVEFUNC(X509_NAME_get_entry)
RESOLVEFUNC(X509_NAME_ENTRY_get_data)
@ -970,12 +1134,12 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(X509_STORE_CTX_get_error)
RESOLVEFUNC(X509_STORE_CTX_get_error_depth)
RESOLVEFUNC(X509_STORE_CTX_get_current_cert)
RESOLVEFUNC(X509_STORE_CTX_get_chain)
RESOLVEFUNC(X509_cmp)
#ifndef SSLEAY_MACROS
RESOLVEFUNC(X509_dup)
#endif
RESOLVEFUNC(X509_print)
RESOLVEFUNC(X509_digest)
RESOLVEFUNC(X509_EXTENSION_get_object)
RESOLVEFUNC(X509_free)
RESOLVEFUNC(X509_get_ext)
@ -991,21 +1155,11 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(X509_check_issued)
RESOLVEFUNC(X509_get_issuer_name)
RESOLVEFUNC(X509_get_subject_name)
RESOLVEFUNC(X509_get_serialNumber)
RESOLVEFUNC(X509_verify_cert)
RESOLVEFUNC(d2i_X509)
RESOLVEFUNC(i2d_X509)
#ifdef SSLEAY_MACROS
RESOLVEFUNC(i2d_DSAPrivateKey)
RESOLVEFUNC(i2d_RSAPrivateKey)
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)
RESOLVEFUNC(SSLeay)
RESOLVEFUNC(SSLeay_version)
RESOLVEFUNC(i2d_SSL_SESSION)
RESOLVEFUNC(d2i_SSL_SESSION)
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG)
@ -1029,27 +1183,14 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(EC_KEY_new_by_curve_name)
RESOLVEFUNC(EC_KEY_free)
RESOLVEFUNC(EC_get_builtin_curves)
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L)
RESOLVEFUNC(EC_curve_nist2nid)
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#endif // OPENSSL_NO_EC
RESOLVEFUNC(PKCS12_parse)
RESOLVEFUNC(d2i_PKCS12_bio)
RESOLVEFUNC(PKCS12_free)
symbolsResolved = true;
delete libs.first;
delete libs.second;
if (!_q_SSLeay || q_SSLeay() >= 0x10100000L) {
// OpenSSL 1.1 deprecated and removed SSLeay. We consider a failure to
// resolve this symbol as a failure to resolve symbols.
// The right operand of '||' above ... a bit of paranoia.
qCWarning(lcSsl, "Incompatible version of OpenSSL");
return false;
}
symbolsResolved = true;
return true;
}
#endif // QT_CONFIG(library)

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
@ -56,6 +56,7 @@
#ifndef QSSLSOCKET_OPENSSL_SYMBOLS_P_H
#define QSSLSOCKET_OPENSSL_SYMBOLS_P_H
//
// W A R N I N G
// -------------
@ -215,20 +216,20 @@ QT_BEGIN_NAMESPACE
#endif // !defined QT_LINKED_OPENSSL
#if QT_CONFIG(opensslv11)
#include "qsslsocket_openssl11_symbols_p.h"
#else
#include "qsslsocket_opensslpre11_symbols_p.h"
#endif // QT_CONFIG
bool q_resolveOpenSslSymbols();
long q_ASN1_INTEGER_get(ASN1_INTEGER *a);
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);
int q_BIO_read(BIO *a, void *b, int c);
Q_AUTOTEST_EXPORT BIO_METHOD *q_BIO_s_mem();
Q_AUTOTEST_EXPORT int q_BIO_write(BIO *a, const void *b, int c);
int q_BN_num_bits(const BIGNUM *a);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
@ -250,27 +251,23 @@ BN_ULONG q_BN_mod_word(const BIGNUM *a, BN_ULONG w);
const EC_GROUP* q_EC_KEY_get0_group(const EC_KEY* k);
int q_EC_GROUP_get_degree(const EC_GROUP* g);
#endif
int q_CRYPTO_num_locks();
void q_CRYPTO_set_locking_callback(void (*a)(int, int, const char *, int));
void q_CRYPTO_set_id_callback(unsigned long (*a)());
void q_CRYPTO_free(void *a);
DSA *q_DSA_new();
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);
EVP_CIPHER_CTX *q_EVP_CIPHER_CTX_new();
void q_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
int q_EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
int q_EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
int q_EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, const unsigned char *key, const unsigned char *iv, int enc);
int q_EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc);
int q_EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
int q_EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
const EVP_CIPHER *q_EVP_des_cbc();
const EVP_CIPHER *q_EVP_des_ede3_cbc();
const EVP_CIPHER *q_EVP_rc2_cbc();
const EVP_MD *q_EVP_sha1();
int q_EVP_PKEY_assign(EVP_PKEY *a, int b, char *c);
Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
@ -314,7 +311,7 @@ int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned
int q_PEM_write_bio_ECPrivateKey(BIO *a, EC_KEY *b, const EVP_CIPHER *c, unsigned char *d,
int e, pem_password_cb *f, void *g);
#endif
#endif
#endif // SSLEAY_MACROS
Q_AUTOTEST_EXPORT EVP_PKEY *q_PEM_read_bio_PUBKEY(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
DSA *q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d);
RSA *q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d);
@ -330,23 +327,10 @@ void q_RAND_seed(const void *a, int b);
int q_RAND_status();
RSA *q_RSA_new();
void q_RSA_free(RSA *a);
int q_sk_num(STACK *a);
void q_sk_pop_free(STACK *a, void (*b)(void *));
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
_STACK *q_sk_new_null();
void q_sk_push(_STACK *st, void *data);
void q_sk_free(_STACK *a);
void * q_sk_value(STACK *a, int b);
#else
STACK *q_sk_new_null();
void q_sk_push(STACK *st, char *data);
void q_sk_free(STACK *a);
char * q_sk_value(STACK *a, int b);
#endif
int q_SSL_accept(SSL *a);
int q_SSL_clear(SSL *a);
char *q_SSL_CIPHER_description(SSL_CIPHER *a, char *b, int c);
int q_SSL_CIPHER_get_bits(SSL_CIPHER *a, int *b);
char *q_SSL_CIPHER_description(const SSL_CIPHER *a, char *b, int c);
int q_SSL_CIPHER_get_bits(const SSL_CIPHER *a, int *b);
int q_SSL_connect(SSL *a);
int q_SSL_CTX_check_private_key(const SSL_CTX *a);
long q_SSL_CTX_ctrl(SSL_CTX *a, int b, long c, void *d);
@ -378,8 +362,6 @@ int q_SSL_get_error(SSL *a, int b);
STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a);
X509 *q_SSL_get_peer_certificate(SSL *a);
long q_SSL_get_verify_result(const SSL *a);
int q_SSL_library_init();
void q_SSL_load_error_strings();
SSL *q_SSL_new(SSL_CTX *a);
long q_SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
int q_SSL_read(SSL *a, void *b, int c);
@ -392,7 +374,6 @@ void q_SSL_SESSION_free(SSL_SESSION *ses);
SSL_SESSION *q_SSL_get1_session(SSL *ssl);
SSL_SESSION *q_SSL_get_session(const SSL *ssl);
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
int q_SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
int q_SSL_set_ex_data(SSL *ssl, int idx, void *arg);
void *q_SSL_get_ex_data(const SSL *ssl, int idx);
#endif
@ -403,49 +384,6 @@ typedef unsigned int (*q_psk_server_callback_t)(SSL *ssl, const char *identity,
void q_SSL_set_psk_server_callback(SSL *ssl, q_psk_server_callback_t callback);
int q_SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint);
#endif // OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_SSL2
const SSL_METHOD *q_SSLv2_client_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
const SSL_METHOD *q_SSLv3_client_method();
#endif
const SSL_METHOD *q_SSLv23_client_method();
const SSL_METHOD *q_TLSv1_client_method();
const SSL_METHOD *q_TLSv1_1_client_method();
const SSL_METHOD *q_TLSv1_2_client_method();
#ifndef OPENSSL_NO_SSL2
const SSL_METHOD *q_SSLv2_server_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
const SSL_METHOD *q_SSLv3_server_method();
#endif
const SSL_METHOD *q_SSLv23_server_method();
const SSL_METHOD *q_TLSv1_server_method();
const SSL_METHOD *q_TLSv1_1_server_method();
const SSL_METHOD *q_TLSv1_2_server_method();
#else
#ifndef OPENSSL_NO_SSL2
SSL_METHOD *q_SSLv2_client_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
SSL_METHOD *q_SSLv3_client_method();
#endif
SSL_METHOD *q_SSLv23_client_method();
SSL_METHOD *q_TLSv1_client_method();
SSL_METHOD *q_TLSv1_1_client_method();
SSL_METHOD *q_TLSv1_2_client_method();
#ifndef OPENSSL_NO_SSL2
SSL_METHOD *q_SSLv2_server_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
SSL_METHOD *q_SSLv3_server_method();
#endif
SSL_METHOD *q_SSLv23_server_method();
SSL_METHOD *q_TLSv1_server_method();
SSL_METHOD *q_TLSv1_1_server_method();
SSL_METHOD *q_TLSv1_2_server_method();
#endif
int q_SSL_write(SSL *a, const void *b, int c);
int q_X509_cmp(X509 *a, X509 *b);
#ifdef SSLEAY_MACROS
@ -456,6 +394,7 @@ void *q_ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x);
X509 *q_X509_dup(X509 *a);
#endif
void q_X509_print(BIO *a, X509*b);
int q_X509_digest(const X509 *x509, const EVP_MD *type, unsigned char *md, unsigned int *len);
ASN1_OBJECT *q_X509_EXTENSION_get_object(X509_EXTENSION *a);
void q_X509_free(X509 *a);
X509_EXTENSION *q_X509_get_ext(X509 *a, int b);
@ -475,6 +414,7 @@ int q_ASN1_STRING_print(BIO *a, ASN1_STRING *b);
int q_X509_check_issued(X509 *a, X509 *b);
X509_NAME *q_X509_get_issuer_name(X509 *a);
X509_NAME *q_X509_get_subject_name(X509 *a);
ASN1_INTEGER *q_X509_get_serialNumber(X509 *a);
int q_X509_verify_cert(X509_STORE_CTX *ctx);
int q_X509_NAME_entry_count(X509_NAME *a);
X509_NAME_ENTRY *q_X509_NAME_get_entry(X509_NAME *a,int b);
@ -492,7 +432,6 @@ int q_X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
int q_X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
int q_X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
X509 *q_X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
STACK_OF(X509) *q_X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
// Diffie-Hellman support
DH *q_DH_new();
@ -526,34 +465,9 @@ int q_PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert,
PKCS12 *q_d2i_PKCS12_bio(BIO *bio, PKCS12 **pkcs12);
void q_PKCS12_free(PKCS12 *pkcs12);
#define q_BIO_get_mem_data(b, pp) (int)q_BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
#define q_BIO_pending(b) (int)q_BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
#ifdef SSLEAY_MACROS
int q_i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
int q_i2d_RSAPrivateKey(const RSA *a, unsigned char **pp);
RSA *q_d2i_RSAPrivateKey(RSA **a, unsigned char **pp, long length);
DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#define q_PEM_read_bio_RSAPrivateKey(bp, x, cb, u) \
(RSA *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_RSAPrivateKey, PEM_STRING_RSA, bp, (void **)x, cb, u)
#define q_PEM_read_bio_DSAPrivateKey(bp, x, cb, u) \
(DSA *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_DSAPrivateKey, PEM_STRING_DSA, bp, (void **)x, cb, u)
#define q_PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_RSAPrivateKey,PEM_STRING_RSA,\
bp,(char *)x,enc,kstr,klen,cb,u)
#define q_PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_DSAPrivateKey,PEM_STRING_DSA,\
bp,(char *)x,enc,kstr,klen,cb,u)
#define q_PEM_read_bio_DHparams(bp, dh, cb, u) \
(DH *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_DHparams, PEM_STRING_DHPARAMS, bp, (void **)x, cb, u)
#endif
#define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st)
#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_sk_value)(st, i)
#define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st))
#define q_sk_GENERAL_NAME_value(st, i) q_SKM_sk_value(GENERAL_NAME, (st), (i))
#define q_sk_X509_num(st) q_SKM_sk_num(X509, (st))
@ -562,19 +476,12 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i))
#define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \
q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
#define q_X509_get_notAfter(x) X509_get_notAfter(x)
#define q_X509_get_notBefore(x) X509_get_notBefore(x)
#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
(char *)(rsa))
#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);
long q_SSLeay();
const char *q_SSLeay_version(int type);
int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
SSL_SESSION *q_d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length);

View File

@ -0,0 +1,424 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 Governikus GmbH & Co. KG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
/****************************************************************************
**
** In addition, as a special exception, the copyright holders listed above give
** permission to link the code of its release of Qt with the OpenSSL project's
** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
** same license as the original version), and distribute the linked executables.
**
** You must comply with the GNU General Public License version 2 in all
** respects for all of the code used other than the "OpenSSL" code. If you
** modify this file, you may extend this exception to your version of the file,
** but you are not obligated to do so. If you do not wish to do so, delete
** this exception statement from your version of this file.
**
****************************************************************************/
//#define QT_DECRYPT_SSL_TRAFFIC
#include "qssl_p.h"
#include "qsslsocket_openssl_p.h"
#include "qsslsocket_openssl_symbols_p.h"
#include "qsslsocket.h"
#include "qsslkey.h"
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qthread.h>
#include <QtCore/qfile.h>
#include <QtCore/qmutex.h>
#include <QtCore/qlibrary.h>
QT_BEGIN_NAMESPACE
/* \internal
From OpenSSL's thread(3) manual page:
OpenSSL can safely be used in multi-threaded applications provided that at
least two callback functions are set.
locking_function(int mode, int n, const char *file, int line) is needed to
perform locking on shared data structures. (Note that OpenSSL uses a
number of global data structures that will be implicitly shared
whenever multiple threads use OpenSSL.) Multi-threaded
applications will crash at random if it is not set. ...
...
id_function(void) is a function that returns a thread ID. It is not
needed on Windows nor on platforms where getpid() returns a different
ID for each thread (most notably Linux)
*/
class QOpenSslLocks
{
public:
QOpenSslLocks()
: initLocker(QMutex::Recursive),
locksLocker(QMutex::Recursive)
{
QMutexLocker locker(&locksLocker);
int numLocks = q_CRYPTO_num_locks();
locks = new QMutex *[numLocks];
memset(locks, 0, numLocks * sizeof(QMutex *));
}
~QOpenSslLocks()
{
QMutexLocker locker(&locksLocker);
for (int i = 0; i < q_CRYPTO_num_locks(); ++i)
delete locks[i];
delete [] locks;
QSslSocketPrivate::deinitialize();
}
QMutex *lock(int num)
{
QMutexLocker locker(&locksLocker);
QMutex *tmp = locks[num];
if (!tmp)
tmp = locks[num] = new QMutex(QMutex::Recursive);
return tmp;
}
QMutex *globalLock()
{
return &locksLocker;
}
QMutex *initLock()
{
return &initLocker;
}
private:
QMutex initLocker;
QMutex locksLocker;
QMutex **locks;
};
Q_GLOBAL_STATIC(QOpenSslLocks, openssl_locks)
extern "C" {
static void locking_function(int mode, int lockNumber, const char *, int)
{
QMutex *mutex = openssl_locks()->lock(lockNumber);
// Lock or unlock it
if (mode & CRYPTO_LOCK)
mutex->lock();
else
mutex->unlock();
}
static unsigned long id_function()
{
return (quintptr)QThread::currentThreadId();
}
} // 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_CRYPTO_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();
}
/*!
\internal
*/
void QSslSocketPrivate::deinitialize()
{
q_CRYPTO_set_id_callback(0);
q_CRYPTO_set_locking_callback(0);
q_ERR_free_strings();
}
bool QSslSocketPrivate::ensureLibraryLoaded()
{
if (!q_resolveOpenSslSymbols())
return false;
// Check if the library itself needs to be initialized.
QMutexLocker locker(openssl_locks()->initLock());
if (!s_libraryLoaded) {
s_libraryLoaded = true;
// Initialize OpenSSL.
q_CRYPTO_set_id_callback(id_function);
q_CRYPTO_set_locking_callback(locking_function);
if (q_SSL_library_init() != 1)
return false;
q_SSL_load_error_strings();
q_OpenSSL_add_all_algorithms_safe();
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
if (q_SSLeay() >= 0x10001000L)
QSslSocketBackendPrivate::s_indexForSSLExtraData = q_SSL_get_ex_new_index(0L, NULL, NULL, NULL, NULL);
#endif
// Initialize OpenSSL's random seed.
if (!q_RAND_status()) {
qWarning("Random number generator not seeded, disabling SSL support");
return false;
}
}
return true;
}
void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
{
QMutexLocker locker(openssl_locks()->initLock());
if (s_loadedCiphersAndCerts)
return;
s_loadedCiphersAndCerts = true;
resetDefaultCiphers();
resetDefaultEllipticCurves();
#if QT_CONFIG(library)
//load symbols needed to receive certificates from system store
#if defined(Q_OS_WIN)
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
if (hLib) {
ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW");
ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore");
ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore");
if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore)
qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen
} else {
qCWarning(lcSsl, "could not load crypt32 library"); // should never happen
}
#elif defined(Q_OS_QNX)
s_loadRootCertsOnDemand = true;
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
// check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
QList<QByteArray> dirs = unixRootCertDirectories();
QStringList symLinkFilter;
symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
for (int a = 0; a < dirs.count(); ++a) {
QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
if (iterator.hasNext()) {
s_loadRootCertsOnDemand = true;
break;
}
}
#endif
#endif // QT_CONFIG(library)
// if on-demand loading was not enabled, load the certs now
if (!s_loadRootCertsOnDemand)
setDefaultCaCertificates(systemCaCertificates());
#ifdef Q_OS_WIN
//Enabled for fetching additional root certs from windows update on windows 6+
//This flag is set false by setDefaultCaCertificates() indicating the app uses
//its own cert bundle rather than the system one.
//Same logic that disables the unix on demand cert loading.
//Unlike unix, we do preload the certificates from the cert store.
if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_6_0)
s_loadRootCertsOnDemand = true;
#endif
}
long QSslSocketPrivate::sslLibraryVersionNumber()
{
if (!supportsSsl())
return 0;
return q_SSLeay();
}
QString QSslSocketPrivate::sslLibraryVersionString()
{
if (!supportsSsl())
return QString();
const char *versionString = q_SSLeay_version(SSLEAY_VERSION);
if (!versionString)
return QString();
return QString::fromLatin1(versionString);
}
void QSslSocketBackendPrivate::continueHandshake()
{
Q_Q(QSslSocket);
// if we have a max read buffer size, reset the plain socket's to match
if (readBufferMaxSize)
plainSocket->setReadBufferSize(readBufferMaxSize);
if (q_SSL_ctrl((ssl), SSL_CTRL_GET_SESSION_REUSED, 0, NULL))
configuration.peerSessionShared = true;
#ifdef QT_DECRYPT_SSL_TRAFFIC
if (ssl->session && ssl->s3) {
const char *mk = reinterpret_cast<const char *>(ssl->session->master_key);
QByteArray masterKey(mk, ssl->session->master_key_length);
const char *random = reinterpret_cast<const char *>(ssl->s3->client_random);
QByteArray clientRandom(random, SSL3_RANDOM_SIZE);
// different format, needed for e.g. older Wireshark versions:
// const char *sid = reinterpret_cast<const char *>(ssl->session->session_id);
// QByteArray sessionID(sid, ssl->session->session_id_length);
// QByteArray debugLineRSA("RSA Session-ID:");
// debugLineRSA.append(sessionID.toHex().toUpper());
// debugLineRSA.append(" Master-Key:");
// debugLineRSA.append(masterKey.toHex().toUpper());
// debugLineRSA.append("\n");
QByteArray debugLineClientRandom("CLIENT_RANDOM ");
debugLineClientRandom.append(clientRandom.toHex().toUpper());
debugLineClientRandom.append(" ");
debugLineClientRandom.append(masterKey.toHex().toUpper());
debugLineClientRandom.append("\n");
QString sslKeyFile = QDir::tempPath() + QLatin1String("/qt-ssl-keys");
QFile file(sslKeyFile);
if (!file.open(QIODevice::Append))
qCWarning(lcSsl) << "could not open file" << sslKeyFile << "for appending";
if (!file.write(debugLineClientRandom))
qCWarning(lcSsl) << "could not write to file" << sslKeyFile;
file.close();
} else {
qCWarning(lcSsl, "could not decrypt SSL traffic");
}
#endif
// Cache this SSL session inside the QSslContext
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) {
if (!sslContextPointer->cacheSession(ssl)) {
sslContextPointer.clear(); // we could not cache the session
} else {
// Cache the session for permanent usage as well
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) {
if (!sslContextPointer->sessionASN1().isEmpty())
configuration.sslSession = sslContextPointer->sessionASN1();
configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint();
}
}
}
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG)
configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
// we could not agree -> be conservative and use HTTP/1.1
configuration.nextNegotiatedProtocol = QByteArrayLiteral("http/1.1");
} else {
const unsigned char *proto = 0;
unsigned int proto_len = 0;
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L) {
q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
if (proto_len && mode == QSslSocket::SslClientMode) {
// Client does not have a callback that sets it ...
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
}
}
if (!proto_len) { // Test if NPN was more lucky ...
#else
{
#endif
q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
}
if (proto_len)
configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len);
else
configuration.nextNegotiatedProtocol.clear();
}
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (q_SSLeay() >= 0x10002000L && mode == QSslSocket::SslClientMode) {
EVP_PKEY *key;
if (q_SSL_get_server_tmp_key(ssl, &key))
configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey);
}
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ...
connectionEncrypted = true;
emit q->encrypted();
if (autoStartHandshake && pendingClose) {
pendingClose = false;
q->disconnectFromHost();
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,230 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
/****************************************************************************
**
** In addition, as a special exception, the copyright holders listed above give
** permission to link the code of its release of Qt with the OpenSSL project's
** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
** same license as the original version), and distribute the linked executables.
**
** You must comply with the GNU General Public License version 2 in all
** respects for all of the code used other than the "OpenSSL" code. If you
** modify this file, you may extend this exception to your version of the file,
** but you are not obligated to do so. If you do not wish to do so, delete
** this exception statement from your version of this file.
**
****************************************************************************/
#ifndef QSSLSOCKET_OPENSSLPRE11_SYMBOLS_P_H
#define QSSLSOCKET_OPENSSLPRE11_SYMBOLS_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
// Note: this file does not have QT_BEGIN_NAMESPACE/QT_END_NAMESPACE, it's done
// in qsslsocket_openssl_symbols_p.h.
#ifndef QSSLSOCKET_OPENSSL_SYMBOLS_P_H
#error "You are not supposed to use this header file, include qsslsocket_openssl_symbols_p.h instead"
#endif
unsigned char * q_ASN1_STRING_data(ASN1_STRING *a);
BIO *q_BIO_new_file(const char *filename, const char *mode);
void q_ERR_clear_error();
Q_AUTOTEST_EXPORT BIO *q_BIO_new(BIO_METHOD *a);
Q_AUTOTEST_EXPORT BIO_METHOD *q_BIO_s_mem();
int q_CRYPTO_num_locks();
void q_CRYPTO_set_locking_callback(void (*a)(int, int, const char *, int));
void q_CRYPTO_set_id_callback(unsigned long (*a)());
void q_CRYPTO_free(void *a);
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);
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
typedef _STACK STACK;
#endif
// The typedef we use to make our pre 1.1 code look more like 1.1 (less ifdefs).
typedef STACK OPENSSL_STACK;
// We resolve q_sk_ functions, but use q_OPENSSL_sk_ macros in code to reduce
// the amount of #ifdefs.
int q_sk_num(STACK *a);
#define q_OPENSSL_sk_num(a) q_sk_num(a)
void q_sk_pop_free(STACK *a, void (*b)(void *));
#define q_OPENSSL_sk_pop_free(a, b) q_sk_pop_free(a, b)
STACK *q_sk_new_null();
#define q_OPENSSL_sk_new_null() q_sk_new_null()
void q_sk_free(STACK *a);
// Just a name alias (not a function call expression) since in code we take an
// address of this:
#define q_OPENSSL_sk_free q_sk_free
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
void *q_sk_value(STACK *a, int b);
void q_sk_push(STACK *st, void *data);
#else
char *q_sk_value(STACK *a, int b);
void q_sk_push(STACK *st, char *data);
#endif // OPENSSL_VERSION_NUMBER >= 0x10000000L
#define q_OPENSSL_sk_value(a, b) q_sk_value(a, b)
#define q_OPENSSL_sk_push(st, data) q_sk_push(st, data)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a);
#else
SSL_CTX *q_SSL_CTX_new(SSL_METHOD *a);
#endif
int q_SSL_library_init();
void q_SSL_load_error_strings();
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
int q_SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_SSL2
const SSL_METHOD *q_SSLv2_client_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
const SSL_METHOD *q_SSLv3_client_method();
#endif
const SSL_METHOD *q_SSLv23_client_method();
const SSL_METHOD *q_TLSv1_client_method();
const SSL_METHOD *q_TLSv1_1_client_method();
const SSL_METHOD *q_TLSv1_2_client_method();
#ifndef OPENSSL_NO_SSL2
const SSL_METHOD *q_SSLv2_server_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
const SSL_METHOD *q_SSLv3_server_method();
#endif
const SSL_METHOD *q_SSLv23_server_method();
const SSL_METHOD *q_TLSv1_server_method();
const SSL_METHOD *q_TLSv1_1_server_method();
const SSL_METHOD *q_TLSv1_2_server_method();
#else
#ifndef OPENSSL_NO_SSL2
SSL_METHOD *q_SSLv2_client_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
SSL_METHOD *q_SSLv3_client_method();
#endif
SSL_METHOD *q_SSLv23_client_method();
SSL_METHOD *q_TLSv1_client_method();
SSL_METHOD *q_TLSv1_1_client_method();
SSL_METHOD *q_TLSv1_2_client_method();
#ifndef OPENSSL_NO_SSL2
SSL_METHOD *q_SSLv2_server_method();
#endif
#ifndef OPENSSL_NO_SSL3_METHOD
SSL_METHOD *q_SSLv3_server_method();
#endif
SSL_METHOD *q_SSLv23_server_method();
SSL_METHOD *q_TLSv1_server_method();
SSL_METHOD *q_TLSv1_1_server_method();
SSL_METHOD *q_TLSv1_2_server_method();
#endif
STACK_OF(X509) *q_X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
#ifdef SSLEAY_MACROS
int q_i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
int q_i2d_RSAPrivateKey(const RSA *a, unsigned char **pp);
RSA *q_d2i_RSAPrivateKey(RSA **a, unsigned char **pp, long length);
DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#define q_PEM_read_bio_RSAPrivateKey(bp, x, cb, u) \
(RSA *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_RSAPrivateKey, PEM_STRING_RSA, bp, (void **)x, cb, u)
#define q_PEM_read_bio_DSAPrivateKey(bp, x, cb, u) \
(DSA *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_DSAPrivateKey, PEM_STRING_DSA, bp, (void **)x, cb, u)
#define q_PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_RSAPrivateKey,PEM_STRING_RSA,\
bp,(char *)x,enc,kstr,klen,cb,u)
#define q_PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_DSAPrivateKey,PEM_STRING_DSA,\
bp,(char *)x,enc,kstr,klen,cb,u)
#define q_PEM_read_bio_DHparams(bp, dh, cb, u) \
(DH *)q_PEM_ASN1_read_bio( \
(void *(*)(void**, const unsigned char**, long int))q_d2i_DHparams, PEM_STRING_DHPARAMS, bp, (void **)x, cb, u)
#endif // SSLEAY_MACROS
#define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st)
#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_sk_value)(st, i)
#define q_X509_getm_notAfter(x) X509_get_notAfter(x)
#define q_X509_getm_notBefore(x) X509_get_notBefore(x)
// "Forward compatibility" with OpenSSL 1.1 (to save on #if-ery elsewhere):
#define q_X509_get_version(x509) q_ASN1_INTEGER_get((x509)->cert_info->version)
#define q_ASN1_STRING_get0_data(x) q_ASN1_STRING_data(x)
#define q_EVP_PKEY_base_id(pkey) ((pkey)->type)
#define q_X509_get_pubkey(x509) q_X509_PUBKEY_get((x509)->cert_info->key)
#define q_SSL_SESSION_get_ticket_lifetime_hint(s) ((s)->tlsext_tick_lifetime_hint)
#define q_RSA_bits(rsa) q_BN_num_bits((rsa)->n)
#define q_DSA_bits(dsa) q_BN_num_bits((dsa)->p)
#define q_X509_STORE_set_verify_cb(s,c) X509_STORE_set_verify_cb_func((s),(c))
char *q_CONF_get1_default_config_file();
void q_OPENSSL_add_all_algorithms_noconf();
void q_OPENSSL_add_all_algorithms_conf();
long q_SSLeay();
const char *q_SSLeay_version(int type);
#endif // QSSLSOCKET_OPENSSL_PRE11_SYMBOLS_P_H

View File

@ -60,13 +60,25 @@ qtConfig(ssl) {
HEADERS += ssl/qsslcontext_openssl_p.h \
ssl/qsslsocket_openssl_p.h \
ssl/qsslsocket_openssl_symbols_p.h
SOURCES += ssl/qsslcertificate_openssl.cpp \
ssl/qsslcontext_openssl.cpp \
SOURCES += ssl/qsslsocket_openssl_symbols.cpp \
ssl/qssldiffiehellmanparameters_openssl.cpp \
ssl/qsslcertificate_openssl.cpp \
ssl/qsslellipticcurve_openssl.cpp \
ssl/qsslkey_openssl.cpp \
ssl/qsslsocket_openssl.cpp \
ssl/qsslsocket_openssl_symbols.cpp
ssl/qsslcontext_openssl.cpp
qtConfig(opensslv11) {
HEADERS += ssl/qsslsocket_openssl11_symbols_p.h
SOURCES += ssl/qsslsocket_openssl11.cpp \
ssl/qsslcontext_openssl11.cpp
QMAKE_CXXFLAGS += -DOPENSSL_API_COMPAT=0x10100000L
} else {
HEADERS += ssl/qsslsocket_opensslpre11_symbols_p.h
SOURCES += ssl/qsslsocket_opensslpre11.cpp \
ssl/qsslcontext_opensslpre11.cpp
}
darwin:SOURCES += ssl/qsslsocket_mac_shared.cpp