SSL: Add support for selecting which curves should be used by an elliptic cipher

[ChangeLog][QtNetwork][QtSSL] It is now possible to choose which elliptic
curves should be used by an elliptic curve cipher.

Change-Id: If5d0d58922768b6f1375836489180e576f5a015a
Done-with: Marc Mutz <marc.mutz@kdab.com>
Reviewed-by: Richard J. Moore <rich@kde.org>
This commit is contained in:
Giuseppe D'Angelo 2014-09-03 11:12:12 +02:00
parent 153463ea95
commit ffbfd8eda6
19 changed files with 942 additions and 1 deletions

View File

@ -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() &&
@ -694,6 +696,50 @@ int QSslConfiguration::sessionTicketLifeTimeHint() const
return d->sslSessionTicketLifeTimeHint;
}
/*!
\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

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
@ -1266,6 +1268,120 @@ QList<QSslCipher> QSslSocket::supportedCiphers()
return QSslSocketPrivate::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
@ -2028,6 +2144,46 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
globalData()->supportedCiphers = ciphers;
}
/*!
\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
*/
@ -2139,6 +2295,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
ptr->peerVerifyMode = global->peerVerifyMode;
ptr->peerVerifyDepth = global->peerVerifyDepth;
ptr->sslOptions = global->sslOptions;
ptr->ellipticCurves = global->ellipticCurves;
}
/*!

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -0,0 +1 @@
tst_qsslellipticcurves

View File

@ -0,0 +1,8 @@
CONFIG += testcase
CONFIG += parallel_test
SOURCES += tst_qsslellipticcurve.cpp
!wince*:win32:LIBS += -lws2_32
QT = core network testlib
TARGET = tst_qsslellipticcurve

View File

@ -0,0 +1,120 @@
/****************************************************************************
**
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite 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 <QtTest/QtTest>
#include <QSslEllipticCurve>
#include <QSslSocket>
class tst_QSslEllipticCurve : public QObject
{
Q_OBJECT
#ifndef QT_NO_SSL
private Q_SLOTS:
void constExpr();
void construction();
void fromShortName_data();
void fromShortName();
#endif
};
#ifndef QT_NO_SSL
void tst_QSslEllipticCurve::constExpr()
{
#ifdef Q_COMPILER_CONSTEXPR
// check that default ctor and op ==/!= are constexpr:
char array1[QSslEllipticCurve() == QSslEllipticCurve() ? 1 : -1];
char array2[QSslEllipticCurve() != QSslEllipticCurve() ? -1 : 1];
Q_UNUSED(array1);
Q_UNUSED(array2);
#else
QSKIP("This test requires C++11 generalized constant expression support enabled in the compiler.");
#endif
}
void tst_QSslEllipticCurve::construction()
{
QSslEllipticCurve curve;
QCOMPARE(curve.isValid(), false);
QCOMPARE(curve.shortName(), QString());
QCOMPARE(curve.longName(), QString());
QCOMPARE(curve.isTlsNamedCurve(), false);
}
void tst_QSslEllipticCurve::fromShortName_data()
{
QTest::addColumn<QString>("shortName");
QTest::addColumn<QSslEllipticCurve>("curve");
QTest::addColumn<bool>("valid");
QTest::newRow("QString()") << QString() << QSslEllipticCurve() << false;
QTest::newRow("\"\"") << QString("") << QSslEllipticCurve() << false;
QTest::newRow("does-not-exist") << QStringLiteral("does-not-exist") << QSslEllipticCurve() << false;
Q_FOREACH (QSslEllipticCurve ec, QSslSocket::supportedEllipticCurves()) {
const QString sN = ec.shortName();
QTest::newRow(qPrintable("supported EC \"" + sN + '"')) << sN << ec << true;
// At least in the OpenSSL impl, the short name is case-sensitive. That feels odd.
//const QString SN = sN.toUpper();
//QTest::newRow(qPrintable("supported EC \"" + SN + '"')) << SN << ec << true;
//const QString sn = sN.toLower();
//QTest::newRow(qPrintable("supported EC \"" + sn + '"')) << sn << ec << true;
}
}
void tst_QSslEllipticCurve::fromShortName()
{
QFETCH(QString, shortName);
QFETCH(QSslEllipticCurve, curve);
QFETCH(bool, valid);
const QSslEllipticCurve result = QSslEllipticCurve::fromShortName(shortName);
QCOMPARE(result, curve);
QCOMPARE(result.isValid(), valid);
QCOMPARE(result.shortName(), curve.shortName());
QCOMPARE(result.shortName(), valid ? shortName : QString());
}
#endif // QT_NO_SSL
QTEST_MAIN(tst_QSslEllipticCurve)
#include "tst_qsslellipticcurve.moc"

View File

@ -2,6 +2,7 @@ TEMPLATE=subdirs
SUBDIRS=\
qsslcertificate \
qsslcipher \
qsslellipticcurve \
qsslerror \
qsslkey \