From ff76599b594d75c9f5a0d40ec598c8be355ba54f Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 23 Feb 2021 11:40:50 +0100 Subject: Convert elliptic curves and DH params to work with QTlsBackend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Fixes: QTBUG-91177 Fixes: QTBUG-91175 Task-number: QTBUG-65922 Change-Id: I44dd0adbdf2427962451998664efe234d59fae24 Reviewed-by: Edward Welbourne Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit cdf4976b5a01bc5b65aed746acc9cc7f87b0fd97) Reviewed-by: Timur Pocheptsov --- src/network/CMakeLists.txt | 5 - src/network/ssl/qssldiffiehellmanparameters.cpp | 26 ++- .../ssl/qssldiffiehellmanparameters_dummy.cpp | 57 ------- .../ssl/qssldiffiehellmanparameters_openssl.cpp | 90 ++++++----- src/network/ssl/qssldiffiehellmanparameters_p.h | 13 +- src/network/ssl/qsslellipticcurve.cpp | 60 +++++-- src/network/ssl/qsslellipticcurve_dummy.cpp | 71 --------- src/network/ssl/qsslellipticcurve_openssl.cpp | 177 --------------------- src/network/ssl/qsslsocket_openssl.cpp | 26 +-- src/network/ssl/qtlsbackend.cpp | 78 +++++++-- src/network/ssl/qtlsbackend_openssl.cpp | 129 +++++++++++++++ src/network/ssl/qtlsbackend_openssl_p.h | 14 ++ src/network/ssl/qtlsbackend_p.h | 22 ++- 13 files changed, 372 insertions(+), 396 deletions(-) delete mode 100644 src/network/ssl/qssldiffiehellmanparameters_dummy.cpp delete mode 100644 src/network/ssl/qsslellipticcurve_dummy.cpp delete mode 100644 src/network/ssl/qsslellipticcurve_openssl.cpp diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 254b3e6643..a260218a13 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -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 SOURCES - ssl/qssldiffiehellmanparameters_dummy.cpp - ssl/qsslellipticcurve_dummy.cpp ssl/qsslsocket_qt.cpp ssl/qsslsocket_schannel.cpp ssl/qsslsocket_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 SOURCES - ssl/qssldiffiehellmanparameters_dummy.cpp - ssl/qsslellipticcurve_dummy.cpp ssl/qsslsocket_mac.cpp ssl/qsslsocket_mac_p.h ssl/qsslsocket_mac_shared.cpp ssl/qsslsocket_qt.cpp @@ -367,7 +363,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ss SOURCES ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h ssl/qssldiffiehellmanparameters_openssl.cpp - ssl/qsslellipticcurve_openssl.cpp ssl/qsslsocket_openssl.cpp ssl/qsslsocket_openssl_p.h ssl/qsslsocket_openssl_symbols.cpp ssl/qsslsocket_openssl_symbols_p.h ssl/qtlskey_openssl.cpp ssl/qtlskey_openssl_p.h diff --git a/src/network/ssl/qssldiffiehellmanparameters.cpp b/src/network/ssl/qssldiffiehellmanparameters.cpp index e5574b2e09..bea0f26742 100644 --- a/src/network/ssl/qssldiffiehellmanparameters.cpp +++ b/src/network/ssl/qssldiffiehellmanparameters.cpp @@ -56,6 +56,7 @@ #include "qssldiffiehellmanparameters.h" #include "qssldiffiehellmanparameters_p.h" +#include "qtlsbackend_p.h" #include "qsslsocket.h" #include "qsslsocket_p.h" @@ -117,12 +118,15 @@ QSslDiffieHellmanParameters::QSslDiffieHellmanParameters() QSslDiffieHellmanParameters QSslDiffieHellmanParameters::fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat encoding) { QSslDiffieHellmanParameters result; + const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse(); + if (!tlsBackend) + return result; switch (encoding) { case QSsl::Der: - result.d->decodeDer(encoded); + result.d->initFromDer(encoded); break; case QSsl::Pem: - result.d->decodePem(encoded); + result.d->initFromPem(encoded); break; } return result; @@ -299,6 +303,24 @@ bool QSslDiffieHellmanParameters::isEqual(const QSslDiffieHellmanParameters &oth 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 /*! \since 5.8 diff --git a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp b/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp deleted file mode 100644 index 8fcf141f73..0000000000 --- a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Mikkel Krautz -** 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 -#include - -QT_BEGIN_NAMESPACE - -void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &) -{ -} - -void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &) -{ -} - -QT_END_NAMESPACE diff --git a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp index 05b3408b75..01dca50720 100644 --- a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp +++ b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp @@ -38,30 +38,25 @@ ** ****************************************************************************/ -#include "qssldiffiehellmanparameters.h" -#include "qssldiffiehellmanparameters_p.h" #include "qsslsocket_openssl_symbols_p.h" -#include "qsslsocket.h" +#include "qtlsbackend_openssl_p.h" #include "qsslsocket_p.h" -#include "private/qssl_p.h" - -#include +#include #include #include -#include -#ifndef QT_NO_DEBUG_STREAM #include -#endif #include #include QT_BEGIN_NAMESPACE +namespace { + #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 // 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 -static bool isSafeDH(DH *dh) +bool isSafeDH(DH *dh) { int status = 0; int bad = 0; + // TLSTODO: check it's needed or if supportsSsl() + // is enough. QSslSocketPrivate::ensureInitialized(); - // From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters: // // The additional call to BN_mod_word(dh->p, 24) @@ -154,71 +150,81 @@ static bool isSafeDH(DH *dh) return !(status & bad); } -void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &der) +} // unnamed namespace + +int QTlsBackendOpenSSL::dhParametersFromDer(const QByteArray &der, QByteArray *derData) const { - if (der.isEmpty()) { - error = QSslDiffieHellmanParameters::InvalidInputDataError; - return; - } + Q_ASSERT(derData); + + if (der.isEmpty()) + return DHParams::InvalidInputDataError; const unsigned char *data = reinterpret_cast(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(); DH *dh = q_d2i_DHparams(nullptr, &data, len); if (dh) { + const auto dhRaii = qScopeGuard([dh] {q_DH_free(dh);}); + if (isSafeDH(dh)) - derData = der; + *derData = der; else - error = QSslDiffieHellmanParameters::UnsafeParametersError; + return DHParams::UnsafeParametersError; } 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()) { - error = QSslDiffieHellmanParameters::InvalidInputDataError; - return; - } + Q_ASSERT(data); - if (!QSslSocket::supportsSsl()) { - error = QSslDiffieHellmanParameters::InvalidInputDataError; - return; - } + if (pem.isEmpty()) + return DHParams::InvalidInputDataError; + // TLSTODO: check it was not a cargo-cult programming in case of + // DH ... QSslSocketPrivate::ensureInitialized(); BIO *bio = q_BIO_new_mem_buf(const_cast(pem.data()), pem.size()); - if (!bio) { - error = QSslDiffieHellmanParameters::InvalidInputDataError; - return; - } + if (!bio) + return DHParams::InvalidInputDataError; + + const auto bioRaii = qScopeGuard([bio] + { + q_BIO_free(bio); + }); DH *dh = nullptr; q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr); if (dh) { + const auto dhGuard = qScopeGuard([dh] + { + q_DH_free(dh); + }); + if (isSafeDH(dh)) { char *buf = nullptr; - int len = q_i2d_DHparams(dh, reinterpret_cast(&buf)); + const int len = q_i2d_DHparams(dh, reinterpret_cast(&buf)); if (len > 0) - derData = QByteArray(buf, len); + *data = QByteArray(buf, len); else - error = QSslDiffieHellmanParameters::InvalidInputDataError; + return DHParams::InvalidInputDataError; } else { - error = QSslDiffieHellmanParameters::UnsafeParametersError; + return DHParams::UnsafeParametersError; } } else { - error = QSslDiffieHellmanParameters::InvalidInputDataError; + return DHParams::InvalidInputDataError; } - q_DH_free(dh); - q_BIO_free(bio); + return DHParams::NoError; } QT_END_NAMESPACE diff --git a/src/network/ssl/qssldiffiehellmanparameters_p.h b/src/network/ssl/qssldiffiehellmanparameters_p.h index 722c2e9cf0..6929d542cb 100644 --- a/src/network/ssl/qssldiffiehellmanparameters_p.h +++ b/src/network/ssl/qssldiffiehellmanparameters_p.h @@ -53,23 +53,20 @@ // #include -#include -#include "qsslkey.h" #include "qssldiffiehellmanparameters.h" -#include "qsslsocket_p.h" // includes wincrypt.h + +#include QT_BEGIN_NAMESPACE class QSslDiffieHellmanParametersPrivate : public QSharedData { public: - QSslDiffieHellmanParametersPrivate() : error(QSslDiffieHellmanParameters::NoError) {} - - void decodeDer(const QByteArray &der); - void decodePem(const QByteArray &pem); + void initFromDer(const QByteArray &der); + void initFromPem(const QByteArray &pem); - QSslDiffieHellmanParameters::Error error; + QSslDiffieHellmanParameters::Error error = QSslDiffieHellmanParameters::NoError; QByteArray derData; }; diff --git a/src/network/ssl/qsslellipticcurve.cpp b/src/network/ssl/qsslellipticcurve.cpp index 6bc5ee6286..7d1a911e67 100644 --- a/src/network/ssl/qsslellipticcurve.cpp +++ b/src/network/ssl/qsslellipticcurve.cpp @@ -38,6 +38,8 @@ ****************************************************************************/ #include "qsslellipticcurve.h" +#include "qtlsbackend_p.h" +#include "qsslsocket_p.h" #ifndef QT_NO_DEBUG_STREAM #include @@ -77,8 +79,6 @@ QT_BEGIN_NAMESPACE */ /*! - \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}), @@ -91,10 +91,19 @@ QT_BEGIN_NAMESPACE \sa shortName() */ +QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name) +{ + QSslEllipticCurve result; + if (name.isEmpty()) + return result; -/*! - \fn QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name) + if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) + result.id = tlsBackend->curveIdFromShortName(name); + return result; +} + +/*! 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 SSL implementation. @@ -105,24 +114,49 @@ QT_BEGIN_NAMESPACE \sa longName() */ +QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name) +{ + QSslEllipticCurve result; + if (name.isEmpty()) + return result; -/*! - \fn QString QSslEllipticCurve::shortName() const + if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) + result.id = tlsBackend->curveIdFromLongName(name); + + return result; +} +/*! Returns the conventional short name for this curve. If this curve is invalid, returns an empty string. \sa longName() */ +QString QSslEllipticCurve::shortName() const +{ + QString name; -/*! - \fn QString QSslEllipticCurve::longName() const + if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) + name = tlsBackend->shortNameForId(id); + return name; +} + +/*! Returns the conventional long name for this curve. If this curve is invalid, returns an empty string. \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 @@ -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 used in the key exchange when using an elliptic curve cipher with TLS; 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) diff --git a/src/network/ssl/qsslellipticcurve_dummy.cpp b/src/network/ssl/qsslellipticcurve_dummy.cpp deleted file mode 100644 index 1313e06875..0000000000 --- a/src/network/ssl/qsslellipticcurve_dummy.cpp +++ /dev/null @@ -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 diff --git a/src/network/ssl/qsslellipticcurve_openssl.cpp b/src/network/ssl/qsslellipticcurve_openssl.cpp deleted file mode 100644 index bb7ad66bd2..0000000000 --- a/src/network/ssl/qsslellipticcurve_openssl.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Governikus GmbH & Co. KG. -** Copyright (C) 2016 Richard J. Moore -** 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 -#include - -#include - -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 diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index fe59d6dab2..b9a8160e99 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -967,22 +967,22 @@ void QSslSocketPrivate::resetDefaultCiphers() void QSslSocketPrivate::resetDefaultEllipticCurves() { - QList curves; - -#ifndef OPENSSL_NO_EC - const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0); + // TLSTODO: this function to be be merged into qsslsocket.cpp + const auto *tlsBackend = tlsBackendInUse(); + if (!tlsBackend) + return; - QVarLengthArray builtinCurves(static_cast(curveCount)); + auto ids = tlsBackend->ellipticCurvesIds(); + if (!ids.size()) + return; - 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); - } + QList curves; + curves.reserve(ids.size()); + for (int id : ids) { + QSslEllipticCurve curve; + curve.id = id; + 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 diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp index dcffb0afd1..c367766801 100644 --- a/src/network/ssl/qtlsbackend.cpp +++ b/src/network/ssl/qtlsbackend.cpp @@ -229,60 +229,120 @@ QString QTlsBackend::backendName() const return QStringLiteral("dummyTLS"); } +#define REPORT_MISSING_SUPPORT(message) \ + qCWarning(lcSsl) << "The backend" << backendName() << message + QSsl::TlsKey *QTlsBackend::createKey() const { - qCWarning(lcSsl, "Dummy TLS backend, cannot generate a key"); + REPORT_MISSING_SUPPORT("does not support QSslKey"); return nullptr; } QSsl::X509Certificate *QTlsBackend::createCertificate() const { - qCWarning(lcSsl, "Dummy TLS backend, cannot create a certificate"); + REPORT_MISSING_SUPPORT("does not support QSslCertificate"); return nullptr; } QSsl::TlsCryptograph *QTlsBackend::createTlsCryptograph() const { - qCWarning(lcSsl, "Dummy TLS backend, cannot create TLS session"); + REPORT_MISSING_SUPPORT("does not support QSslSocket"); return nullptr; } QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph() const { - qCWarning(lcSsl, "Dummy TLS backend, cannot create DTLS session"); + REPORT_MISSING_SUPPORT("does not support QDtls"); return nullptr; } 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; } 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; } QSsl::X509PemReaderPtr QTlsBackend::X509PemReader() const { - qCWarning(lcSsl, "Dummy TLS backend, cannot read PEM format"); + REPORT_MISSING_SUPPORT("cannot read PEM format"); return nullptr; } 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; } QSsl::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const { - qCWarning(lcSsl, "Dummy TLS backend, cannot read PKCS12"); + REPORT_MISSING_SUPPORT("cannot read PKCS12 format"); return nullptr; } +QList 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 QTlsBackend::availableBackendNames() { if (!backends()) diff --git a/src/network/ssl/qtlsbackend_openssl.cpp b/src/network/ssl/qtlsbackend_openssl.cpp index e288498820..b3686e15fa 100644 --- a/src/network/ssl/qtlsbackend_openssl.cpp +++ b/src/network/ssl/qtlsbackend_openssl.cpp @@ -51,6 +51,8 @@ #include +#include + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl"); @@ -181,4 +183,131 @@ QSsl::X509Pkcs12ReaderPtr QTlsBackendOpenSSL::X509Pkcs12Reader() const return QSsl::X509CertificateOpenSSL::importPkcs12; } +QList QTlsBackendOpenSSL::ellipticCurvesIds() const +{ + QList ids; + +#ifndef OPENSSL_NO_EC + const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0); + QVarLengthArray builtinCurves(static_cast(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 diff --git a/src/network/ssl/qtlsbackend_openssl_p.h b/src/network/ssl/qtlsbackend_openssl_p.h index 478e4762c2..b3c2b733a5 100644 --- a/src/network/ssl/qtlsbackend_openssl_p.h +++ b/src/network/ssl/qtlsbackend_openssl_p.h @@ -53,6 +53,7 @@ #include +#include "qssldiffiehellmanparameters.h" #include "qtlsbackend_p.h" #include @@ -83,6 +84,19 @@ private: QSsl::X509PemReaderPtr X509PemReader() const override; QSsl::X509DerReaderPtr X509DerReader() const override; QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override; + + // Elliptic curves: + QList 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 diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h index d560288b5e..d91b3da548 100644 --- a/src/network/ssl/qtlsbackend_p.h +++ b/src/network/ssl/qtlsbackend_p.h @@ -68,7 +68,6 @@ #include #include -#include #include QT_BEGIN_NAMESPACE @@ -168,6 +167,11 @@ public: 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 (*)(const QList &chain, const QString &hostName); using X509PemReaderPtr = QList (*)(const QByteArray &pem, int count); @@ -212,12 +216,26 @@ public: virtual QSsl::DtlsCryptograph *createDtlsCryptograph() 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::X509PemReaderPtr X509PemReader() const; virtual QSsl::X509DerReaderPtr X509DerReader() const; virtual QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const; + // Elliptic curves: + virtual QList 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 availableBackendNames(); static QString defaultBackendName(); static QTlsBackend *findBackend(const QString &backendName); -- cgit v1.2.3