262 lines
11 KiB
Diff
262 lines
11 KiB
Diff
From b0404383ab573d7550a6564405bb9b1316ff193a Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Sebastian=20L=C3=B6sch?= <Sebastian.Loesch@governikus.de>
|
|
Date: Thu, 21 Apr 2016 09:19:19 +0200
|
|
Subject: [PATCH] Make server side signature algorithms configurable
|
|
|
|
Signature algorithms are used during the TLS handshake phase to protect
|
|
transferred security parameters, e.g the message ServerKeyExchange.
|
|
This patch enables the configuration of allowed algorithms used by the
|
|
server side.
|
|
|
|
Change-Id: Ia178efd4778b91863fcc919bf50219115b300d77
|
|
---
|
|
src/network/ssl/qsslconfiguration.cpp | 42 ++++++++++++++++++++++++
|
|
src/network/ssl/qsslconfiguration.h | 8 ++++-
|
|
src/network/ssl/qsslconfiguration_p.h | 5 +++
|
|
src/network/ssl/qsslcontext_openssl.cpp | 45 ++++++++++++++++++++++++++
|
|
src/network/ssl/qsslcontext_openssl_p.h | 1 +
|
|
src/network/ssl/qsslsocket.cpp | 2 ++
|
|
src/network/ssl/qsslsocket_openssl_symbols_p.h | 5 +++
|
|
7 files changed, 107 insertions(+), 1 deletion(-)
|
|
|
|
diff --git x/qtbase/src/network/ssl/qsslconfiguration.cpp y/qtbase/src/network/ssl/qsslconfiguration.cpp
|
|
index 75a880f115..37f99feef1 100644
|
|
--- x/qtbase/src/network/ssl/qsslconfiguration.cpp
|
|
+++ y/qtbase/src/network/ssl/qsslconfiguration.cpp
|
|
@@ -221,6 +221,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
|
|
d->peerVerifyMode == other.d->peerVerifyMode &&
|
|
d->peerVerifyDepth == other.d->peerVerifyDepth &&
|
|
d->allowRootCertOnDemandLoading == other.d->allowRootCertOnDemandLoading &&
|
|
+ d->signatureAndHashAlgorithms == other.d->signatureAndHashAlgorithms &&
|
|
d->sslOptions == other.d->sslOptions &&
|
|
d->sslSession == other.d->sslSession &&
|
|
d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint &&
|
|
@@ -263,6 +264,7 @@ bool QSslConfiguration::isNull() const
|
|
d->privateKey.isNull() &&
|
|
d->peerCertificate.isNull() &&
|
|
d->peerCertificateChain.count() == 0 &&
|
|
+ d->signatureAndHashAlgorithms.isEmpty() &&
|
|
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
|
|
d->sslSession.isNull() &&
|
|
d->sslSessionTicketLifeTimeHint == -1 &&
|
|
@@ -869,6 +871,46 @@ void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParame
|
|
d->dhParams = dhparams;
|
|
}
|
|
|
|
+/*!
|
|
+ \since 5.9
|
|
+
|
|
+ Returns the connection's current list of supported signature
|
|
+ algorithms if enabled. Enable it by calling
|
|
+ setSignatureAndHashAlgorithms().
|
|
+
|
|
+ \sa setSignatureAndHashAlgorithms()
|
|
+ */
|
|
+QVector<QPair<QSsl::KeyAlgorithm, QCryptographicHash::Algorithm> > QSslConfiguration::signatureAndHashAlgorithms() const
|
|
+{
|
|
+ return d->signatureAndHashAlgorithms;
|
|
+}
|
|
+
|
|
+/*!
|
|
+ \since 5.9
|
|
+
|
|
+ Sets the list of signature algorithms to be used for the current
|
|
+ connection. The algorithms are expected to be ordered by descending
|
|
+ preference (i.e., the first algorithm is the most preferred one).
|
|
+ Notice that this restricts the list of supported ciphers (e.g.
|
|
+ configuring the signature algorithm RSA+SHA1 will restrict the ciphers
|
|
+ to RSA ciphers).
|
|
+
|
|
+ When configuring the client side this are the algorithms set in the
|
|
+ Signature Algorithms TLS extension, see RFC 5246 for details. Although
|
|
+ this extension will be ignored for TLS protocol versions prior 1.2
|
|
+ this still restricts the supported ciphers as mentioned above.
|
|
+
|
|
+ By default, the handshake phase can choose any of the algorithms
|
|
+ supported by this system's SSL libraries, which may vary from
|
|
+ system to system.
|
|
+
|
|
+ \sa signatureAndHashAlgorithms()
|
|
+ */
|
|
+void QSslConfiguration::setSignatureAndHashAlgorithms(const QVector<QPair<QSsl::KeyAlgorithm, QCryptographicHash::Algorithm> > &algorithms)
|
|
+{
|
|
+ d->signatureAndHashAlgorithms = algorithms;
|
|
+}
|
|
+
|
|
/*!
|
|
\since 5.3
|
|
|
|
diff --git x/qtbase/src/network/ssl/qsslconfiguration.h y/qtbase/src/network/ssl/qsslconfiguration.h
|
|
index 1c57bebd65..4d3e5129d5 100644
|
|
--- x/qtbase/src/network/ssl/qsslconfiguration.h
|
|
+++ y/qtbase/src/network/ssl/qsslconfiguration.h
|
|
@@ -56,10 +56,13 @@
|
|
#ifndef QSSLCONFIGURATION_H
|
|
#define QSSLCONFIGURATION_H
|
|
|
|
-#include <QtNetwork/qtnetworkglobal.h>
|
|
+#include <QtCore/qcryptographichash.h>
|
|
+#include <QtCore/qpair.h>
|
|
#include <QtCore/qshareddata.h>
|
|
+#include <QtCore/qvector.h>
|
|
#include <QtNetwork/qsslsocket.h>
|
|
#include <QtNetwork/qssl.h>
|
|
+#include <QtNetwork/qtnetworkglobal.h>
|
|
|
|
#ifndef QT_NO_SSL
|
|
|
|
@@ -149,6 +152,9 @@ public:
|
|
QSslDiffieHellmanParameters diffieHellmanParameters() const;
|
|
void setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams);
|
|
|
|
+ QVector<QPair<QSsl::KeyAlgorithm, QCryptographicHash::Algorithm> > signatureAndHashAlgorithms() const;
|
|
+ void setSignatureAndHashAlgorithms(const QVector<QPair<QSsl::KeyAlgorithm, QCryptographicHash::Algorithm> > &algorithms);
|
|
+
|
|
static QSslConfiguration defaultConfiguration();
|
|
static void setDefaultConfiguration(const QSslConfiguration &configuration);
|
|
|
|
diff --git x/qtbase/src/network/ssl/qsslconfiguration_p.h y/qtbase/src/network/ssl/qsslconfiguration_p.h
|
|
index 6adf2c9b54..7be253973b 100644
|
|
--- x/qtbase/src/network/ssl/qsslconfiguration_p.h
|
|
+++ y/qtbase/src/network/ssl/qsslconfiguration_p.h
|
|
@@ -75,6 +75,9 @@
|
|
#include "qsslkey.h"
|
|
#include "qsslellipticcurve.h"
|
|
#include "qssldiffiehellmanparameters.h"
|
|
+#include <QtCore/qcryptographichash.h>
|
|
+#include <QtCore/qpair.h>
|
|
+#include <QtCore/qvector.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
@@ -123,6 +126,8 @@ public:
|
|
|
|
QSslDiffieHellmanParameters dhParams;
|
|
|
|
+ QVector<QPair<QSsl::KeyAlgorithm, QCryptographicHash::Algorithm> > signatureAndHashAlgorithms;
|
|
+
|
|
QByteArray sslSession;
|
|
int sslSessionTicketLifeTimeHint;
|
|
|
|
diff --git x/qtbase/src/network/ssl/qsslcontext_openssl.cpp y/qtbase/src/network/ssl/qsslcontext_openssl.cpp
|
|
index c92d8fc3f8..29df53abc0 100644
|
|
--- x/qtbase/src/network/ssl/qsslcontext_openssl.cpp
|
|
+++ y/qtbase/src/network/ssl/qsslcontext_openssl.cpp
|
|
@@ -42,6 +42,7 @@
|
|
|
|
#include <QtNetwork/qsslsocket.h>
|
|
#include <QtNetwork/qssldiffiehellmanparameters.h>
|
|
+#include <QtCore/qmetaobject.h>
|
|
#include <QtCore/qmutex.h>
|
|
|
|
#include "private/qssl_p.h"
|
|
@@ -78,6 +79,11 @@ QSslContext::~QSslContext()
|
|
q_SSL_SESSION_free(session);
|
|
}
|
|
|
|
+static inline QString msgErrorSettingSignatureAlgorithms(const QString &why)
|
|
+{
|
|
+ return QSslSocket::tr("Error when setting the signature algorithms (%1)").arg(why);
|
|
+}
|
|
+
|
|
static inline QString msgErrorSettingEllipticCurves(const QString &why)
|
|
{
|
|
return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
|
|
@@ -371,6 +377,45 @@ init_context:
|
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
|
}
|
|
}
|
|
+
|
|
+ const auto& sigAndHashAlgorithms = sslContext->sslConfiguration.signatureAndHashAlgorithms();
|
|
+ if (!sigAndHashAlgorithms.isEmpty()) {
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
+ if (q_SSLeay() >= 0x10002000L) {
|
|
+ QMetaEnum hashMetaEnum = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
|
|
+ QByteArrayList algorithmList;
|
|
+ for (int i=0; i < sigAndHashAlgorithms.size(); ++i) {
|
|
+ QByteArray sig;
|
|
+ switch (sigAndHashAlgorithms[i].first) {
|
|
+ case QSsl::KeyAlgorithm::Rsa:
|
|
+ sig = QByteArrayLiteral("RSA");
|
|
+ break;
|
|
+ case QSsl::KeyAlgorithm::Dsa:
|
|
+ sig = QByteArrayLiteral("DSA");
|
|
+ break;
|
|
+ case QSsl::KeyAlgorithm::Ec:
|
|
+ sig = QByteArrayLiteral("ECDSA");
|
|
+ break;
|
|
+ case QSsl::KeyAlgorithm::Opaque:
|
|
+ qCWarning(lcSsl, "Invalid value KeyAlgorithm::Opaque will be ignored");
|
|
+ continue;
|
|
+ }
|
|
+ QByteArray hash = QByteArray(hashMetaEnum.valueToKey(sigAndHashAlgorithms[i].second)).toUpper();
|
|
+ algorithmList += sig + QByteArrayLiteral("+") + hash;
|
|
+ }
|
|
+ QByteArray algorithms = algorithmList.join(':');
|
|
+ if (!q_SSL_CTX_set1_sigalgs_list(sslContext->ctx, algorithms.data())) {
|
|
+ sslContext->errorStr = msgErrorSettingSignatureAlgorithms(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
|
+ sslContext->errorCode = QSslError::UnspecifiedError;
|
|
+ }
|
|
+ } else
|
|
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
+ {
|
|
+ // specific algorithms requested, but not possible to set -> error
|
|
+ sslContext->errorStr = msgErrorSettingSignatureAlgorithms(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)
|
|
diff --git x/qtbase/src/network/ssl/qsslcontext_openssl_p.h y/qtbase/src/network/ssl/qsslcontext_openssl_p.h
|
|
index 06a31af5e5..c8c8e1941b 100644
|
|
--- x/qtbase/src/network/ssl/qsslcontext_openssl_p.h
|
|
+++ y/qtbase/src/network/ssl/qsslcontext_openssl_p.h
|
|
@@ -54,6 +54,7 @@
|
|
//
|
|
|
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
|
+#include <QtCore/qobjectdefs.h>
|
|
#include <QtCore/qvariant.h>
|
|
#include <QtNetwork/qsslcertificate.h>
|
|
#include <QtNetwork/qsslconfiguration.h>
|
|
diff --git x/qtbase/src/network/ssl/qsslsocket.cpp y/qtbase/src/network/ssl/qsslsocket.cpp
|
|
index 8eba5db9fe..c0aa8b9bdf 100644
|
|
--- x/qtbase/src/network/ssl/qsslsocket.cpp
|
|
+++ y/qtbase/src/network/ssl/qsslsocket.cpp
|
|
@@ -922,6 +922,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
|
|
d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
|
|
d->configuration.peerVerifyMode = configuration.peerVerifyMode();
|
|
d->configuration.protocol = configuration.protocol();
|
|
+ d->configuration.signatureAndHashAlgorithms = configuration.signatureAndHashAlgorithms();
|
|
d->configuration.sslOptions = configuration.d->sslOptions;
|
|
d->configuration.sslSession = configuration.sessionTicket();
|
|
d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
|
|
@@ -2249,6 +2250,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
|
|
ptr->peerVerifyDepth = global->peerVerifyDepth;
|
|
ptr->sslOptions = global->sslOptions;
|
|
ptr->ellipticCurves = global->ellipticCurves;
|
|
+ ptr->signatureAndHashAlgorithms = global->signatureAndHashAlgorithms;
|
|
}
|
|
|
|
/*!
|
|
diff --git x/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h y/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h
|
|
index b35a895d38..d4cd493c45 100644
|
|
--- x/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h
|
|
+++ y/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h
|
|
@@ -517,6 +517,11 @@ int q_EC_curve_nist2nid(const char *name);
|
|
#define q_SSL_get_server_tmp_key(ssl, key) q_SSL_ctrl((ssl), SSL_CTRL_GET_SERVER_TMP_KEY, 0, (char *)key)
|
|
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
|
+// Signature algorithm extension
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
+#define q_SSL_CTX_set1_sigalgs_list(ctx, s) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_SIGALGS_LIST, 0, (char *)s)
|
|
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
+
|
|
// PKCS#12 support
|
|
int q_PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca);
|
|
PKCS12 *q_d2i_PKCS12_bio(BIO *bio, PKCS12 **pkcs12);
|
|
--
|
|
2.15.0
|
|
|