summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qnetworkaccessftpbackend.cpp61
-rw-r--r--src/network/access/qnetworkaccessftpbackend_p.h5
-rw-r--r--src/network/access/qnetworkrequest.cpp114
-rw-r--r--src/network/access/qnetworkrequest.h6
-rw-r--r--src/network/ssl/qasn1element_p.h25
-rw-r--r--src/network/ssl/qssl.cpp4
-rw-r--r--src/network/ssl/qssl.h5
-rw-r--r--src/network/ssl/qsslconfiguration.cpp56
-rw-r--r--src/network/ssl/qsslconfiguration.h6
-rw-r--r--src/network/ssl/qsslconfiguration_p.h5
-rw-r--r--src/network/ssl/qsslcontext_openssl11.cpp7
-rw-r--r--src/network/ssl/qsslcontext_opensslpre11.cpp7
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp4
-rw-r--r--src/network/ssl/qsslkey_p.cpp92
-rw-r--r--src/network/ssl/qsslkey_p.h7
-rw-r--r--src/network/ssl/qsslkey_qt.cpp5
-rw-r--r--src/network/ssl/qsslsocket.cpp61
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp186
-rw-r--r--src/network/ssl/qsslsocket_openssl11_symbols_p.h39
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h17
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp78
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h35
-rw-r--r--src/network/ssl/qsslsocket_opensslpre11_symbols_p.h7
-rw-r--r--src/network/ssl/qwindowscarootfetcher.cpp163
-rw-r--r--src/network/ssl/qwindowscarootfetcher_p.h79
-rw-r--r--src/network/ssl/ssl.pri6
26 files changed, 898 insertions, 182 deletions
diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp
index c5404e4221..269845ed39 100644
--- a/src/network/access/qnetworkaccessftpbackend.cpp
+++ b/src/network/access/qnetworkaccessftpbackend.cpp
@@ -102,8 +102,8 @@ public:
};
QNetworkAccessFtpBackend::QNetworkAccessFtpBackend()
- : ftp(0), uploadDevice(0), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1),
- supportsSize(false), supportsMdtm(false), state(Idle)
+ : ftp(0), uploadDevice(0), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1), pwdId(-1),
+ supportsSize(false), supportsMdtm(false), supportsPwd(false), state(Idle)
{
}
@@ -302,13 +302,38 @@ void QNetworkAccessFtpBackend::ftpDone()
if (state == LoggingIn) {
state = CheckingFeatures;
- if (operation() == QNetworkAccessManager::GetOperation) {
- // send help command to find out if server supports "SIZE" and "MDTM"
+ // send help command to find out if server supports SIZE, MDTM, and PWD
+ if (operation() == QNetworkAccessManager::GetOperation
+ || operation() == QNetworkAccessManager::PutOperation) {
helpId = ftp->rawCommand(QLatin1String("HELP")); // get supported commands
} else {
ftpDone();
}
} else if (state == CheckingFeatures) {
+ // If a URL path starts with // prefix (/%2F decoded), the resource will
+ // be retrieved by an absolute path starting with the root directory.
+ // For the other URLs, the working directory is retrieved by PWD command
+ // and prepended to the resource path as an absolute path starting with
+ // the working directory.
+ state = ResolvingPath;
+ QString path = url().path();
+ if (path.startsWith(QLatin1String("//")) || supportsPwd == false) {
+ ftpDone(); // no commands sent, move to the next state
+ } else {
+ // If a path starts with /~/ prefix, its prefix will be replaced by
+ // the working directory as an absolute path starting with working
+ // directory.
+ if (path.startsWith(QLatin1String("/~/"))) {
+ // Remove leading /~ symbols
+ QUrl newUrl = url();
+ newUrl.setPath(path.mid(2));
+ setUrl(newUrl);
+ }
+
+ // send PWD command to retrieve the working directory
+ pwdId = ftp->rawCommand(QLatin1String("PWD"));
+ }
+ } else if (state == ResolvingPath) {
state = Statting;
if (operation() == QNetworkAccessManager::GetOperation) {
// logged in successfully, send the stat requests (if supported)
@@ -366,6 +391,34 @@ void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text)
supportsSize = true;
if (text.contains(QLatin1String("MDTM"), Qt::CaseSensitive))
supportsMdtm = true;
+ if (text.contains(QLatin1String("PWD"), Qt::CaseSensitive))
+ supportsPwd = true;
+ } else if (id == pwdId && code == 257) {
+ QString pwdPath;
+ int startIndex = text.indexOf('"');
+ int stopIndex = text.lastIndexOf('"');
+ if (stopIndex - startIndex) {
+ // The working directory is a substring between \" symbols.
+ startIndex++; // skip the first \" symbol
+ pwdPath = text.mid(startIndex, stopIndex - startIndex);
+ } else {
+ // If there is no or only one \" symbol, use all the characters of
+ // text.
+ pwdPath = text;
+ }
+
+ // If a URL path starts with the working directory prefix, its resource
+ // will be retrieved from the working directory. Otherwise, the path of
+ // the working directory is prepended to the resource path.
+ QString urlPath = url().path();
+ if (!urlPath.startsWith(pwdPath)) {
+ if (pwdPath.endsWith(QLatin1Char('/')))
+ pwdPath.chop(1);
+ // Prepend working directory to the URL path
+ QUrl newUrl = url();
+ newUrl.setPath(pwdPath % urlPath);
+ setUrl(newUrl);
+ }
} else if (code == 213) { // file status
if (id == sizeId) {
// reply to the size command
diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h
index 4bd082fb67..0b3d35dcd3 100644
--- a/src/network/access/qnetworkaccessftpbackend_p.h
+++ b/src/network/access/qnetworkaccessftpbackend_p.h
@@ -76,6 +76,7 @@ public:
//Connecting,
LoggingIn,
CheckingFeatures,
+ ResolvingPath,
Statting,
Transferring,
Disconnecting
@@ -107,8 +108,8 @@ private:
QPointer<QNetworkAccessCachedFtpConnection> ftp;
QIODevice *uploadDevice;
qint64 totalBytes;
- int helpId, sizeId, mdtmId;
- bool supportsSize, supportsMdtm;
+ int helpId, sizeId, mdtmId, pwdId;
+ bool supportsSize, supportsMdtm, supportsPwd;
State state;
};
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index 1d7c5bec51..2d6df9de21 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -98,6 +98,25 @@ QT_BEGIN_NAMESPACE
header and contains a QDateTime representing the last modification
date of the contents.
+ \value IfModifiedSinceHeader Corresponds to the HTTP If-Modified-Since
+ header and contains a QDateTime. It is usually added to a
+ QNetworkRequest. The server shall send a 304 (Not Modified) response
+ if the resource has not changed since this time.
+
+ \value ETagHeader Corresponds to the HTTP ETag
+ header and contains a QString representing the last modification
+ state of the contents.
+
+ \value IfMatchHeader Corresponds to the HTTP If-Match
+ header and contains a QStringList. It is usually added to a
+ QNetworkRequest. The server shall send a 412 (Precondition Failed)
+ response if the resource does not match.
+
+ \value IfNoneMatchHeader Corresponds to the HTTP If-None-Match
+ header and contains a QStringList. It is usually added to a
+ QNetworkRequest. The server shall send a 304 (Not Modified) response
+ if the resource does match.
+
\value CookieHeader Corresponds to the HTTP Cookie header
and contains a QList<QNetworkCookie> representing the cookies to
be sent back to the server.
@@ -788,6 +807,18 @@ static QByteArray headerName(QNetworkRequest::KnownHeaders header)
case QNetworkRequest::LastModifiedHeader:
return "Last-Modified";
+ case QNetworkRequest::IfModifiedSinceHeader:
+ return "If-Modified-Since";
+
+ case QNetworkRequest::ETagHeader:
+ return "ETag";
+
+ case QNetworkRequest::IfMatchHeader:
+ return "If-Match";
+
+ case QNetworkRequest::IfNoneMatchHeader:
+ return "If-None-Match";
+
case QNetworkRequest::CookieHeader:
return "Cookie";
@@ -818,6 +849,9 @@ static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVaria
case QNetworkRequest::ContentDispositionHeader:
case QNetworkRequest::UserAgentHeader:
case QNetworkRequest::ServerHeader:
+ case QNetworkRequest::ETagHeader:
+ case QNetworkRequest::IfMatchHeader:
+ case QNetworkRequest::IfNoneMatchHeader:
return value.toByteArray();
case QNetworkRequest::LocationHeader:
@@ -830,6 +864,7 @@ static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVaria
}
case QNetworkRequest::LastModifiedHeader:
+ case QNetworkRequest::IfModifiedSinceHeader:
switch (value.userType()) {
case QMetaType::QDate:
case QMetaType::QDateTime:
@@ -891,6 +926,20 @@ static int parseHeaderName(const QByteArray &headerName)
return QNetworkRequest::CookieHeader;
break;
+ case 'e':
+ if (qstricmp(headerName.constData(), "etag") == 0)
+ return QNetworkRequest::ETagHeader;
+ break;
+
+ case 'i':
+ if (qstricmp(headerName.constData(), "if-modified-since") == 0)
+ return QNetworkRequest::IfModifiedSinceHeader;
+ if (qstricmp(headerName.constData(), "if-match") == 0)
+ return QNetworkRequest::IfMatchHeader;
+ if (qstricmp(headerName.constData(), "if-none-match") == 0)
+ return QNetworkRequest::IfNoneMatchHeader;
+ break;
+
case 'l':
if (qstricmp(headerName.constData(), "location") == 0)
return QNetworkRequest::LocationHeader;
@@ -937,6 +986,61 @@ static QVariant parseCookieHeader(const QByteArray &raw)
return QVariant::fromValue(result);
}
+static QVariant parseETag(const QByteArray &raw)
+{
+ const QByteArray trimmed = raw.trimmed();
+ if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
+ return QVariant();
+
+ if (!trimmed.endsWith('"'))
+ return QVariant();
+
+ return QString::fromLatin1(trimmed);
+}
+
+static QVariant parseIfMatch(const QByteArray &raw)
+{
+ const QByteArray trimmedRaw = raw.trimmed();
+ if (trimmedRaw == "*")
+ return QStringList(QStringLiteral("*"));
+
+ QStringList tags;
+ const QList<QByteArray> split = trimmedRaw.split(',');
+ for (const QByteArray &element : split) {
+ const QByteArray trimmed = element.trimmed();
+ if (!trimmed.startsWith('"'))
+ continue;
+
+ if (!trimmed.endsWith('"'))
+ continue;
+
+ tags += QString::fromLatin1(trimmed);
+ }
+ return tags;
+}
+
+static QVariant parseIfNoneMatch(const QByteArray &raw)
+{
+ const QByteArray trimmedRaw = raw.trimmed();
+ if (trimmedRaw == "*")
+ return QStringList(QStringLiteral("*"));
+
+ QStringList tags;
+ const QList<QByteArray> split = trimmedRaw.split(',');
+ for (const QByteArray &element : split) {
+ const QByteArray trimmed = element.trimmed();
+ if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
+ continue;
+
+ if (!trimmed.endsWith('"'))
+ continue;
+
+ tags += QString::fromLatin1(trimmed);
+ }
+ return tags;
+}
+
+
static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QByteArray &value)
{
// header is always a valid value
@@ -963,8 +1067,18 @@ static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QBy
}
case QNetworkRequest::LastModifiedHeader:
+ case QNetworkRequest::IfModifiedSinceHeader:
return parseHttpDate(value);
+ case QNetworkRequest::ETagHeader:
+ return parseETag(value);
+
+ case QNetworkRequest::IfMatchHeader:
+ return parseIfMatch(value);
+
+ case QNetworkRequest::IfNoneMatchHeader:
+ return parseIfNoneMatch(value);
+
case QNetworkRequest::CookieHeader:
return parseCookieHeader(value);
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index e104c139d9..8462eae8c8 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -63,7 +63,11 @@ public:
SetCookieHeader,
ContentDispositionHeader, // added for QMultipartMessage
UserAgentHeader,
- ServerHeader
+ ServerHeader,
+ IfModifiedSinceHeader,
+ ETagHeader,
+ IfMatchHeader,
+ IfNoneMatchHeader
};
enum Attribute {
HttpStatusCodeAttribute,
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h
index 2c5019b4f7..c706c1f321 100644
--- a/src/network/ssl/qasn1element_p.h
+++ b/src/network/ssl/qasn1element_p.h
@@ -58,10 +58,33 @@
QT_BEGIN_NAMESPACE
-#define RSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.113549.1.1.1")
+// General
+#define RSADSI_OID "1.2.840.113549."
+
+#define RSA_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.1.1")
#define DSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10040.4.1")
#define EC_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10045.2.1")
+// These are mostly from the RFC for PKCS#5
+// PKCS#5: https://tools.ietf.org/html/rfc8018#appendix-B
+#define PKCS5_OID RSADSI_OID "1.5."
+// PKCS#12: https://tools.ietf.org/html/rfc7292#appendix-D)
+#define PKCS12_OID RSADSI_OID "1.12."
+
+// -PBES1
+#define PKCS5_MD2_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "1")
+#define PKCS5_MD2_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "4")
+#define PKCS5_MD5_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "3")
+#define PKCS5_MD5_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "6")
+#define PKCS5_SHA1_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "10")
+#define PKCS5_SHA1_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "11")
+
+// -PBKDF2
+#define PKCS5_PBKDF2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "12")
+
+// -PBES2
+#define PKCS5_PBES2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "13")
+
class Q_AUTOTEST_EXPORT QAsn1Element
{
public:
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index 51779dec33..3a0983e8b5 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -125,6 +125,10 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value TlsV1_1OrLater TLSv1.1 and later versions. This option is not available when using the WinRT backend due to platform limitations.
\value TlsV1_2 TLSv1.2. When using the WinRT backend this option will also enable TLSv1.0 and TLSv1.1.
\value TlsV1_2OrLater TLSv1.2 and later versions. This option is not available when using the WinRT backend due to platform limitations.
+ \value DtlsV1_0 DTLSv1.0
+ \value DtlsV1_0OrLater DTLSv1.0 and later versions.
+ \value DtlsV1_2 DTLSv1.2
+ \value DtlsV1_2OrLater DTLSv1.2 and later versions.
\value UnknownProtocol The cipher's protocol cannot be determined.
\value AnyProtocol The socket understands SSLv2, SSLv3, TLSv1.0 and all
supported later versions of TLS. This value is used by QSslSocket only.
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index c2a468c97c..0f091b181a 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -91,6 +91,11 @@ namespace QSsl {
TlsV1_1OrLater,
TlsV1_2OrLater,
+ DtlsV1_0,
+ DtlsV1_0OrLater,
+ DtlsV1_2,
+ DtlsV1_2OrLater,
+
UnknownProtocol = -1
};
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 116a6693c4..8c9fa5d4f2 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -998,6 +998,27 @@ QSslConfiguration::NextProtocolNegotiationStatus QSslConfiguration::nextProtocol
}
/*!
+ This function returns true if DTLS cookie verification was enabled on a
+ server-side socket.
+
+ \sa setDtlsCookieVerificationEnabled()
+ */
+bool QSslConfiguration::dtlsCookieVerificationEnabled() const
+{
+ return d->dtlsCookieEnabled;
+}
+
+/*!
+ This function enables DTLS cookie verification when \a enable is true.
+
+ \sa dtlsCookieVerificationEnabled()
+ */
+void QSslConfiguration::setDtlsCookieVerificationEnabled(bool enable)
+{
+ d->dtlsCookieEnabled = enable;
+}
+
+/*!
Returns the default SSL configuration to be used in new SSL
connections.
@@ -1030,6 +1051,41 @@ void QSslConfiguration::setDefaultConfiguration(const QSslConfiguration &configu
QSslConfigurationPrivate::setDefaultConfiguration(configuration);
}
+/*!
+ Returns the default DTLS configuration to be used in new DTLS
+ connections.
+
+ The default DTLS configuration consists of:
+
+ \list
+ \li no local certificate and no private key
+ \li protocol DtlsV1_2OrLater
+ \li the system's default CA certificate list
+ \li the cipher list equal to the list of the SSL libraries'
+ supported TLS 1.2 ciphers that use 128 or more secret bits
+ for the cipher.
+ \endlist
+
+ \sa setDefaultDtlsConfiguration()
+*/
+QSslConfiguration QSslConfiguration::defaultDtlsConfiguration()
+{
+ return QSslConfigurationPrivate::defaultDtlsConfiguration();
+}
+
+/*!
+ Sets the default DTLS configuration to be used in new DTLS
+ connections to be \a configuration. Existing connections are not
+ affected by this call.
+
+ \sa defaultDtlsConfiguration()
+*/
+void QSslConfiguration::setDefaultDtlsConfiguration(const QSslConfiguration &configuration)
+{
+ QSslConfigurationPrivate::setDefaultDtlsConfiguration(configuration);
+}
+
+
/*! \internal
*/
bool QSslConfigurationPrivate::peerSessionWasShared(const QSslConfiguration &configuration) {
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index a5561d9828..520504ff4c 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -154,9 +154,15 @@ public:
void setBackendConfigurationOption(const QByteArray &name, const QVariant &value);
void setBackendConfiguration(const QMap<QByteArray, QVariant> &backendConfig = QMap<QByteArray, QVariant>());
+ bool dtlsCookieVerificationEnabled() const;
+ void setDtlsCookieVerificationEnabled(bool enable);
+
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
+ static QSslConfiguration defaultDtlsConfiguration();
+ static void setDefaultDtlsConfiguration(const QSslConfiguration &configuration);
+
enum NextProtocolNegotiationStatus {
NextProtocolNegotiationNone,
NextProtocolNegotiationNegotiated,
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 38a98239db..f44485d51a 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -137,10 +137,15 @@ public:
QByteArray nextNegotiatedProtocol;
QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
+ bool dtlsCookieEnabled = true;
+
// in qsslsocket.cpp:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
static void deepCopyDefaultConfiguration(QSslConfigurationPrivate *config);
+
+ static QSslConfiguration defaultDtlsConfiguration();
+ static void setDefaultDtlsConfiguration(const QSslConfiguration &configuration);
};
// implemented here for inlining purposes
diff --git a/src/network/ssl/qsslcontext_openssl11.cpp b/src/network/ssl/qsslcontext_openssl11.cpp
index 5c68ed41db..0f4878c98d 100644
--- a/src/network/ssl/qsslcontext_openssl11.cpp
+++ b/src/network/ssl/qsslcontext_openssl11.cpp
@@ -139,6 +139,13 @@ init_context:
minVersion = TLS1_2_VERSION;
maxVersion = TLS_MAX_VERSION;
break;
+ case QSsl::DtlsV1_0:
+ case QSsl::DtlsV1_0OrLater:
+ case QSsl::DtlsV1_2:
+ case QSsl::DtlsV1_2OrLater:
+ sslContext->errorStr = QSslSocket::tr("unsupported protocol");
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
case QSsl::SslV2:
// This protocol is not supported by OpenSSL 1.1 and we handle
// it as an error (see the code above).
diff --git a/src/network/ssl/qsslcontext_opensslpre11.cpp b/src/network/ssl/qsslcontext_opensslpre11.cpp
index eea821804f..7994892cfc 100644
--- a/src/network/ssl/qsslcontext_opensslpre11.cpp
+++ b/src/network/ssl/qsslcontext_opensslpre11.cpp
@@ -73,6 +73,13 @@ void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mo
bool unsupportedProtocol = false;
init_context:
switch (sslContext->sslConfiguration.protocol()) {
+ case QSsl::DtlsV1_0:
+ case QSsl::DtlsV1_0OrLater:
+ case QSsl::DtlsV1_2:
+ case QSsl::DtlsV1_2OrLater:
+ sslContext->ctx = 0;
+ unsupportedProtocol = true;
+ break;
case QSsl::SslV2:
#ifndef OPENSSL_NO_SSL2
sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method());
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
index aa81b735b9..7c77f5a910 100644
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ b/src/network/ssl/qsslkey_openssl.cpp
@@ -125,10 +125,10 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
return false;
}
-void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
+void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
{
QMap<QByteArray, QByteArray> headers;
- decodePem(pemFromDer(der, headers), QByteArray(), deepClear);
+ decodePem(pemFromDer(der, headers), passPhrase, deepClear);
}
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index e66ec953a0..2957633348 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -61,6 +61,7 @@
#endif
#include "qsslsocket.h"
#include "qsslsocket_p.h"
+#include "qasn1element_p.h"
#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h>
@@ -120,6 +121,13 @@ QByteArray QSslKeyPrivate::pemHeader() const
return QByteArray();
}
+static QByteArray pkcs8Header(bool encrypted)
+{
+ return encrypted
+ ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
+ : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+}
+
/*!
\internal
*/
@@ -138,6 +146,13 @@ QByteArray QSslKeyPrivate::pemFooter() const
return QByteArray();
}
+static QByteArray pkcs8Footer(bool encrypted)
+{
+ return encrypted
+ ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
+ : QByteArrayLiteral("-----END PRIVATE KEY-----");
+}
+
/*!
\internal
@@ -166,8 +181,14 @@ QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArr
} while (it != headers.constBegin());
extra += '\n';
}
- pem.prepend(pemHeader() + '\n' + extra);
- pem.append(pemFooter() + '\n');
+
+ if (isEncryptedPkcs8(der)) {
+ pem.prepend(pkcs8Header(true) + '\n' + extra);
+ pem.append(pkcs8Footer(true) + '\n');
+ } else {
+ pem.prepend(pemHeader() + '\n' + extra);
+ pem.append(pemFooter() + '\n');
+ }
return pem;
}
@@ -179,13 +200,27 @@ QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArr
*/
QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
{
- const QByteArray header = pemHeader();
- const QByteArray footer = pemFooter();
+ QByteArray header = pemHeader();
+ QByteArray footer = pemFooter();
QByteArray der(pem);
- const int headerIndex = der.indexOf(header);
- const int footerIndex = der.indexOf(footer);
+ int headerIndex = der.indexOf(header);
+ int footerIndex = der.indexOf(footer, headerIndex + header.length());
+ if (type != QSsl::PublicKey) {
+ if (headerIndex == -1 || footerIndex == -1) {
+ header = pkcs8Header(true);
+ footer = pkcs8Footer(true);
+ headerIndex = der.indexOf(header);
+ footerIndex = der.indexOf(footer, headerIndex + header.length());
+ }
+ if (headerIndex == -1 || footerIndex == -1) {
+ header = pkcs8Header(false);
+ footer = pkcs8Footer(false);
+ headerIndex = der.indexOf(header);
+ footerIndex = der.indexOf(footer, headerIndex + header.length());
+ }
+ }
if (headerIndex == -1 || footerIndex == -1)
return QByteArray();
@@ -225,13 +260,47 @@ QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QB
return QByteArray::fromBase64(der); // ignores newlines
}
+bool QSslKeyPrivate::isEncryptedPkcs8(const QByteArray &der) const
+{
+ static const QVector<QByteArray> pbes1OIds {
+ // PKCS5
+ {PKCS5_MD2_DES_CBC_OID},
+ {PKCS5_MD2_RC2_CBC_OID},
+ {PKCS5_MD5_DES_CBC_OID},
+ {PKCS5_MD5_RC2_CBC_OID},
+ {PKCS5_SHA1_DES_CBC_OID},
+ {PKCS5_SHA1_RC2_CBC_OID},
+ };
+ QAsn1Element elem;
+ if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ const QVector<QAsn1Element> items = elem.toVector();
+ if (items.size() != 2
+ || items[0].type() != QAsn1Element::SequenceType
+ || items[1].type() != QAsn1Element::OctetStringType) {
+ return false;
+ }
+
+ const QVector<QAsn1Element> encryptionSchemeContainer = items[0].toVector();
+ if (encryptionSchemeContainer.size() != 2
+ || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
+ || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
+ return false;
+ }
+
+ const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
+ return encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID
+ || pbes1OIds.contains(encryptionScheme)
+ || encryptionScheme.startsWith(PKCS12_OID);
+}
+
/*!
Constructs a QSslKey by decoding the string in the byte array
\a encoded using a specified \a algorithm and \a encoding format.
\a type specifies whether the key is public or private.
- If the key is encoded as PEM and encrypted, \a passPhrase is used
- to decrypt it.
+ If the key is encrypted then \a passPhrase is used to decrypt it.
After construction, use isNull() to check if \a encoded contained
a valid key.
@@ -243,7 +312,7 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
d->type = type;
d->algorithm = algorithm;
if (encoding == QSsl::Der)
- d->decodeDer(encoded);
+ d->decodeDer(encoded, passPhrase);
else
d->decodePem(encoded, passPhrase);
}
@@ -253,8 +322,7 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
\a device using a specified \a algorithm and \a encoding format.
\a type specifies whether the key is public or private.
- If the key is encoded as PEM and encrypted, \a passPhrase is used
- to decrypt it.
+ If the key is encrypted then \a passPhrase is used to decrypt it.
After construction, use isNull() to check if \a device provided
a valid key.
@@ -269,7 +337,7 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
d->type = type;
d->algorithm = algorithm;
if (encoding == QSsl::Der)
- d->decodeDer(encoded);
+ d->decodeDer(encoded, passPhrase);
else
d->decodePem(encoded, passPhrase);
}
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index c93941c198..d6c5af9d47 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -81,9 +81,8 @@ public:
#ifndef QT_NO_OPENSSL
bool fromEVP_PKEY(EVP_PKEY *pkey);
#endif
- void decodeDer(const QByteArray &der, bool deepClear = true);
- void decodePem(const QByteArray &pem, const QByteArray &passPhrase,
- bool deepClear = true);
+ void decodeDer(const QByteArray &der, const QByteArray &passPhrase = {}, bool deepClear = true);
+ void decodePem(const QByteArray &pem, const QByteArray &passPhrase, bool deepClear = true);
QByteArray pemHeader() const;
QByteArray pemFooter() const;
QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const;
@@ -93,6 +92,8 @@ public:
QByteArray toPem(const QByteArray &passPhrase) const;
Qt::HANDLE handle() const;
+ bool isEncryptedPkcs8(const QByteArray &der) const;
+
bool isNull;
QSsl::KeyType type;
QSsl::KeyAlgorithm algorithm;
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
index a85fed21ed..0e7702bbeb 100644
--- a/src/network/ssl/qsslkey_qt.cpp
+++ b/src/network/ssl/qsslkey_qt.cpp
@@ -154,8 +154,9 @@ void QSslKeyPrivate::clear(bool deep)
keyLength = -1;
}
-void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
+void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
{
+ Q_UNUSED(passPhrase);
clear(deepClear);
if (der.isEmpty())
@@ -272,7 +273,7 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra
const QByteArray key = deriveKey(cipher, passPhrase, iv);
data = decrypt(cipher, data, key, iv);
}
- decodeDer(data, deepClear);
+ decodeDer(data, passPhrase, deepClear);
}
int QSslKeyPrivate::length() const
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 4273904c12..2a415ace44 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -336,12 +336,18 @@ QT_BEGIN_NAMESPACE
class QSslSocketGlobalData
{
public:
- QSslSocketGlobalData() : config(new QSslConfigurationPrivate) {}
+ QSslSocketGlobalData()
+ : config(new QSslConfigurationPrivate),
+ dtlsConfig(new QSslConfigurationPrivate)
+ {
+ dtlsConfig->protocol = QSsl::DtlsV1_2OrLater;
+ }
QMutex mutex;
QList<QSslCipher> supportedCiphers;
QVector<QSslEllipticCurve> supportedEllipticCurves;
QExplicitlySharedDataPointer<QSslConfigurationPrivate> config;
+ QExplicitlySharedDataPointer<QSslConfigurationPrivate> dtlsConfig;
};
Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
@@ -2128,6 +2134,26 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
/*!
\internal
*/
+void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
+{
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->ciphers = ciphers;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCipher> q_getDefaultDtlsCiphers()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->dtlsConfig->ciphers;
+}
+
+/*!
+ \internal
+*/
QVector<QSslEllipticCurve> QSslSocketPrivate::supportedEllipticCurves()
{
QSslSocketPrivate::ensureInitialized();
@@ -2142,6 +2168,7 @@ void QSslSocketPrivate::setDefaultSupportedEllipticCurves(const QVector<QSslElli
{
const QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
+ globalData()->dtlsConfig.detach();
globalData()->supportedEllipticCurves = curves;
}
@@ -2164,6 +2191,8 @@ void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &c
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates = certs;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates = certs;
// when the certificates are set explicitly, we do not want to
// load the system certificates on demand
s_loadRootCertsOnDemand = false;
@@ -2183,6 +2212,8 @@ bool QSslSocketPrivate::addDefaultCaCertificates(const QString &path, QSsl::Enco
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates += certs;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates += certs;
return true;
}
@@ -2195,6 +2226,8 @@ void QSslSocketPrivate::addDefaultCaCertificate(const QSslCertificate &cert)
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates += cert;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates += cert;
}
/*!
@@ -2206,6 +2239,8 @@ void QSslSocketPrivate::addDefaultCaCertificates(const QList<QSslCertificate> &c
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates += certs;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates += certs;
}
/*!
@@ -2263,6 +2298,30 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
/*!
\internal
*/
+QSslConfiguration QSslConfigurationPrivate::defaultDtlsConfiguration()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+
+ return QSslConfiguration(globalData()->dtlsConfig.data());
+}
+
+/*!
+ \internal
+*/
+void QSslConfigurationPrivate::setDefaultDtlsConfiguration(const QSslConfiguration &configuration)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ if (globalData()->dtlsConfig == configuration.d)
+ return; // nothing to do
+
+ globalData()->dtlsConfig = const_cast<QSslConfigurationPrivate*>(configuration.d.constData());
+}
+
+/*!
+ \internal
+*/
void QSslSocketPrivate::createPlainSocket(QIODevice::OpenMode openMode)
{
Q_Q(QSslSocket);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 1fc7817fe8..3858b4b21f 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -66,6 +66,10 @@
#include "qsslpresharedkeyauthenticator.h"
#include "qsslpresharedkeyauthenticator_p.h"
+#ifdef Q_OS_WIN
+#include "qwindowscarootfetcher_p.h"
+#endif
+
#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
@@ -99,12 +103,13 @@ int QSslSocketBackendPrivate::s_indexForSSLExtraData = -1;
QString QSslSocketBackendPrivate::getErrorsFromOpenSsl()
{
QString errorString;
+ char buf[256] = {}; // OpenSSL docs claim both 120 and 256; use the larger.
unsigned long errNum;
while ((errNum = q_ERR_get_error())) {
- if (! errorString.isEmpty())
+ if (!errorString.isEmpty())
errorString.append(QLatin1String(", "));
- const char *error = q_ERR_error_string(errNum, NULL);
- errorString.append(QString::fromLatin1(error)); // error is ascii according to man ERR_error_string
+ q_ERR_error_string_n(errNum, buf, sizeof buf);
+ errorString.append(QString::fromLatin1(buf)); // error is ascii according to man ERR_error_string
}
return errorString;
}
@@ -188,8 +193,7 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER
return ciph;
}
-// static
-inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
+QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
{
return {
q_X509_STORE_CTX_get_error(ctx),
@@ -242,6 +246,33 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx)
return 1;
}
+static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphers,
+ QList<QSslCipher> &defaultCiphers)
+{
+ Q_ASSERT(connection);
+
+ STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
+ for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
+ if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
+ QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);
+ if (!ciph.isNull()) {
+ // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
+ if (!ciph.name().toLower().startsWith(QLatin1String("adh")) &&
+ !ciph.name().toLower().startsWith(QLatin1String("exp-adh")) &&
+ !ciph.name().toLower().startsWith(QLatin1String("aecdh"))) {
+ ciphers << ciph;
+
+ if (ciph.usedBits() >= 128)
+ defaultCiphers << ciph;
+ }
+ }
+ }
+ }
+}
+
+// Defined in qsslsocket.cpp
+void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
+
long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
{
long options;
@@ -447,29 +478,27 @@ void QSslSocketPrivate::resetDefaultCiphers()
QList<QSslCipher> ciphers;
QList<QSslCipher> defaultCiphers;
- STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(mySsl);
- for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
- if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
- QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);
- if (!ciph.isNull()) {
- // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
- if (!ciph.name().toLower().startsWith(QLatin1String("adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("exp-adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("aecdh"))) {
- ciphers << ciph;
-
- if (ciph.usedBits() >= 128)
- defaultCiphers << ciph;
- }
- }
- }
- }
+ q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
q_SSL_CTX_free(myCtx);
q_SSL_free(mySsl);
setDefaultSupportedCiphers(ciphers);
setDefaultCiphers(defaultCiphers);
+
+ ciphers.clear();
+ defaultCiphers.clear();
+
+ myCtx = q_SSL_CTX_new(q_DTLS_client_method());
+ if (myCtx) {
+ mySsl = q_SSL_new(myCtx);
+ if (mySsl) {
+ q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
+ q_setDefaultDtlsCiphers(defaultCiphers);
+ q_SSL_free(mySsl);
+ }
+ q_SSL_CTX_free(myCtx);
+ }
}
void QSslSocketPrivate::resetDefaultEllipticCurves()
@@ -1172,119 +1201,6 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi
}
}
-class QWindowsCaRootFetcherThread : public QThread
-{
-public:
- QWindowsCaRootFetcherThread()
- {
- qRegisterMetaType<QSslCertificate>();
- setObjectName(QStringLiteral("QWindowsCaRootFetcher"));
- start();
- }
- ~QWindowsCaRootFetcherThread()
- {
- quit();
- wait(15500); // worst case, a running request can block for 15 seconds
- }
-};
-
-Q_GLOBAL_STATIC(QWindowsCaRootFetcherThread, windowsCaRootFetcherThread);
-
-QWindowsCaRootFetcher::QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode)
- : cert(certificate), mode(sslMode)
-{
- moveToThread(windowsCaRootFetcherThread());
-}
-
-QWindowsCaRootFetcher::~QWindowsCaRootFetcher()
-{
-}
-
-void QWindowsCaRootFetcher::start()
-{
- QByteArray der = cert.toDer();
- PCCERT_CONTEXT wincert = CertCreateCertificateContext(X509_ASN_ENCODING, (const BYTE *)der.constData(), der.length());
- if (!wincert) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "QWindowsCaRootFetcher failed to convert certificate to windows form");
-#endif
- emit finished(cert, QSslCertificate());
- deleteLater();
- return;
- }
-
- CERT_CHAIN_PARA parameters;
- memset(&parameters, 0, sizeof(parameters));
- parameters.cbSize = sizeof(parameters);
- // set key usage constraint
- parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
- parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
- LPSTR oid = (LPSTR)(mode == QSslSocket::SslClientMode ? szOID_PKIX_KP_SERVER_AUTH : szOID_PKIX_KP_CLIENT_AUTH);
- parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
-
-#ifdef QSSLSOCKET_DEBUG
- QElapsedTimer stopwatch;
- stopwatch.start();
-#endif
- PCCERT_CHAIN_CONTEXT chain;
- BOOL result = CertGetCertificateChain(
- 0, //default engine
- wincert,
- 0, //current date/time
- 0, //default store
- &parameters,
- 0, //default dwFlags
- 0, //reserved
- &chain);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QWindowsCaRootFetcher" << stopwatch.elapsed() << "ms to get chain";
-#endif
-
- QSslCertificate trustedRoot;
- if (result) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QWindowsCaRootFetcher - examining windows chains";
- if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
- qCDebug(lcSsl) << " - TRUSTED";
- else
- qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
- if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
- qCDebug(lcSsl) << " - SELF SIGNED";
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::fetchCaRootForCert - dumping simple chains";
- for (unsigned int i = 0; i < chain->cChain; i++) {
- if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
- qCDebug(lcSsl) << " - TRUSTED SIMPLE CHAIN" << i;
- else
- qCDebug(lcSsl) << " - UNTRUSTED SIMPLE CHAIN" << i << "reason:" << chain->rgpChain[i]->TrustStatus.dwErrorStatus;
- for (unsigned int j = 0; j < chain->rgpChain[i]->cElement; j++) {
- QSslCertificate foundCert(QByteArray((const char *)chain->rgpChain[i]->rgpElement[j]->pCertContext->pbCertEncoded
- , chain->rgpChain[i]->rgpElement[j]->pCertContext->cbCertEncoded), QSsl::Der);
- qCDebug(lcSsl) << " - " << foundCert;
- }
- }
- qCDebug(lcSsl) << " - and" << chain->cLowerQualityChainContext << "low quality chains"; //expect 0, we haven't asked for them
-#endif
-
- //based on http://msdn.microsoft.com/en-us/library/windows/desktop/aa377182%28v=vs.85%29.aspx
- //about the final chain rgpChain[cChain-1] which must begin with a trusted root to be valid
- if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
- && chain->cChain > 0) {
- const PCERT_SIMPLE_CHAIN finalChain = chain->rgpChain[chain->cChain - 1];
- // http://msdn.microsoft.com/en-us/library/windows/desktop/aa377544%28v=vs.85%29.aspx
- // rgpElement[0] is the end certificate chain element. rgpElement[cElement-1] is the self-signed "root" certificate element.
- if (finalChain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
- && finalChain->cElement > 0) {
- trustedRoot = QSslCertificate(QByteArray((const char *)finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->pbCertEncoded
- , finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->cbCertEncoded), QSsl::Der);
- }
- }
- CertFreeCertificateChain(chain);
- }
- CertFreeCertificateContext(wincert);
-
- emit finished(cert, trustedRoot);
- deleteLater();
-}
#endif
void QSslSocketBackendPrivate::disconnectFromHost()
diff --git a/src/network/ssl/qsslsocket_openssl11_symbols_p.h b/src/network/ssl/qsslsocket_openssl11_symbols_p.h
index ac8d46ce6d..1ceddecbb7 100644
--- a/src/network/ssl/qsslsocket_openssl11_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl11_symbols_p.h
@@ -128,6 +128,45 @@ 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);
+unsigned long q_SSL_set_options(SSL *s, unsigned long op);
+
+// Functions and types required for DTLS support:
+extern "C"
+{
+
+typedef int (*CookieVerifyCallback)(SSL *, const unsigned char *, unsigned);
+typedef int (*DgramWriteCallback) (BIO *, const char *, int);
+typedef int (*DgramReadCallback) (BIO *, char *, int);
+typedef int (*DgramPutsCallback) (BIO *, const char *);
+typedef long (*DgramCtrlCallback) (BIO *, int, long, void *);
+typedef int (*DgramCreateCallback) (BIO *);
+typedef int (*DgramDestroyCallback) (BIO *);
+
+}
+
+int q_DTLSv1_listen(SSL *s, BIO_ADDR *client);
+BIO_ADDR *q_BIO_ADDR_new();
+void q_BIO_ADDR_free(BIO_ADDR *ap);
+int q_BIO_ADDR_family(const BIO_ADDR *ap);
+unsigned short q_BIO_ADDR_rawport(const BIO_ADDR *ap);
+int q_BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l);
+int q_BIO_ADDR_rawmake(BIO_ADDR *ap, int family, const void *where, size_t wherelen,
+ unsigned short port);
+
+// API we need for a custom dgram BIO:
+BIO_METHOD *q_BIO_meth_new(int type, const char *name);
+void q_BIO_meth_free(BIO_METHOD *biom);
+int q_BIO_meth_set_write(BIO_METHOD *biom, DgramWriteCallback);
+int q_BIO_meth_set_read(BIO_METHOD *biom, DgramReadCallback);
+int q_BIO_meth_set_puts(BIO_METHOD *biom, DgramPutsCallback);
+int q_BIO_meth_set_ctrl(BIO_METHOD *biom, DgramCtrlCallback);
+int q_BIO_meth_set_create(BIO_METHOD *biom, DgramCreateCallback);
+int q_BIO_meth_set_destroy(BIO_METHOD *biom, DgramDestroyCallback);
+void q_BIO_set_data(BIO *a, void *ptr);
+void *q_BIO_get_data(BIO *a);
+void q_BIO_set_init(BIO *a, int init);
+int q_BIO_get_shutdown(BIO *a);
+void q_BIO_set_shutdown(BIO *a, int shut);
#define q_SSL_CTX_set_min_proto_version(ctx, version) \
q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, nullptr)
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index 2a800cdc34..2d0a5fe895 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -161,23 +161,6 @@ public:
const QByteArray &passPhrase);
};
-#ifdef Q_OS_WIN
-class QWindowsCaRootFetcher : public QObject
-{
- Q_OBJECT;
-public:
- QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode);
- ~QWindowsCaRootFetcher();
-public slots:
- void start();
-signals:
- void finished(QSslCertificate brokenChain, QSslCertificate caroot);
-private:
- QSslCertificate cert;
- QSslSocket::SslMode mode;
-};
-#endif
-
QT_END_NAMESPACE
#endif
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 82ff5e9e3a..0c24b5caac 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -162,6 +162,7 @@ DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long
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)
+DEFINEFUNC2(unsigned long, SSL_set_options, SSL *ssl, ssl, unsigned long op, op, return 0, return)
DEFINEFUNC(const SSL_METHOD *, TLS_method, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(const SSL_METHOD *, TLS_client_method, DUMMYARG, DUMMYARG, return 0, return)
@@ -178,6 +179,26 @@ 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)
+DEFINEFUNC2(int, DTLSv1_listen, SSL *s, s, BIO_ADDR *c, c, return -1, return)
+DEFINEFUNC(BIO_ADDR *, BIO_ADDR_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, BIO_ADDR_free, BIO_ADDR *ap, ap, return, DUMMYARG)
+DEFINEFUNC(int, BIO_ADDR_family, const BIO_ADDR *ap, ap, return 0, return)
+DEFINEFUNC(unsigned short, BIO_ADDR_rawport, const BIO_ADDR *ap, ap, return 0, return)
+DEFINEFUNC3(int, BIO_ADDR_rawaddress, const BIO_ADDR *ap, ap, void *p, p, size_t *l, l, return 0, return)
+DEFINEFUNC5(int, BIO_ADDR_rawmake, BIO_ADDR *ap, ap, int family, family, const void *where, where, size_t len, len, unsigned short port, port, return 0, return)
+DEFINEFUNC2(BIO_METHOD *, BIO_meth_new, int type, type, const char *name, name, return nullptr, return)
+DEFINEFUNC(void, BIO_meth_free, BIO_METHOD *biom, biom, return, DUMMYARG)
+DEFINEFUNC2(int, BIO_meth_set_write, BIO_METHOD *biom, biom, DgramWriteCallback write, write, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_read, BIO_METHOD *biom, biom, DgramReadCallback read, read, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_puts, BIO_METHOD *biom, biom, DgramPutsCallback puts, puts, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_ctrl, BIO_METHOD *biom, biom, DgramCtrlCallback ctrl, ctrl, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_create, BIO_METHOD *biom, biom, DgramCreateCallback crt, crt, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_destroy, BIO_METHOD *biom, biom, DgramDestroyCallback dtr, dtr, return 0, return)
+DEFINEFUNC2(void, BIO_set_data, BIO *a, a, void *ptr, ptr, return, DUMMYARG)
+DEFINEFUNC(void *, BIO_get_data, BIO *a, a, return nullptr, return)
+DEFINEFUNC2(void, BIO_set_init, BIO *a, a, int init, init, return, DUMMYARG)
+DEFINEFUNC(int, BIO_get_shutdown, BIO *a, a, return -1, return)
+DEFINEFUNC2(void, BIO_set_shutdown, BIO *a, a, int shut, shut, return, DUMMYARG)
#else // QT_CONFIG(opensslv11)
@@ -313,6 +334,7 @@ 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)
+DEFINEFUNC3(void, ERR_error_string_n, unsigned long e, e, char *b, b, size_t len, len, return, DUMMYARG)
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)
@@ -377,12 +399,14 @@ DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, ret
#endif
DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
+DEFINEFUNC2(int, RAND_bytes, unsigned char *b, b, int n, n, return 0, 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(BIO *, SSL_get_rbio, const SSL *s, s, return nullptr, 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)
@@ -434,6 +458,7 @@ 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)
+DEFINEFUNC(int, SSL_get_shutdown, const SSL *ssl, ssl, return 0, 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)
@@ -491,6 +516,8 @@ DEFINEFUNC(int, X509_STORE_CTX_get_error, X509_STORE_CTX *a, a, return -1, retur
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(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC2(void *, X509_STORE_CTX_get_ex_data, X509_STORE_CTX *ctx, ctx, int idx, idx, return nullptr, return)
+DEFINEFUNC(int, SSL_get_ex_data_X509_STORE_CTX_idx, DUMMYARG, DUMMYARG, return -1, return)
DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, 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)
@@ -520,6 +547,18 @@ DEFINEFUNC3(void, SSL_get0_alpn_selected, const SSL *s, s, const unsigned char *
unsigned *len, len, return, DUMMYARG)
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ...
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+
+// DTLS:
+DEFINEFUNC2(void, SSL_CTX_set_cookie_generate_cb, SSL_CTX *ctx, ctx, CookieGenerateCallback cb, cb, return, DUMMYARG)
+DEFINEFUNC2(void, SSL_CTX_set_cookie_verify_cb, SSL_CTX *ctx, ctx, CookieVerifyCallback cb, cb, return, DUMMYARG)
+DEFINEFUNC2(BIO *, BIO_new_dgram, int fd, fd, int flag, flag, return nullptr, return)
+DEFINEFUNC(const SSL_METHOD *, DTLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const SSL_METHOD *, DTLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(void, BIO_set_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
+DEFINEFUNC2(void, BIO_clear_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
+DEFINEFUNC2(void *, BIO_get_ex_data, BIO *b, b, int idx, idx, return nullptr, return)
+DEFINEFUNC3(int, BIO_set_ex_data, BIO *b, b, int idx, idx, void *data, data, return -1, return)
+
DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
DEFINEFUNC3(DH *, d2i_DHparams, DH**a, a, const unsigned char **pp, pp, long length, length, return 0, return)
@@ -893,6 +932,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_SESSION_get_master_key)
RESOLVEFUNC(SSL_session_reused)
RESOLVEFUNC(SSL_get_session)
+ RESOLVEFUNC(SSL_set_options)
RESOLVEFUNC(CRYPTO_get_ex_new_index)
RESOLVEFUNC(TLS_method)
RESOLVEFUNC(TLS_client_method)
@@ -918,7 +958,26 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_SESSION_get_ticket_lifetime_hint)
RESOLVEFUNC(DH_bits)
RESOLVEFUNC(DSA_bits)
-
+ RESOLVEFUNC(DTLSv1_listen)
+ RESOLVEFUNC(BIO_ADDR_new)
+ RESOLVEFUNC(BIO_ADDR_free)
+ RESOLVEFUNC(BIO_ADDR_family)
+ RESOLVEFUNC(BIO_ADDR_rawport)
+ RESOLVEFUNC(BIO_ADDR_rawaddress)
+ RESOLVEFUNC(BIO_ADDR_rawmake)
+ RESOLVEFUNC(BIO_meth_new)
+ RESOLVEFUNC(BIO_meth_free)
+ RESOLVEFUNC(BIO_meth_set_write)
+ RESOLVEFUNC(BIO_meth_set_read)
+ RESOLVEFUNC(BIO_meth_set_puts)
+ RESOLVEFUNC(BIO_meth_set_ctrl)
+ RESOLVEFUNC(BIO_meth_set_create)
+ RESOLVEFUNC(BIO_meth_set_destroy)
+ RESOLVEFUNC(BIO_set_data)
+ RESOLVEFUNC(BIO_get_data)
+ RESOLVEFUNC(BIO_set_init)
+ RESOLVEFUNC(BIO_get_shutdown)
+ RESOLVEFUNC(BIO_set_shutdown)
#else // !opensslv11
RESOLVEFUNC(ASN1_STRING_data)
@@ -1018,9 +1077,15 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(BIO_free)
RESOLVEFUNC(BIO_new)
RESOLVEFUNC(BIO_new_mem_buf)
+ RESOLVEFUNC(BIO_new_dgram)
RESOLVEFUNC(BIO_read)
RESOLVEFUNC(BIO_s_mem)
RESOLVEFUNC(BIO_write)
+ RESOLVEFUNC(BIO_set_flags)
+ RESOLVEFUNC(BIO_clear_flags)
+ RESOLVEFUNC(BIO_set_ex_data)
+ RESOLVEFUNC(BIO_get_ex_data)
+
#ifndef OPENSSL_NO_EC
RESOLVEFUNC(EC_KEY_get0_group)
RESOLVEFUNC(EC_GROUP_get_degree)
@@ -1033,6 +1098,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(DSA_new)
RESOLVEFUNC(DSA_free)
RESOLVEFUNC(ERR_error_string)
+ RESOLVEFUNC(ERR_error_string_n)
RESOLVEFUNC(ERR_get_error)
RESOLVEFUNC(EVP_CIPHER_CTX_new)
RESOLVEFUNC(EVP_CIPHER_CTX_free)
@@ -1096,10 +1162,12 @@ bool q_resolveOpenSslSymbols()
#endif
RESOLVEFUNC(RAND_seed)
RESOLVEFUNC(RAND_status)
+ RESOLVEFUNC(RAND_bytes)
RESOLVEFUNC(RSA_new)
RESOLVEFUNC(RSA_free)
RESOLVEFUNC(SSL_CIPHER_description)
RESOLVEFUNC(SSL_CIPHER_get_bits)
+ RESOLVEFUNC(SSL_get_rbio)
RESOLVEFUNC(SSL_CTX_check_private_key)
RESOLVEFUNC(SSL_CTX_ctrl)
RESOLVEFUNC(SSL_CTX_free)
@@ -1140,6 +1208,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_set_bio)
RESOLVEFUNC(SSL_set_connect_state)
RESOLVEFUNC(SSL_shutdown)
+ RESOLVEFUNC(SSL_get_shutdown)
RESOLVEFUNC(SSL_set_session)
RESOLVEFUNC(SSL_SESSION_free)
RESOLVEFUNC(SSL_get1_session)
@@ -1147,6 +1216,7 @@ bool q_resolveOpenSslSymbols()
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
RESOLVEFUNC(SSL_set_ex_data)
RESOLVEFUNC(SSL_get_ex_data)
+ RESOLVEFUNC(SSL_get_ex_data_X509_STORE_CTX_idx)
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
RESOLVEFUNC(SSL_set_psk_client_callback)
@@ -1170,6 +1240,8 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(X509_STORE_CTX_get_error_depth)
RESOLVEFUNC(X509_STORE_CTX_get_current_cert)
RESOLVEFUNC(X509_cmp)
+ RESOLVEFUNC(X509_STORE_CTX_get_ex_data)
+
#ifndef SSLEAY_MACROS
RESOLVEFUNC(X509_dup)
#endif
@@ -1208,6 +1280,10 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_CTX_set_alpn_select_cb)
RESOLVEFUNC(SSL_get0_alpn_selected)
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ...
+ RESOLVEFUNC(SSL_CTX_set_cookie_generate_cb)
+ RESOLVEFUNC(SSL_CTX_set_cookie_verify_cb)
+ RESOLVEFUNC(DTLS_server_method)
+ RESOLVEFUNC(DTLS_client_method)
RESOLVEFUNC(DH_new)
RESOLVEFUNC(DH_free)
RESOLVEFUNC(d2i_DHparams)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index 4fb8f26cf6..65823e3f3e 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -257,6 +257,7 @@ 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);
+void q_ERR_error_string_n(unsigned long e, char *buf, size_t len);
unsigned long q_ERR_get_error();
EVP_CIPHER_CTX *q_EVP_CIPHER_CTX_new();
void q_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
@@ -327,12 +328,14 @@ int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
#endif
void q_RAND_seed(const void *a, int b);
int q_RAND_status();
+int q_RAND_bytes(unsigned char *b, int n);
RSA *q_RSA_new();
void q_RSA_free(RSA *a);
int q_SSL_accept(SSL *a);
int q_SSL_clear(SSL *a);
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);
+BIO *q_SSL_get_rbio(const SSL *s);
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);
@@ -379,6 +382,7 @@ void q_SSL_set_bio(SSL *a, BIO *b, BIO *c);
void q_SSL_set_accept_state(SSL *a);
void q_SSL_set_connect_state(SSL *a);
int q_SSL_shutdown(SSL *a);
+int q_SSL_get_shutdown(const SSL *ssl);
int q_SSL_set_session(SSL *to, SSL_SESSION *session);
void q_SSL_SESSION_free(SSL_SESSION *ses);
SSL_SESSION *q_SSL_get1_session(SSL *ssl);
@@ -477,6 +481,7 @@ 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)
+#define q_BIO_dgram_get_peer(b, peer) (int)q_BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)peer)
#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
#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))
@@ -525,6 +530,36 @@ void q_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
#endif
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+extern "C"
+{
+typedef int (*CookieGenerateCallback)(SSL *, unsigned char *, unsigned *);
+}
+
+void q_SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, CookieGenerateCallback cb);
+void q_SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, CookieVerifyCallback cb);
+BIO *q_BIO_new_dgram(int fd, int close_flag);
+const SSL_METHOD *q_DTLS_server_method();
+const SSL_METHOD *q_DTLS_client_method();
+
+void *q_X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx);
+int q_SSL_get_ex_data_X509_STORE_CTX_idx();
+
+#define q_DTLS_get_link_min_mtu(ssl) q_SSL_ctrl((ssl), DTLS_CTRL_GET_LINK_MIN_MTU, 0, nullptr)
+#define q_DTLS_set_link_mtu(ssl, mtu) q_SSL_ctrl((ssl), DTLS_CTRL_SET_LINK_MTU, (mtu), nullptr)
+#define q_DTLSv1_get_timeout(ssl, arg) q_SSL_ctrl(ssl, DTLS_CTRL_GET_TIMEOUT, 0, arg)
+#define q_DTLSv1_handle_timeout(ssl) q_SSL_ctrl(ssl, DTLS_CTRL_HANDLE_TIMEOUT, 0, nullptr)
+
+void q_BIO_set_flags(BIO *b, int flags);
+void q_BIO_clear_flags(BIO *b, int flags);
+void *q_BIO_get_ex_data(BIO *b, int idx);
+int q_BIO_set_ex_data(BIO *b, int idx, void *data);
+
+#define q_BIO_set_retry_read(b) q_BIO_set_flags(b, (BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_set_retry_write(b) q_BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_clear_retry_flags(b) q_BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_set_app_data(s,arg) q_BIO_set_ex_data(s,0,arg)
+#define q_BIO_get_app_data(s) q_BIO_get_ex_data(s,0)
+
// Helper function
class QDateTime;
QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime);
diff --git a/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h
index 9686d22b98..6676f768a7 100644
--- a/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h
+++ b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h
@@ -204,6 +204,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#endif // SSLEAY_MACROS
#define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
+#define q_SSL_set_options(ssl,op) q_SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),nullptr)
#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)
@@ -226,5 +227,11 @@ void q_OPENSSL_add_all_algorithms_conf();
long q_SSLeay();
const char *q_SSLeay_version(int type);
+// DTLS:
+extern "C"
+{
+typedef int (*CookieVerifyCallback)(SSL *, unsigned char *, unsigned);
+}
+#define q_DTLSv1_listen(ssl, peer) q_SSL_ctrl(ssl, DTLS_CTRL_LISTEN, 0, (void *)peer)
#endif // QSSLSOCKET_OPENSSL_PRE11_SYMBOLS_P_H
diff --git a/src/network/ssl/qwindowscarootfetcher.cpp b/src/network/ssl/qwindowscarootfetcher.cpp
new file mode 100644
index 0000000000..12dc650500
--- /dev/null
+++ b/src/network/ssl/qwindowscarootfetcher.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "qwindowscarootfetcher_p.h"
+
+#include <QtCore/QThread>
+#include <QtGlobal>
+
+#include "qsslsocket_p.h" // Transitively includes Wincrypt.h
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsCaRootFetcherThread : public QThread
+{
+public:
+ QWindowsCaRootFetcherThread()
+ {
+ qRegisterMetaType<QSslCertificate>();
+ setObjectName(QStringLiteral("QWindowsCaRootFetcher"));
+ start();
+ }
+ ~QWindowsCaRootFetcherThread()
+ {
+ quit();
+ wait(15500); // worst case, a running request can block for 15 seconds
+ }
+};
+
+Q_GLOBAL_STATIC(QWindowsCaRootFetcherThread, windowsCaRootFetcherThread);
+
+QWindowsCaRootFetcher::QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode)
+ : cert(certificate), mode(sslMode)
+{
+ moveToThread(windowsCaRootFetcherThread());
+}
+
+QWindowsCaRootFetcher::~QWindowsCaRootFetcher()
+{
+}
+
+void QWindowsCaRootFetcher::start()
+{
+ QByteArray der = cert.toDer();
+ PCCERT_CONTEXT wincert = CertCreateCertificateContext(X509_ASN_ENCODING, (const BYTE *)der.constData(), der.length());
+ if (!wincert) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl, "QWindowsCaRootFetcher failed to convert certificate to windows form");
+#endif
+ emit finished(cert, QSslCertificate());
+ deleteLater();
+ return;
+ }
+
+ CERT_CHAIN_PARA parameters;
+ memset(&parameters, 0, sizeof(parameters));
+ parameters.cbSize = sizeof(parameters);
+ // set key usage constraint
+ parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
+ parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
+ LPSTR oid = (LPSTR)(mode == QSslSocket::SslClientMode ? szOID_PKIX_KP_SERVER_AUTH : szOID_PKIX_KP_CLIENT_AUTH);
+ parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
+
+#ifdef QSSLSOCKET_DEBUG
+ QElapsedTimer stopwatch;
+ stopwatch.start();
+#endif
+ PCCERT_CHAIN_CONTEXT chain;
+ BOOL result = CertGetCertificateChain(
+ 0, //default engine
+ wincert,
+ 0, //current date/time
+ 0, //default store
+ &parameters,
+ 0, //default dwFlags
+ 0, //reserved
+ &chain);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << "QWindowsCaRootFetcher" << stopwatch.elapsed() << "ms to get chain";
+#endif
+
+ QSslCertificate trustedRoot;
+ if (result) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << "QWindowsCaRootFetcher - examining windows chains";
+ if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
+ qCDebug(lcSsl) << " - TRUSTED";
+ else
+ qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
+ if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
+ qCDebug(lcSsl) << " - SELF SIGNED";
+ qCDebug(lcSsl) << "QSslSocketBackendPrivate::fetchCaRootForCert - dumping simple chains";
+ for (unsigned int i = 0; i < chain->cChain; i++) {
+ if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
+ qCDebug(lcSsl) << " - TRUSTED SIMPLE CHAIN" << i;
+ else
+ qCDebug(lcSsl) << " - UNTRUSTED SIMPLE CHAIN" << i << "reason:" << chain->rgpChain[i]->TrustStatus.dwErrorStatus;
+ for (unsigned int j = 0; j < chain->rgpChain[i]->cElement; j++) {
+ QSslCertificate foundCert(QByteArray((const char *)chain->rgpChain[i]->rgpElement[j]->pCertContext->pbCertEncoded
+ , chain->rgpChain[i]->rgpElement[j]->pCertContext->cbCertEncoded), QSsl::Der);
+ qCDebug(lcSsl) << " - " << foundCert;
+ }
+ }
+ qCDebug(lcSsl) << " - and" << chain->cLowerQualityChainContext << "low quality chains"; //expect 0, we haven't asked for them
+#endif
+
+ //based on http://msdn.microsoft.com/en-us/library/windows/desktop/aa377182%28v=vs.85%29.aspx
+ //about the final chain rgpChain[cChain-1] which must begin with a trusted root to be valid
+ if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
+ && chain->cChain > 0) {
+ const PCERT_SIMPLE_CHAIN finalChain = chain->rgpChain[chain->cChain - 1];
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa377544%28v=vs.85%29.aspx
+ // rgpElement[0] is the end certificate chain element. rgpElement[cElement-1] is the self-signed "root" certificate element.
+ if (finalChain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
+ && finalChain->cElement > 0) {
+ trustedRoot = QSslCertificate(QByteArray((const char *)finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->pbCertEncoded
+ , finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->cbCertEncoded), QSsl::Der);
+ }
+ }
+ CertFreeCertificateChain(chain);
+ }
+ CertFreeCertificateContext(wincert);
+
+ emit finished(cert, trustedRoot);
+ deleteLater();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qwindowscarootfetcher_p.h b/src/network/ssl/qwindowscarootfetcher_p.h
new file mode 100644
index 0000000000..181c309388
--- /dev/null
+++ b/src/network/ssl/qwindowscarootfetcher_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSCAROOTFETCHER_P_H
+#define QWINDOWSCAROOTFETCHER_P_H
+
+#include <QtCore/QtGlobal>
+#include <QtCore/QObject>
+
+#include "qsslsocket.h"
+#include "qsslcertificate.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsCaRootFetcher : public QObject
+{
+ Q_OBJECT;
+public:
+ QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode);
+ ~QWindowsCaRootFetcher();
+public slots:
+ void start();
+signals:
+ void finished(QSslCertificate brokenChain, QSslCertificate caroot);
+private:
+ QSslCertificate cert;
+ QSslSocket::SslMode mode;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSCAROOTFETCHER_P_H
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index 2783effaf1..b8cbe83089 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -95,6 +95,10 @@ qtConfig(ssl) {
QMAKE_USE_FOR_PRIVATE += openssl
else: \
QMAKE_USE_FOR_PRIVATE += openssl/nolink
- win32: LIBS_PRIVATE += -lcrypt32
+ win32 {
+ LIBS_PRIVATE += -lcrypt32
+ HEADERS += ssl/qwindowscarootfetcher_p.h
+ SOURCES += ssl/qwindowscarootfetcher.cpp
+ }
}
}