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

View File

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

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.h"
#include "qtlsbackend_openssl_p.h"
#include "qsslsocket_p.h"
#include "private/qssl_p.h"
#include <QtCore/qatomic.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qscopeguard.h>
#ifndef QT_NO_DEBUG_STREAM
#include <QtCore/qdebug.h>
#endif
#include <openssl/bn.h>
#include <openssl/dh.h>
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<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();
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<char *>(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<unsigned char **>(&buf));
const int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&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

View File

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

View File

@ -38,6 +38,8 @@
****************************************************************************/
#include "qsslellipticcurve.h"
#include "qtlsbackend_p.h"
#include "qsslsocket_p.h"
#ifndef QT_NO_DEBUG_STREAM
#include <QDebug>
@ -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;
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.
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;
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
curve is invalid, returns an empty string.
\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
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)

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()
{
// 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;
#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) {
curves.reserve(int(curveCount));
for (size_t i = 0; i < curveCount; ++i) {
curves.reserve(ids.size());
for (int id : ids) {
QSslEllipticCurve curve;
curve.id = builtinCurves[int(i)].nid;
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

View File

@ -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<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()
{
if (!backends())

View File

@ -51,6 +51,8 @@
#include <qlist.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl");
@ -181,4 +183,131 @@ QSsl::X509Pkcs12ReaderPtr QTlsBackendOpenSSL::X509Pkcs12Reader() const
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

View File

@ -53,6 +53,7 @@
#include <private/qtnetworkglobal_p.h>
#include "qssldiffiehellmanparameters.h"
#include "qtlsbackend_p.h"
#include <QtCore/qglobal.h>
@ -83,6 +84,19 @@ private:
QSsl::X509PemReaderPtr X509PemReader() const override;
QSsl::X509DerReaderPtr X509DerReader() 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

View File

@ -68,7 +68,6 @@
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <vector>
#include <memory>
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<QSslError> (*)(const QList<QSslCertificate> &chain,
const QString &hostName);
using X509PemReaderPtr = QList<QSslCertificate> (*)(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<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 QString defaultBackendName();
static QTlsBackend *findBackend(const QString &backendName);