Convert elliptic curves and DH params to work with QTlsBackend

The corresponding API is becoming a part of QTlsBackend interface,
since it's too minimalistic and does not require additional
interfaces, unlike certificates or keys.

Pick-to: dev
Fixes: QTBUG-91177
Fixes: QTBUG-91175
Task-number: QTBUG-65922
Change-Id: I44dd0adbdf2427962451998664efe234d59fae24
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Timur Pocheptsov 2021-02-23 11:40:50 +01:00
parent c2e7eaa009
commit cdf4976b5a
13 changed files with 373 additions and 397 deletions

View File

@ -330,8 +330,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
SOURCES SOURCES
ssl/qssldiffiehellmanparameters_dummy.cpp
ssl/qsslellipticcurve_dummy.cpp
ssl/qsslsocket_qt.cpp ssl/qsslsocket_qt.cpp
ssl/qsslsocket_schannel.cpp ssl/qsslsocket_schannel_p.h ssl/qsslsocket_schannel.cpp ssl/qsslsocket_schannel_p.h
ssl/qtlsbackend_schannel_p.h ssl/qtlsbackend_schannel_p.h
@ -347,8 +345,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_s
qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FEATURE_ssl qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FEATURE_ssl
SOURCES SOURCES
ssl/qssldiffiehellmanparameters_dummy.cpp
ssl/qsslellipticcurve_dummy.cpp
ssl/qsslsocket_mac.cpp ssl/qsslsocket_mac_p.h ssl/qsslsocket_mac.cpp ssl/qsslsocket_mac_p.h
ssl/qsslsocket_mac_shared.cpp ssl/qsslsocket_mac_shared.cpp
ssl/qsslsocket_qt.cpp ssl/qsslsocket_qt.cpp
@ -367,7 +363,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ss
SOURCES SOURCES
ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h
ssl/qssldiffiehellmanparameters_openssl.cpp ssl/qssldiffiehellmanparameters_openssl.cpp
ssl/qsslellipticcurve_openssl.cpp
ssl/qsslsocket_openssl.cpp ssl/qsslsocket_openssl_p.h ssl/qsslsocket_openssl.cpp ssl/qsslsocket_openssl_p.h
ssl/qsslsocket_openssl_symbols.cpp ssl/qsslsocket_openssl_symbols_p.h ssl/qsslsocket_openssl_symbols.cpp ssl/qsslsocket_openssl_symbols_p.h
ssl/qtlskey_openssl.cpp ssl/qtlskey_openssl_p.h ssl/qtlskey_openssl.cpp ssl/qtlskey_openssl_p.h

View File

@ -56,6 +56,7 @@
#include "qssldiffiehellmanparameters.h" #include "qssldiffiehellmanparameters.h"
#include "qssldiffiehellmanparameters_p.h" #include "qssldiffiehellmanparameters_p.h"
#include "qtlsbackend_p.h"
#include "qsslsocket.h" #include "qsslsocket.h"
#include "qsslsocket_p.h" #include "qsslsocket_p.h"
@ -117,12 +118,15 @@ QSslDiffieHellmanParameters::QSslDiffieHellmanParameters()
QSslDiffieHellmanParameters QSslDiffieHellmanParameters::fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat encoding) QSslDiffieHellmanParameters QSslDiffieHellmanParameters::fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat encoding)
{ {
QSslDiffieHellmanParameters result; QSslDiffieHellmanParameters result;
const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
if (!tlsBackend)
return result;
switch (encoding) { switch (encoding) {
case QSsl::Der: case QSsl::Der:
result.d->decodeDer(encoded); result.d->initFromDer(encoded);
break; break;
case QSsl::Pem: case QSsl::Pem:
result.d->decodePem(encoded); result.d->initFromPem(encoded);
break; break;
} }
return result; return result;
@ -299,6 +303,24 @@ bool QSslDiffieHellmanParameters::isEqual(const QSslDiffieHellmanParameters &oth
return d->derData == other.d->derData; return d->derData == other.d->derData;
} }
/*!
\internal
*/
void QSslDiffieHellmanParametersPrivate::initFromDer(const QByteArray &der)
{
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
error = QSslDiffieHellmanParameters::Error(tlsBackend->dhParametersFromDer(der, &derData));
}
/*!
\internal
*/
void QSslDiffieHellmanParametersPrivate::initFromPem(const QByteArray &pem)
{
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
error = QSslDiffieHellmanParameters::Error(tlsBackend->dhParametersFromPem(pem, &derData));
}
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
/*! /*!
\since 5.8 \since 5.8

View File

@ -1,57 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
** 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 "qssldiffiehellmanparameters.h"
#include "qssldiffiehellmanparameters_p.h"
#include <QtCore/qglobal.h>
#include <QtCore/qbytearray.h>
QT_BEGIN_NAMESPACE
void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &)
{
}
void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &)
{
}
QT_END_NAMESPACE

View File

@ -38,30 +38,25 @@
** **
****************************************************************************/ ****************************************************************************/
#include "qssldiffiehellmanparameters.h"
#include "qssldiffiehellmanparameters_p.h"
#include "qsslsocket_openssl_symbols_p.h" #include "qsslsocket_openssl_symbols_p.h"
#include "qsslsocket.h" #include "qtlsbackend_openssl_p.h"
#include "qsslsocket_p.h" #include "qsslsocket_p.h"
#include "private/qssl_p.h" #include <QtCore/qscopeguard.h>
#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h> #include <QtCore/qbytearray.h>
#include <QtCore/qiodevice.h> #include <QtCore/qiodevice.h>
#include <QtCore/qscopeguard.h>
#ifndef QT_NO_DEBUG_STREAM
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#endif
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dh.h> #include <openssl/dh.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace {
#ifdef OPENSSL_NO_DEPRECATED_3_0 #ifdef OPENSSL_NO_DEPRECATED_3_0
static int q_DH_check(DH *dh, int *status) int q_DH_check(DH *dh, int *status)
{ {
// DH_check was first deprecated in OpenSSL 3.0.0, as low-level // DH_check was first deprecated in OpenSSL 3.0.0, as low-level
// API; the EVP_PKEY family of functions was advised as an alternative. // API; the EVP_PKEY family of functions was advised as an alternative.
@ -110,14 +105,15 @@ static int q_DH_check(DH *dh, int *status)
} }
#endif // OPENSSL_NO_DEPRECATED_3_0 #endif // OPENSSL_NO_DEPRECATED_3_0
static bool isSafeDH(DH *dh) bool isSafeDH(DH *dh)
{ {
int status = 0; int status = 0;
int bad = 0; int bad = 0;
// TLSTODO: check it's needed or if supportsSsl()
// is enough.
QSslSocketPrivate::ensureInitialized(); QSslSocketPrivate::ensureInitialized();
// From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters: // From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters:
// //
// The additional call to BN_mod_word(dh->p, 24) // The additional call to BN_mod_word(dh->p, 24)
@ -154,71 +150,81 @@ static bool isSafeDH(DH *dh)
return !(status & bad); return !(status & bad);
} }
void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &der) } // unnamed namespace
int QTlsBackendOpenSSL::dhParametersFromDer(const QByteArray &der, QByteArray *derData) const
{ {
if (der.isEmpty()) { Q_ASSERT(derData);
error = QSslDiffieHellmanParameters::InvalidInputDataError;
return; if (der.isEmpty())
} return DHParams::InvalidInputDataError;
const unsigned char *data = reinterpret_cast<const unsigned char *>(der.data()); const unsigned char *data = reinterpret_cast<const unsigned char *>(der.data());
int len = der.size(); const int len = der.size();
// TLSTODO: check it's needed (loading ciphers and certs in
// addition to the library!)
QSslSocketPrivate::ensureInitialized(); QSslSocketPrivate::ensureInitialized();
DH *dh = q_d2i_DHparams(nullptr, &data, len); DH *dh = q_d2i_DHparams(nullptr, &data, len);
if (dh) { if (dh) {
const auto dhRaii = qScopeGuard([dh] {q_DH_free(dh);});
if (isSafeDH(dh)) if (isSafeDH(dh))
derData = der; *derData = der;
else else
error = QSslDiffieHellmanParameters::UnsafeParametersError; return DHParams::UnsafeParametersError;
} else { } else {
error = QSslDiffieHellmanParameters::InvalidInputDataError; return DHParams::InvalidInputDataError;
} }
q_DH_free(dh); return DHParams::NoError;
} }
void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &pem) int QTlsBackendOpenSSL::dhParametersFromPem(const QByteArray &pem, QByteArray *data) const
{ {
if (pem.isEmpty()) { Q_ASSERT(data);
error = QSslDiffieHellmanParameters::InvalidInputDataError;
return;
}
if (!QSslSocket::supportsSsl()) { if (pem.isEmpty())
error = QSslDiffieHellmanParameters::InvalidInputDataError; return DHParams::InvalidInputDataError;
return;
}
// TLSTODO: check it was not a cargo-cult programming in case of
// DH ...
QSslSocketPrivate::ensureInitialized(); QSslSocketPrivate::ensureInitialized();
BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size()); BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
if (!bio) { if (!bio)
error = QSslDiffieHellmanParameters::InvalidInputDataError; return DHParams::InvalidInputDataError;
return;
} const auto bioRaii = qScopeGuard([bio]
{
q_BIO_free(bio);
});
DH *dh = nullptr; DH *dh = nullptr;
q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr); q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr);
if (dh) { if (dh) {
const auto dhGuard = qScopeGuard([dh]
{
q_DH_free(dh);
});
if (isSafeDH(dh)) { if (isSafeDH(dh)) {
char *buf = nullptr; char *buf = nullptr;
int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf)); const int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf));
if (len > 0) if (len > 0)
derData = QByteArray(buf, len); *data = QByteArray(buf, len);
else else
error = QSslDiffieHellmanParameters::InvalidInputDataError; return DHParams::InvalidInputDataError;
} else { } else {
error = QSslDiffieHellmanParameters::UnsafeParametersError; return DHParams::UnsafeParametersError;
} }
} else { } else {
error = QSslDiffieHellmanParameters::InvalidInputDataError; return DHParams::InvalidInputDataError;
} }
q_DH_free(dh); return DHParams::NoError;
q_BIO_free(bio);
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -53,23 +53,20 @@
// //
#include <QtNetwork/private/qtnetworkglobal_p.h> #include <QtNetwork/private/qtnetworkglobal_p.h>
#include <QSharedData>
#include "qsslkey.h"
#include "qssldiffiehellmanparameters.h" #include "qssldiffiehellmanparameters.h"
#include "qsslsocket_p.h" // includes wincrypt.h
#include <QSharedData>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSslDiffieHellmanParametersPrivate : public QSharedData class QSslDiffieHellmanParametersPrivate : public QSharedData
{ {
public: public:
QSslDiffieHellmanParametersPrivate() : error(QSslDiffieHellmanParameters::NoError) {} void initFromDer(const QByteArray &der);
void initFromPem(const QByteArray &pem);
void decodeDer(const QByteArray &der); QSslDiffieHellmanParameters::Error error = QSslDiffieHellmanParameters::NoError;
void decodePem(const QByteArray &pem);
QSslDiffieHellmanParameters::Error error;
QByteArray derData; QByteArray derData;
}; };

View File

@ -38,6 +38,8 @@
****************************************************************************/ ****************************************************************************/
#include "qsslellipticcurve.h" #include "qsslellipticcurve.h"
#include "qtlsbackend_p.h"
#include "qsslsocket_p.h"
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
#include <QDebug> #include <QDebug>
@ -77,8 +79,6 @@ QT_BEGIN_NAMESPACE
*/ */
/*! /*!
\fn QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
Returns an QSslEllipticCurve instance representing the Returns an QSslEllipticCurve instance representing the
named curve \a name. The \a name is the conventional short named curve \a name. The \a name is the conventional short
name for the curve, as represented by RFC 4492 (for instance \c{secp521r1}), name for the curve, as represented by RFC 4492 (for instance \c{secp521r1}),
@ -91,10 +91,19 @@ QT_BEGIN_NAMESPACE
\sa shortName() \sa shortName()
*/ */
QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
{
QSslEllipticCurve result;
if (name.isEmpty())
return result;
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
result.id = tlsBackend->curveIdFromShortName(name);
return result;
}
/*! /*!
\fn QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
Returns an QSslEllipticCurve instance representing the named curve \a name. Returns an QSslEllipticCurve instance representing the named curve \a name.
The \a name is a long name for the curve, whose exact spelling depends on the The \a name is a long name for the curve, whose exact spelling depends on the
SSL implementation. SSL implementation.
@ -105,24 +114,49 @@ QT_BEGIN_NAMESPACE
\sa longName() \sa longName()
*/ */
QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
{
QSslEllipticCurve result;
if (name.isEmpty())
return result;
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
result.id = tlsBackend->curveIdFromLongName(name);
return result;
}
/*! /*!
\fn QString QSslEllipticCurve::shortName() const
Returns the conventional short name for this curve. If this Returns the conventional short name for this curve. If this
curve is invalid, returns an empty string. curve is invalid, returns an empty string.
\sa longName() \sa longName()
*/ */
QString QSslEllipticCurve::shortName() const
{
QString name;
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
name = tlsBackend->shortNameForId(id);
return name;
}
/*! /*!
\fn QString QSslEllipticCurve::longName() const
Returns the conventional long name for this curve. If this Returns the conventional long name for this curve. If this
curve is invalid, returns an empty string. curve is invalid, returns an empty string.
\sa shortName() \sa shortName()
*/ */
QString QSslEllipticCurve::longName() const
{
QString name;
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
name = tlsBackend->longNameForId(id);
return name;
}
/*! /*!
\fn bool QSslEllipticCurve::isValid() const \fn bool QSslEllipticCurve::isValid() const
@ -131,12 +165,18 @@ QT_BEGIN_NAMESPACE
*/ */
/*! /*!
\fn bool QSslEllipticCurve::isTlsNamedCurve() const
Returns true if this elliptic curve is one of the named curves that can be 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; used in the key exchange when using an elliptic curve cipher with TLS;
false otherwise. false otherwise.
*/ */
bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
{
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
return tlsBackend->isTlsNamedCurve(id);
return false;
}
/*! /*!
\fn bool QSslEllipticCurve::operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) \fn bool QSslEllipticCurve::operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs)

View File

@ -1,71 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "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();
}
QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
{
Q_UNUSED(name);
return QSslEllipticCurve();
}
bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
{
return false;
}
QT_END_NAMESPACE

View File

@ -1,177 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "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
{
QString result;
#ifndef OPENSSL_NO_EC
if (id != 0)
result = QString::fromLatin1(q_OBJ_nid2sn(id));
#endif
return result;
}
QString QSslEllipticCurve::longName() const
{
QString result;
#ifndef OPENSSL_NO_EC
if (id != 0)
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 (nid == 0)
nid = q_EC_curve_nist2nid(curveNameLatin1.data());
result.id = nid;
#endif // !OPENSSL_NO_EC
return result;
}
QSslEllipticCurve QSslEllipticCurve::fromLongName(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_ln2nid(curveNameLatin1.data());
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 noexcept
{
const int * const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
}
QT_END_NAMESPACE

View File

@ -967,22 +967,22 @@ void QSslSocketPrivate::resetDefaultCiphers()
void QSslSocketPrivate::resetDefaultEllipticCurves() void QSslSocketPrivate::resetDefaultEllipticCurves()
{ {
// TLSTODO: this function to be be merged into qsslsocket.cpp
const auto *tlsBackend = tlsBackendInUse();
if (!tlsBackend)
return;
auto ids = tlsBackend->ellipticCurvesIds();
if (!ids.size())
return;
QList<QSslEllipticCurve> curves; QList<QSslEllipticCurve> curves;
curves.reserve(ids.size());
#ifndef OPENSSL_NO_EC for (int id : ids) {
const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0); QSslEllipticCurve curve;
curve.id = id;
QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount)); curves.append(curve);
if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
curves.reserve(int(curveCount));
for (size_t i = 0; i < curveCount; ++i) {
QSslEllipticCurve curve;
curve.id = builtinCurves[int(i)].nid;
curves.append(curve);
}
} }
#endif // OPENSSL_NO_EC
// set the list of supported ECs, but not the list // set the list of supported ECs, but not the list
// of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong // of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong

View File

@ -229,60 +229,120 @@ QString QTlsBackend::backendName() const
return QStringLiteral("dummyTLS"); return QStringLiteral("dummyTLS");
} }
#define REPORT_MISSING_SUPPORT(message) \
qCWarning(lcSsl) << "The backend" << backendName() << message
QSsl::TlsKey *QTlsBackend::createKey() const QSsl::TlsKey *QTlsBackend::createKey() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot generate a key"); REPORT_MISSING_SUPPORT("does not support QSslKey");
return nullptr; return nullptr;
} }
QSsl::X509Certificate *QTlsBackend::createCertificate() const QSsl::X509Certificate *QTlsBackend::createCertificate() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot create a certificate"); REPORT_MISSING_SUPPORT("does not support QSslCertificate");
return nullptr; return nullptr;
} }
QSsl::TlsCryptograph *QTlsBackend::createTlsCryptograph() const QSsl::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot create TLS session"); REPORT_MISSING_SUPPORT("does not support QSslSocket");
return nullptr; return nullptr;
} }
QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph() const QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot create DTLS session"); REPORT_MISSING_SUPPORT("does not support QDtls");
return nullptr; return nullptr;
} }
QSsl::DtlsCookieVerifier *QTlsBackend::createDtlsCookieVerifier() const QSsl::DtlsCookieVerifier *QTlsBackend::createDtlsCookieVerifier() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot create DTLS cookie generator/verifier"); REPORT_MISSING_SUPPORT("does not support DTLS cookies");
return nullptr; return nullptr;
} }
QSsl::X509ChainVerifyPtr QTlsBackend::X509Verifier() const QSsl::X509ChainVerifyPtr QTlsBackend::X509Verifier() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot verify X509 chain"); REPORT_MISSING_SUPPORT("does not support (manual) certificate verification");
return nullptr; return nullptr;
} }
QSsl::X509PemReaderPtr QTlsBackend::X509PemReader() const QSsl::X509PemReaderPtr QTlsBackend::X509PemReader() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot read PEM format"); REPORT_MISSING_SUPPORT("cannot read PEM format");
return nullptr; return nullptr;
} }
QSsl::X509DerReaderPtr QTlsBackend::X509DerReader() const QSsl::X509DerReaderPtr QTlsBackend::X509DerReader() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, don't know how to read DER"); REPORT_MISSING_SUPPORT("cannot read DER format");
return nullptr; return nullptr;
} }
QSsl::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const QSsl::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const
{ {
qCWarning(lcSsl, "Dummy TLS backend, cannot read PKCS12"); REPORT_MISSING_SUPPORT("cannot read PKCS12 format");
return nullptr; return nullptr;
} }
QList<int> QTlsBackend::ellipticCurvesIds() const
{
REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
return {};
}
int QTlsBackend::curveIdFromShortName(const QString &name) const
{
Q_UNUSED(name);
REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
return 0;
}
int QTlsBackend::curveIdFromLongName(const QString &name) const
{
Q_UNUSED(name);
REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
return 0;
}
QString QTlsBackend::shortNameForId(int cid) const
{
Q_UNUSED(cid);
REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
return {};
}
QString QTlsBackend::longNameForId(int cid) const
{
Q_UNUSED(cid);
REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
return {};
}
bool QTlsBackend::isTlsNamedCurve(int cid) const
{
Q_UNUSED(cid);
REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
return false;
}
int QTlsBackend::dhParametersFromDer(const QByteArray &derData, QByteArray *data) const
{
Q_UNUSED(derData);
Q_UNUSED(data);
REPORT_MISSING_SUPPORT("does not support QSslDiffieHellmanParameters in DER format");
return {};
}
int QTlsBackend::dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const
{
Q_UNUSED(pemData);
Q_UNUSED(data);
REPORT_MISSING_SUPPORT("does not support QSslDiffieHellmanParameters in PEM format");
return {};
}
QList<QString> QTlsBackend::availableBackendNames() QList<QString> QTlsBackend::availableBackendNames()
{ {
if (!backends()) if (!backends())

View File

@ -51,6 +51,8 @@
#include <qlist.h> #include <qlist.h>
#include <algorithm>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl"); Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl");
@ -181,4 +183,131 @@ QSsl::X509Pkcs12ReaderPtr QTlsBackendOpenSSL::X509Pkcs12Reader() const
return QSsl::X509CertificateOpenSSL::importPkcs12; return QSsl::X509CertificateOpenSSL::importPkcs12;
} }
QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
{
QList<int> ids;
#ifndef OPENSSL_NO_EC
const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0);
QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount));
if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
ids.reserve(curveCount);
for (const auto &ec : builtinCurves)
ids.push_back(ec.nid);
}
#endif // OPENSSL_NO_EC
return ids;
}
int QTlsBackendOpenSSL::curveIdFromShortName(const QString &name) const
{
int nid = 0;
if (name.isEmpty())
return nid;
// TLSTODO: check if it's needed! The fact we are here,
// means OpenSSL was loaded, symbols resolved. Is it because
// of ensureCiphers(AndCertificates)Loaded ?
QSslSocketPrivate::ensureInitialized();
#ifndef OPENSSL_NO_EC
const QByteArray curveNameLatin1 = name.toLatin1();
nid = q_OBJ_sn2nid(curveNameLatin1.data());
if (nid == 0)
nid = q_EC_curve_nist2nid(curveNameLatin1.data());
#endif // !OPENSSL_NO_EC
return nid;
}
int QTlsBackendOpenSSL::curveIdFromLongName(const QString &name) const
{
int nid = 0;
if (name.isEmpty())
return nid;
// TLSTODO: check if it's needed! The fact we are here,
// means OpenSSL was loaded, symbols resolved. Is it because
// of ensureCiphers(AndCertificates)Loaded ?
QSslSocketPrivate::ensureInitialized();
#ifndef OPENSSL_NO_EC
const QByteArray curveNameLatin1 = name.toLatin1();
nid = q_OBJ_ln2nid(curveNameLatin1.data());
#endif
return nid;
}
QString QTlsBackendOpenSSL::shortNameForId(int id) const
{
QString result;
#ifndef OPENSSL_NO_EC
if (id != 0)
result = QString::fromLatin1(q_OBJ_nid2sn(id));
#endif
return result;
}
QString QTlsBackendOpenSSL::longNameForId(int id) const
{
QString result;
#ifndef OPENSSL_NO_EC
if (id != 0)
result = QString::fromLatin1(q_OBJ_nid2ln(id));
#endif
return result;
}
// 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
};
const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
bool QTlsBackendOpenSSL::isTlsNamedCurve(int id) const
{
const int *const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -53,6 +53,7 @@
#include <private/qtnetworkglobal_p.h> #include <private/qtnetworkglobal_p.h>
#include "qssldiffiehellmanparameters.h"
#include "qtlsbackend_p.h" #include "qtlsbackend_p.h"
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
@ -83,6 +84,19 @@ private:
QSsl::X509PemReaderPtr X509PemReader() const override; QSsl::X509PemReaderPtr X509PemReader() const override;
QSsl::X509DerReaderPtr X509DerReader() const override; QSsl::X509DerReaderPtr X509DerReader() const override;
QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override; QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override;
// Elliptic curves:
QList<int> ellipticCurvesIds() const override;
int curveIdFromShortName(const QString &name) const override;
int curveIdFromLongName(const QString &name) const override;
QString shortNameForId(int cid) const override;
QString longNameForId(int cid) const override;
bool isTlsNamedCurve(int cid) const override;
// DH parameters:
using DHParams = QSslDiffieHellmanParameters;
int dhParametersFromDer(const QByteArray &derData, QByteArray *data) const override;
int dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const override;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -68,7 +68,6 @@
#include <QtCore/qlist.h> #include <QtCore/qlist.h>
#include <QtCore/qmap.h> #include <QtCore/qmap.h>
#include <vector>
#include <memory> #include <memory>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -168,6 +167,11 @@ public:
virtual size_t hash(size_t seed) const noexcept = 0; virtual size_t hash(size_t seed) const noexcept = 0;
}; };
// TLSTODO: consider making those into virtuals in QTlsBackend. After all, we ask the backend
// to return those pointers if the functionality is supported, but it's a bit odd to have
// this level of indirection. They are not parts of the classes above because ...
// you'd then have to ask backend to create a certificate to ... call those
// functions on a certificate.
using X509ChainVerifyPtr = QList<QSslError> (*)(const QList<QSslCertificate> &chain, using X509ChainVerifyPtr = QList<QSslError> (*)(const QList<QSslCertificate> &chain,
const QString &hostName); const QString &hostName);
using X509PemReaderPtr = QList<QSslCertificate> (*)(const QByteArray &pem, int count); using X509PemReaderPtr = QList<QSslCertificate> (*)(const QByteArray &pem, int count);
@ -212,12 +216,26 @@ public:
virtual QSsl::DtlsCryptograph *createDtlsCryptograph() const; virtual QSsl::DtlsCryptograph *createDtlsCryptograph() const;
virtual QSsl::DtlsCookieVerifier *createDtlsCookieVerifier() const; virtual QSsl::DtlsCookieVerifier *createDtlsCookieVerifier() const;
// X509 machinery: // TLSTODO - get rid of these function pointers, make them virtuals in
// the backend itself. X509 machinery:
virtual QSsl::X509ChainVerifyPtr X509Verifier() const; virtual QSsl::X509ChainVerifyPtr X509Verifier() const;
virtual QSsl::X509PemReaderPtr X509PemReader() const; virtual QSsl::X509PemReaderPtr X509PemReader() const;
virtual QSsl::X509DerReaderPtr X509DerReader() const; virtual QSsl::X509DerReaderPtr X509DerReader() const;
virtual QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const; virtual QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const;
// Elliptic curves:
virtual QList<int> ellipticCurvesIds() const;
virtual int curveIdFromShortName(const QString &name) const;
virtual int curveIdFromLongName(const QString &name) const;
virtual QString shortNameForId(int cid) const;
virtual QString longNameForId(int cid) const;
virtual bool isTlsNamedCurve(int cid) const;
// TLSTODO: int->enum ugliness in error reporting.
// DH decoding:
virtual int dhParametersFromDer(const QByteArray &derData, QByteArray *data) const;
virtual int dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const;
static QList<QString> availableBackendNames(); static QList<QString> availableBackendNames();
static QString defaultBackendName(); static QString defaultBackendName();
static QTlsBackend *findBackend(const QString &backendName); static QTlsBackend *findBackend(const QString &backendName);