summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/ssl/qsslconfiguration.cpp46
-rw-r--r--src/network/ssl/qsslconfiguration.h5
-rw-r--r--src/network/ssl/qsslconfiguration_p.h3
-rw-r--r--src/network/ssl/qsslcontext_openssl.cpp25
-rw-r--r--src/network/ssl/qsslellipticcurve.cpp173
-rw-r--r--src/network/ssl/qsslellipticcurve.h104
-rw-r--r--src/network/ssl/qsslellipticcurve_dummy.cpp67
-rw-r--r--src/network/ssl/qsslellipticcurve_openssl.cpp167
-rw-r--r--src/network/ssl/qsslsocket.cpp157
-rw-r--r--src/network/ssl/qsslsocket.h8
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp28
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp11
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h7
-rw-r--r--src/network/ssl/qsslsocket_p.h6
-rw-r--r--src/network/ssl/ssl.pri6
15 files changed, 812 insertions, 1 deletions
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 2aa59e5d18..9430e81fd3 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -202,6 +202,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->sessionCipher == other.d->sessionCipher &&
d->sessionProtocol == other.d->sessionProtocol &&
d->ciphers == other.d->ciphers &&
+ d->ellipticCurves == other.d->ellipticCurves &&
d->caCertificates == other.d->caCertificates &&
d->protocol == other.d->protocol &&
d->peerVerifyMode == other.d->peerVerifyMode &&
@@ -242,6 +243,7 @@ bool QSslConfiguration::isNull() const
d->allowRootCertOnDemandLoading == true &&
d->caCertificates.count() == 0 &&
d->ciphers.count() == 0 &&
+ d->ellipticCurves.isEmpty() &&
d->localCertificateChain.isEmpty() &&
d->privateKey.isNull() &&
d->peerCertificate.isNull() &&
@@ -695,6 +697,50 @@ int QSslConfiguration::sessionTicketLifeTimeHint() const
}
/*!
+ \since 5.5
+
+ Returns this connection's current list of elliptic curves. This
+ list is used during the handshake phase for choosing an
+ elliptic curve (when using an elliptic curve cipher).
+ The returned list of curves is ordered by descending preference
+ (i.e., the first curve in the list is the most preferred one).
+
+ By default, the handshake phase can choose any of the curves
+ supported by this system's SSL libraries, which may vary from
+ system to system. The list of curves supported by this system's
+ SSL libraries is returned by QSslSocket::supportedEllipticCurves().
+
+ You can restrict the list of curves used for choosing the session cipher
+ for this socket by calling setEllipticCurves() with a subset of the
+ supported ciphers. You can revert to using the entire set by calling
+ setEllipticCurves() with the list returned by
+ QSslSocket::supportedEllipticCurves().
+
+ \sa setEllipticCurves
+ */
+QVector<QSslEllipticCurve> QSslConfiguration::ellipticCurves() const
+{
+ return d->ellipticCurves;
+}
+
+/*!
+ \since 5.5
+
+ Sets the list of elliptic curves to be used by this socket to \a curves,
+ which must contain a subset of the curves in the list returned by
+ supportedEllipticCurves().
+
+ Restricting the elliptic curves must be done before the handshake
+ phase, where the session cipher is chosen.
+
+ \sa ellipticCurves
+ */
+void QSslConfiguration::setEllipticCurves(const QVector<QSslEllipticCurve> &curves)
+{
+ d->ellipticCurves = curves;
+}
+
+/*!
\since 5.3
This function returns the protocol negotiated with the server
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index 0c4e122912..7bc7a32cb7 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -62,6 +62,7 @@ template<typename T> class QList;
class QSslCertificate;
class QSslCipher;
class QSslKey;
+class QSslEllipticCurve;
class QSslConfigurationPrivate;
class Q_NETWORK_EXPORT QSslConfiguration
@@ -122,6 +123,10 @@ public:
void setSessionTicket(const QByteArray &sessionTicket);
int sessionTicketLifeTimeHint() const;
+ // EC settings
+ QVector<QSslEllipticCurve> ellipticCurves() const;
+ void setEllipticCurves(const QVector<QSslEllipticCurve> &curves);
+
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 6880f59c4b..54a4786d9f 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -66,6 +66,7 @@
#include "qsslcertificate.h"
#include "qsslcipher.h"
#include "qsslkey.h"
+#include "qsslellipticcurve.h"
QT_BEGIN_NAMESPACE
@@ -107,6 +108,8 @@ public:
Q_AUTOTEST_EXPORT static const QSsl::SslOptions defaultSslOptions;
+ QVector<QSslEllipticCurve> ellipticCurves;
+
QByteArray sslSession;
int sslSessionTicketLifeTimeHint;
diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp
index a2758398f4..e62367cef3 100644
--- a/src/network/ssl/qsslcontext_openssl.cpp
+++ b/src/network/ssl/qsslcontext_openssl.cpp
@@ -2,6 +2,7 @@
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -327,6 +328,30 @@ init_context:
q_EC_KEY_free(ecdh);
#endif // OPENSSL_NO_EC
+ 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) {
+ QVarLengthArray<int, 32> curves;
+ foreach (const QSslEllipticCurve curve, qcurves)
+ curves.append(curve.id);
+
+ if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, curves.size(), curves.data())) {
+ sslContext->errorStr = QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return sslContext;
+ }
+ } else
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
+ {
+ // specific curves requested, but not possible to set -> error
+ sslContext->errorStr = QSslSocket::tr("Error when setting the elliptic curves (OpenSSL version too old, need at least v1.0.2)");
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return sslContext;
+ }
+ }
+
return sslContext;
}
diff --git a/src/network/ssl/qsslellipticcurve.cpp b/src/network/ssl/qsslellipticcurve.cpp
new file mode 100644
index 0000000000..7e122557df
--- /dev/null
+++ b/src/network/ssl/qsslellipticcurve.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsslellipticcurve.h"
+
+#ifndef QT_NO_DEBUG_STREAM
+#include <QDebug>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSslEllipticCurve
+ \since 5.5
+
+ \brief Represents an elliptic curve for use by elliptic-curve cipher algorithms.
+
+ \reentrant
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ The class QSslEllipticCurve represents an elliptic curve for use by
+ elliptic-curve cipher algorithms.
+
+ Elliptic curves can be constructed from a "short name" (SN) (fromShortName()),
+ and by a call to QSslSocket::supportedEllipticCurves().
+
+ QSslEllipticCurve instances can be compared for equality and can be used as keys
+ in QHash and QSet. They cannot be used as key in a QMap.
+*/
+
+/*!
+ \fn QSslEllipticCurve::QSslEllipticCurve()
+
+ Constructs an invalid elliptic curve.
+
+ \sa isValid(), QSslSocket::supportedEllipticCurves()
+*/
+
+/*!
+ \fn QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
+
+ Returns an QSslEllipticCurve instance representing the
+ named curve \a name. The \a name is the conventional short
+ name for the curve, as represented by RFC 4492 (for instance \c{secp521r1}),
+ or as NIST short names (for instance \c{P-256}). The actual set of
+ recognized names depends on the SSL implementation.
+
+ If the given \a name is not supported, returns an invalid QSslEllipticCurve instance.
+
+ \note The OpenSSL implementation of this function treats the name case-sensitively.
+
+ \sa shortName()
+*/
+
+
+/*!
+ \fn QString QSslEllipticCurve::shortName() const
+
+ Returns the conventional short name for this curve. If this
+ curve is invalid, returns an empty string.
+
+ \sa longName()
+*/
+
+/*!
+ \fn QString QSslEllipticCurve::longName() const
+
+ Returns the conventional long name for this curve. If this
+ curve is invalid, returns an empty string.
+
+ \sa shortName()
+*/
+
+/*!
+ \fn bool QSslEllipticCurve::isValid() const
+
+ Returns true if this elliptic curve is a valid curve, false otherwise.
+*/
+
+/*!
+ \fn bool QSslEllipticCurve::isTlsNamedCurve() const
+
+ Returns true if this elliptic curve is one of the named curves that can be
+ used in the key exchange when using an elliptic curve cipher with TLS;
+ false otherwise.
+*/
+
+/*!
+ \fn bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
+ \since 5.5
+ \relates QSslEllipticCurve
+
+ Returns true if the curve \a lhs represents the same curve of \a rhs;
+ false otherwise.
+*/
+
+/*!
+ \fn bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
+ \since 5.5
+ \relates QSslEllipticCurve
+
+ Returns true if the curve \a lhs represents a different curve than \a rhs;
+ false otherwise.
+*/
+
+/*!
+ \fn uint qHash(QSslEllipticCurve curve, uint seed)
+ \since 5.5
+ \relates QHash
+
+ Returns an hash value for the curve \a curve, using \a seed to seed
+ the calculation.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \relates QSslEllipticCurve
+ \since 5.5
+
+ Writes the elliptic curve \a curve into the debug object \a debug for
+ debugging purposes.
+
+ \sa {Debugging Techniques}
+*/
+QDebug operator<<(QDebug debug, QSslEllipticCurve curve)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace() << "QSslEllipticCurve(" << curve.shortName() << ")";
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslellipticcurve.h b/src/network/ssl/qsslellipticcurve.h
new file mode 100644
index 0000000000..8f31b32777
--- /dev/null
+++ b/src/network/ssl/qsslellipticcurve.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSSLELLIPTICCURVE_H
+#define QSSLELLIPTICCURVE_H
+
+#include <QtCore/QtGlobal>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMetaType>
+#include <QtCore/QVector>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QSslEllipticCurve;
+// qHash is a friend, but we can't use default arguments for friends (ยง8.3.6.4)
+Q_DECL_CONSTEXPR uint qHash(QSslEllipticCurve curve, uint seed = 0) Q_DECL_NOTHROW;
+
+class QSslEllipticCurve {
+public:
+ Q_DECL_CONSTEXPR QSslEllipticCurve()
+ : id(0)
+ {
+ }
+
+ Q_NETWORK_EXPORT static QSslEllipticCurve fromShortName(const QString &name);
+
+ Q_NETWORK_EXPORT QString shortName() const Q_REQUIRED_RESULT;
+ Q_NETWORK_EXPORT QString longName() const Q_REQUIRED_RESULT;
+
+ Q_DECL_CONSTEXPR bool isValid() const
+ {
+ return id != 0;
+ }
+
+ Q_NETWORK_EXPORT bool isTlsNamedCurve() const;
+
+private:
+ int id;
+
+ friend Q_DECL_CONSTEXPR bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) Q_DECL_NOTHROW
+ { return lhs.id == rhs.id; }
+ friend Q_DECL_CONSTEXPR uint qHash(QSslEllipticCurve curve, uint seed) Q_DECL_NOTHROW
+ { return qHash(curve.id, seed); }
+
+ friend class QSslContext;
+ friend class QSslSocketPrivate;
+ friend class QSslSocketBackendPrivate;
+};
+
+Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
+
+Q_DECL_CONSTEXPR inline bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs) Q_DECL_NOTHROW
+{ return !operator==(lhs, rhs); }
+
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslEllipticCurve curve);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSslEllipticCurve)
+
+#endif // QSSLELLIPTICCURVE_H
diff --git a/src/network/ssl/qsslellipticcurve_dummy.cpp b/src/network/ssl/qsslellipticcurve_dummy.cpp
new file mode 100644
index 0000000000..64ac1514ab
--- /dev/null
+++ b/src/network/ssl/qsslellipticcurve_dummy.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsslellipticcurve.h"
+
+QT_BEGIN_NAMESPACE
+
+QString QSslEllipticCurve::shortName() const
+{
+ return QString();
+}
+
+QString QSslEllipticCurve::longName() const
+{
+ return QString();
+}
+
+QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
+{
+ Q_UNUSED(name);
+ return QSslEllipticCurve();
+}
+
+bool QSslEllipticCurve::isTlsNamedCurve() const
+{
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslellipticcurve_openssl.cpp b/src/network/ssl/qsslellipticcurve_openssl.cpp
new file mode 100644
index 0000000000..d8d1307b2e
--- /dev/null
+++ b/src/network/ssl/qsslellipticcurve_openssl.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsslellipticcurve.h"
+#include "qsslsocket_p.h"
+#include "qsslsocket_openssl_symbols_p.h"
+
+#include <openssl/ssl.h>
+#include <openssl/obj_mac.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+QString QSslEllipticCurve::shortName() const
+{
+ if (id == 0)
+ return QString();
+
+ QSslSocketPrivate::ensureInitialized();
+
+ QString result;
+#ifndef OPENSSL_NO_EC
+ result = QString::fromLatin1(q_OBJ_nid2sn(id));
+#endif
+ return result;
+}
+
+QString QSslEllipticCurve::longName() const
+{
+ if (id == 0)
+ return QString();
+
+ QSslSocketPrivate::ensureInitialized();
+
+ QString result;
+#ifndef OPENSSL_NO_EC
+ result = QString::fromLatin1(q_OBJ_nid2ln(id));
+#endif
+ return result;
+}
+
+QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
+{
+ if (name.isEmpty())
+ return QSslEllipticCurve();
+
+ QSslSocketPrivate::ensureInitialized();
+
+ QSslEllipticCurve result;
+
+#ifndef OPENSSL_NO_EC
+ const QByteArray curveNameLatin1 = name.toLatin1();
+
+ int nid = q_OBJ_sn2nid(curveNameLatin1.data());
+
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ if (nid == 0 && q_SSLeay() >= 0x10002000L)
+ nid = q_EC_curve_nist2nid(curveNameLatin1.data());
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
+
+ result.id = nid;
+#endif
+
+ return result;
+}
+
+// The brainpool curve NIDs (RFC 7027) have been introduced in OpenSSL 1.0.2,
+// redefine them here to make Qt compile with previous versions of OpenSSL
+// (yet correctly recognize them as TLS named curves).
+// See crypto/objects/obj_mac.h
+#ifndef NID_brainpoolP256r1
+#define NID_brainpoolP256r1 927
+#endif
+
+#ifndef NID_brainpoolP384r1
+#define NID_brainpoolP384r1 931
+#endif
+
+#ifndef NID_brainpoolP512r1
+#define NID_brainpoolP512r1 933
+#endif
+
+// NIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
+// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+static const int tlsNamedCurveNIDs[] = {
+ // RFC 4492
+ NID_sect163k1,
+ NID_sect163r1,
+ NID_sect163r2,
+ NID_sect193r1,
+ NID_sect193r2,
+ NID_sect233k1,
+ NID_sect233r1,
+ NID_sect239k1,
+ NID_sect283k1,
+ NID_sect283r1,
+ NID_sect409k1,
+ NID_sect409r1,
+ NID_sect571k1,
+ NID_sect571r1,
+
+ NID_secp160k1,
+ NID_secp160r1,
+ NID_secp160r2,
+ NID_secp192k1,
+ NID_X9_62_prime192v1, // secp192r1
+ NID_secp224k1,
+ NID_secp224r1,
+ NID_secp256k1,
+ NID_X9_62_prime256v1, // secp256r1
+ NID_secp384r1,
+ NID_secp521r1,
+
+ // RFC 7027
+ NID_brainpoolP256r1,
+ NID_brainpoolP384r1,
+ NID_brainpoolP512r1
+};
+
+static const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
+
+bool QSslEllipticCurve::isTlsNamedCurve() const
+{
+ const int * const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
+ return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 06d85de91b..e8096eca78 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -320,6 +320,7 @@ public:
QMutex mutex;
QList<QSslCipher> supportedCiphers;
+ QVector<QSslEllipticCurve> supportedEllipticCurves;
QExplicitlySharedDataPointer<QSslConfigurationPrivate> config;
};
Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
@@ -899,6 +900,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
d->configuration.localCertificateChain = configuration.localCertificateChain();
d->configuration.privateKey = configuration.privateKey();
d->configuration.ciphers = configuration.ciphers();
+ d->configuration.ellipticCurves = configuration.ellipticCurves();
d->configuration.caCertificates = configuration.caCertificates();
d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
d->configuration.peerVerifyMode = configuration.peerVerifyMode();
@@ -1267,6 +1269,120 @@ QList<QSslCipher> QSslSocket::supportedCiphers()
}
/*!
+ \since 5.5
+
+ Returns this socket's current list of elliptic curves. This
+ list is used during the socket's handshake phase for choosing an
+ elliptic curve (when using an elliptic curve cipher).
+ The returned list of curves is ordered by descending preference
+ (i.e., the first curve in the list is the most preferred one).
+
+ By default, this list is empty. An empty default list means that the
+ handshake phase can choose any of the curves supported by this system's SSL
+ libraries (which may vary from system to system). The list of curves
+ supported by this system's SSL libraries is returned by
+ supportedEllipticCurves().
+
+ You can restrict the list of curves used for choosing the session cipher
+ for this socket by calling setEllipticCurves() with a subset of the
+ supported ciphers. You can revert to using the entire set by calling
+ setEllipticCurves() with the list returned by supportedEllipticCurves().
+
+ \sa setEllipticCurves(), defaultEllipticCurves(), setDefaultEllipticCurves(), supportedEllipticCurves()
+*/
+QVector<QSslEllipticCurve> QSslSocket::ellipticCurves() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.ellipticCurves;
+}
+
+/*!
+ \since 5.5
+
+ Sets the list of elliptic curves to be used by this socket to \a curves,
+ which must contain a subset of the curves in the list returned by
+ supportedEllipticCurves().
+
+ Restricting the elliptic curves must be done before the handshake
+ phase, where the session cipher is chosen.
+
+ If an empty list is set, then the handshake phase can choose any of the
+ curves supported by this system's SSL libraries (which may vary from system
+ to system). The list of curves supported by this system's SSL libraries is
+ returned by supportedEllipticCurves().
+
+ Use setCipher() in order to disable the usage of elliptic curve ciphers.
+
+ \sa ellipticCurves(), setDefaultEllipticCurves(), supportedEllipticCurves()
+*/
+void QSslSocket::setEllipticCurves(const QVector<QSslEllipticCurve> &curves)
+{
+ Q_D(QSslSocket);
+ d->configuration.ellipticCurves = curves;
+}
+
+/*!
+ \since 5.5
+
+ Sets the list of elliptic curves to be used by all sockets in this
+ application to \a curves, which must contain a subset of the curves in the
+ list returned by supportedEllipticCurves().
+
+ Restricting the default elliptic curves only affects SSL sockets
+ that perform their handshake phase after the default list has been changed.
+
+ If an empty list is set, then the handshake phase can choose any of the
+ curves supported by this system's SSL libraries (which may vary from system
+ to system). The list of curves supported by this system's SSL libraries is
+ returned by supportedEllipticCurves().
+
+ Use setDefaultCiphers() in order to disable the usage of elliptic curve ciphers.
+
+ \sa setEllipticCurves(), defaultEllipticCurves(), supportedEllipticCurves()
+*/
+void QSslSocket::setDefaultEllipticCurves(const QVector<QSslEllipticCurve> &curves)
+{
+ QSslSocketPrivate::setDefaultEllipticCurves(curves);
+}
+
+
+/*!
+ \since 5.5
+
+ Returns the default elliptic curves list for all sockets in
+ this application. This list is used during the socket's handshake
+ phase when negotiating with the peer to choose a session cipher.
+ The list is ordered by preference (i.e., the first curve in the
+ list is the most preferred one).
+
+ By default, this list is empty. An empty default list means that the
+ handshake phase can choose any of the curves supported by this system's SSL
+ libraries (which may vary from system to system). The list of curves
+ supported by this system's SSL libraries is returned by
+ supportedEllipticCurves().
+
+ \sa setDefaultEllipticCurves(), supportedEllipticCurves()
+*/
+QVector<QSslEllipticCurve> QSslSocket::defaultEllipticCurves()
+{
+ return QSslSocketPrivate::defaultEllipticCurves();
+}
+
+/*!
+ \since 5.5
+
+ Returns the list of elliptic curves supported by this
+ system. This list is set by the system's SSL libraries and may
+ vary from system to system.
+
+ \sa ellipticCurves(), setEllipticCurves(), defaultEllipticCurves()
+*/
+QVector<QSslEllipticCurve> QSslSocket::supportedEllipticCurves()
+{
+ return QSslSocketPrivate::supportedEllipticCurves();
+}
+
+/*!
Searches all files in the \a path for certificates encoded in the
specified \a format and adds them to this socket's CA certificate
database. \a path can be explicit, or it can contain wildcards in
@@ -2031,6 +2147,46 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
/*!
\internal
*/
+QVector<QSslEllipticCurve> QSslSocketPrivate::defaultEllipticCurves()
+{
+ QSslSocketPrivate::ensureInitialized();
+ const QMutexLocker locker(&globalData()->mutex);
+ return globalData()->config->ellipticCurves;
+}
+
+/*!
+ \internal
+*/
+QVector<QSslEllipticCurve> QSslSocketPrivate::supportedEllipticCurves()
+{
+ QSslSocketPrivate::ensureInitialized();
+ const QMutexLocker locker(&globalData()->mutex);
+ return globalData()->supportedEllipticCurves;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultEllipticCurves(const QVector<QSslEllipticCurve> &curves)
+{
+ const QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->ellipticCurves = curves;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultSupportedEllipticCurves(const QVector<QSslEllipticCurve> &curves)
+{
+ const QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->supportedEllipticCurves = curves;
+}
+
+/*!
+ \internal
+*/
QList<QSslCertificate> QSslSocketPrivate::defaultCaCertificates()
{
QSslSocketPrivate::ensureInitialized();
@@ -2139,6 +2295,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
ptr->peerVerifyMode = global->peerVerifyMode;
ptr->peerVerifyDepth = global->peerVerifyDepth;
ptr->sslOptions = global->sslOptions;
+ ptr->ellipticCurves = global->ellipticCurves;
}
/*!
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index 1fe12e5989..149dcc99cc 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -51,6 +51,7 @@ class QDir;
class QSslCipher;
class QSslCertificate;
class QSslConfiguration;
+class QSslEllipticCurve;
class QSslSocketPrivate;
class Q_NETWORK_EXPORT QSslSocket : public QTcpSocket
@@ -149,6 +150,13 @@ public:
static QList<QSslCipher> defaultCiphers();
static QList<QSslCipher> supportedCiphers();
+ // EC settings.
+ QVector<QSslEllipticCurve> ellipticCurves() const;
+ void setEllipticCurves(const QVector<QSslEllipticCurve> &curves);
+ static void setDefaultEllipticCurves(const QVector<QSslEllipticCurve> &curves);
+ static QVector<QSslEllipticCurve> defaultEllipticCurves();
+ static QVector<QSslEllipticCurve> supportedEllipticCurves();
+
// CA settings.
bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
QRegExp::PatternSyntax syntax = QRegExp::FixedString);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 84b0d9c75e..516d862936 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Governikus GmbH & Co. KG
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -55,6 +56,7 @@
#include "qsslcertificate_p.h"
#include "qsslcipher_p.h"
#include "qsslkey_p.h"
+#include "qsslellipticcurve.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
@@ -479,6 +481,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
s_loadedCiphersAndCerts = true;
resetDefaultCiphers();
+ resetDefaultEllipticCurves();
#ifndef QT_NO_LIBRARY
//load symbols needed to receive certificates from system store
@@ -627,6 +630,31 @@ void QSslSocketPrivate::resetDefaultCiphers()
setDefaultCiphers(defaultCiphers);
}
+void QSslSocketPrivate::resetDefaultEllipticCurves()
+{
+ QVector<QSslEllipticCurve> curves;
+
+#ifndef OPENSSL_NO_EC
+ const size_t curveCount = q_EC_get_builtin_curves(NULL, 0);
+
+ QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount));
+
+ if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
+ for (size_t i = 0; i < curveCount; ++i) {
+ QSslEllipticCurve curve;
+ curve.id = builtinCurves[i].nid;
+ curves.append(curve);
+ }
+ }
+#endif // OPENSSL_NO_EC
+
+ // set the list of supported ECs, but not the list
+ // of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong
+ // ciphersuite, so don't try it -- leave the empty list to mean
+ // "the implementation will choose the most suitable one".
+ setDefaultSupportedEllipticCurves(curves);
+}
+
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
{
ensureInitialized();
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 71b8237e03..08dec606ae 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -167,6 +167,7 @@ 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)
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)
@@ -371,6 +372,10 @@ DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM
#ifndef OPENSSL_NO_EC
DEFINEFUNC(EC_KEY *, EC_KEY_new_by_curve_name, int nid, nid, return 0, return)
DEFINEFUNC(void, EC_KEY_free, EC_KEY *ecdh, ecdh, return, DUMMYARG)
+DEFINEFUNC2(size_t, EC_get_builtin_curves, EC_builtin_curve * r, r, size_t nitems, nitems, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+DEFINEFUNC(int, EC_curve_nist2nid, const char *name, name, return 0, return)
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#endif // OPENSSL_NO_EC
DEFINEFUNC5(int, PKCS12_parse, PKCS12 *p12, p12, const char *pass, pass, EVP_PKEY **pkey, pkey, \
@@ -728,6 +733,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(EVP_PKEY_type)
RESOLVEFUNC(OBJ_nid2sn)
RESOLVEFUNC(OBJ_nid2ln)
+ RESOLVEFUNC(OBJ_sn2nid)
RESOLVEFUNC(i2t_ASN1_OBJECT)
RESOLVEFUNC(OBJ_obj2txt)
RESOLVEFUNC(OBJ_obj2nid)
@@ -878,6 +884,11 @@ bool q_resolveOpenSslSymbols()
#ifndef OPENSSL_NO_EC
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)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index e2e09e4feb..ee19345e4a 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -248,6 +248,7 @@ Q_AUTOTEST_EXPORT EVP_PKEY *q_EVP_PKEY_new();
int q_i2d_X509(X509 *a, unsigned char **b);
const char *q_OBJ_nid2sn(int a);
const char *q_OBJ_nid2ln(int a);
+int q_OBJ_sn2nid(const char *s);
int q_i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *obj);
int q_OBJ_obj2txt(char *buf, int buf_len, ASN1_OBJECT *obj, int no_name);
int q_OBJ_obj2nid(const ASN1_OBJECT *a);
@@ -435,6 +436,12 @@ BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
EC_KEY *q_EC_KEY_new_by_curve_name(int nid);
void q_EC_KEY_free(EC_KEY *ecdh);
#define q_SSL_CTX_set_tmp_ecdh(ctx, ecdh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_ECDH, 0, (char *)ecdh)
+
+// EC curves management
+size_t q_EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+int q_EC_curve_nist2nid(const char *name);
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#endif // OPENSSL_NO_EC
// PKCS#12 support
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 6e7a2c5520..53f91ee205 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -135,6 +135,12 @@ public:
static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
static void resetDefaultCiphers();
+ static QVector<QSslEllipticCurve> defaultEllipticCurves();
+ static QVector<QSslEllipticCurve> supportedEllipticCurves();
+ static void setDefaultEllipticCurves(const QVector<QSslEllipticCurve> &curves);
+ static void setDefaultSupportedEllipticCurves(const QVector<QSslEllipticCurve> &curves);
+ static void resetDefaultEllipticCurves();
+
static QList<QSslCertificate> defaultCaCertificates();
static QList<QSslCertificate> systemCaCertificates();
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index 384e149241..85fd6fc3f5 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -8,6 +8,7 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslconfiguration_p.h \
ssl/qsslcipher.h \
ssl/qsslcipher_p.h \
+ ssl/qsslellipticcurve.h \
ssl/qsslerror.h \
ssl/qsslkey.h \
ssl/qsslkey_p.h \
@@ -20,6 +21,7 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslcertificate.cpp \
ssl/qsslconfiguration.cpp \
ssl/qsslcipher.cpp \
+ ssl/qsslellipticcurve.cpp \
ssl/qsslkey_p.cpp \
ssl/qsslerror.cpp \
ssl/qsslsocket.cpp \
@@ -31,7 +33,8 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslcertificate_winrt.cpp \
ssl/qsslkey_qt.cpp \
ssl/qsslkey_winrt.cpp \
- ssl/qsslsocket_winrt.cpp
+ ssl/qsslsocket_winrt.cpp \
+ ssl/qsslellipticcurve_dummy.cpp
}
}
@@ -41,6 +44,7 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
ssl/qsslsocket_openssl_symbols_p.h
SOURCES += ssl/qsslcertificate_openssl.cpp \
ssl/qsslcontext_openssl.cpp \
+ ssl/qsslellipticcurve_openssl.cpp \
ssl/qsslkey_openssl.cpp \
ssl/qsslsocket_openssl.cpp \
ssl/qsslsocket_openssl_symbols.cpp