Introduce QSsl::X509Certificate interface and its implementations
To enable QSslCertificate to use TLS plugins. All backend-specific code is to be moved from QSslCertificate(Private) making them backend-neutral. Pick-to: dev Task-number: QTBUG-90954 Task-number: QTBUG-65922 Change-Id: Ic9d5abf91e42ce81fe56239f95ae97b64035e950 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
137f5518b8
commit
405337ee72
@ -328,6 +328,7 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
|
||||
ssl/qsslsocket.cpp ssl/qsslsocket.h ssl/qsslsocket_p.h
|
||||
ssl/qtlsbackend.cpp ssl/qtlsbackend_p.h
|
||||
ssl/qtlskey_base.cpp ssl/qtlskey_base_p.h
|
||||
ssl/qx509_base.cpp ssl/qx509_base_p.h
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
|
||||
@ -339,8 +340,11 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_s
|
||||
ssl/qsslkey_schannel.cpp
|
||||
ssl/qsslsocket_qt.cpp
|
||||
ssl/qsslsocket_schannel.cpp ssl/qsslsocket_schannel_p.h
|
||||
ssl/qtlsbackend_schannel_p.h
|
||||
ssl/qtlskey_generic.cpp ssl/qtlskey_generic_p.h
|
||||
ssl/qtlskey_schannel.cpp ssl/qtlskey_schannel_p.h
|
||||
ssl/qx509_generic.cpp ssl/qx509_generic_p.h
|
||||
ssl/qx509_schannel.cpp ssl/qx509_schannel_p.h
|
||||
LIBRARIES
|
||||
Crypt32
|
||||
Secur32
|
||||
@ -359,6 +363,9 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FE
|
||||
ssl/qsslsocket_qt.cpp
|
||||
ssl/qtlskey_generic.cpp ssl/qtlskey_generic_p.h
|
||||
ssl/qtlskey_st.cpp ssl/qtlskey_st_p.h
|
||||
ssl/qtlsbackend_st.cpp ssl/qtlsbackend_st_p.h
|
||||
ssl/qx509_generic.cpp ssl/qx509_generic_p.h
|
||||
ssl/qx509_st.cpp ssl/qx509_st_p.h
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_ssl
|
||||
@ -376,6 +383,8 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ss
|
||||
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
|
||||
ssl/qtlsbackend_openssl.cpp ssl/qtlsbackend_openssl_p.h
|
||||
ssl/qx509_openssl.cpp ssl/qx509_openssl_p.h
|
||||
DEFINES
|
||||
OPENSSL_API_COMPAT=0x10100000L
|
||||
)
|
||||
|
@ -66,6 +66,12 @@ class QSslCertificate;
|
||||
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
|
||||
Q_NETWORK_EXPORT size_t qHash(const QSslCertificate &key, size_t seed = 0) noexcept;
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
class X509Certificate;
|
||||
|
||||
} // namespace QSsl.
|
||||
|
||||
class QSslCertificatePrivate;
|
||||
class Q_NETWORK_EXPORT QSslCertificate
|
||||
{
|
||||
@ -157,9 +163,14 @@ public:
|
||||
Qt::HANDLE handle() const;
|
||||
|
||||
private:
|
||||
QSsl::X509Certificate *backendImplementation() const
|
||||
{
|
||||
return nullptr; // TLSTODO
|
||||
}
|
||||
QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
|
||||
friend class QSslCertificatePrivate;
|
||||
friend class QSslSocketBackendPrivate;
|
||||
friend class QTlsBackend;
|
||||
|
||||
friend Q_NETWORK_EXPORT size_t qHash(const QSslCertificate &key, size_t seed) noexcept;
|
||||
};
|
||||
|
@ -44,7 +44,7 @@
|
||||
#include "qsslsocket_mac_p.h"
|
||||
#include "qasn1element_p.h"
|
||||
#include "qsslcertificate_p.h"
|
||||
#include "qtlsbackend_p.h"
|
||||
#include "qtlsbackend_st_p.h"
|
||||
#include "qsslcipher_p.h"
|
||||
#include "qtlskey_st_p.h"
|
||||
#include "qsslkey_p.h"
|
||||
@ -75,59 +75,9 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace
|
||||
{
|
||||
Q_GLOBAL_STATIC(QSecureTransportBackend, backend)
|
||||
|
||||
// These two classes are ad-hoc temporary solution, to be replaced
|
||||
// by the real things soon.
|
||||
class SecureTransportBackend : public QTlsBackend
|
||||
{
|
||||
private:
|
||||
QString backendName() const override
|
||||
{
|
||||
return builtinBackendNames[nameIndexSecureTransport];
|
||||
}
|
||||
QSsl::TlsKey *createKey() const override
|
||||
{
|
||||
return new QSsl::TlsKeySecureTransport;
|
||||
}
|
||||
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override
|
||||
{
|
||||
QList<QSsl::SslProtocol> protocols;
|
||||
|
||||
protocols << QSsl::AnyProtocol;
|
||||
protocols << QSsl::SecureProtocols;
|
||||
protocols << QSsl::TlsV1_0;
|
||||
protocols << QSsl::TlsV1_0OrLater;
|
||||
protocols << QSsl::TlsV1_1;
|
||||
protocols << QSsl::TlsV1_1OrLater;
|
||||
protocols << QSsl::TlsV1_2;
|
||||
protocols << QSsl::TlsV1_2OrLater;
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override
|
||||
{
|
||||
QList<QSsl::SupportedFeature> features;
|
||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
QList<QSsl::ImplementedClass> implementedClasses() const override
|
||||
{
|
||||
QList<QSsl::ImplementedClass> classes;
|
||||
classes << QSsl::ImplementedClass::Socket;
|
||||
classes << QSsl::ImplementedClass::Certificate;
|
||||
classes << QSsl::ImplementedClass::Key;
|
||||
|
||||
return classes;
|
||||
}
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(SecureTransportBackend, backend)
|
||||
namespace {
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
/*
|
||||
|
@ -67,7 +67,7 @@
|
||||
#include "qsslpresharedkeyauthenticator_p.h"
|
||||
#include "qocspresponse_p.h"
|
||||
#include "qsslkey.h"
|
||||
#include "qtlsbackend_p.h"
|
||||
#include "qtlsbackend_openssl_p.h"
|
||||
#include "qtlskey_openssl_p.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
@ -101,80 +101,9 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace {
|
||||
Q_GLOBAL_STATIC(QTlsBackendOpenSSL, backend)
|
||||
|
||||
// These two classes are ad-hoc temporary solution, to be replaced
|
||||
// by the real things soon.
|
||||
class OpenSSLBackend : public QTlsBackend
|
||||
{
|
||||
private:
|
||||
QString backendName() const override
|
||||
{
|
||||
return builtinBackendNames[nameIndexOpenSSL];
|
||||
}
|
||||
QSsl::TlsKey *createKey() const override
|
||||
{
|
||||
return new QSsl::TlsKeyOpenSSL;
|
||||
}
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override
|
||||
{
|
||||
QList<QSsl::SslProtocol> protocols;
|
||||
|
||||
protocols << QSsl::AnyProtocol;
|
||||
protocols << QSsl::SecureProtocols;
|
||||
protocols << QSsl::TlsV1_0;
|
||||
protocols << QSsl::TlsV1_0OrLater;
|
||||
protocols << QSsl::TlsV1_1;
|
||||
protocols << QSsl::TlsV1_1OrLater;
|
||||
protocols << QSsl::TlsV1_2;
|
||||
protocols << QSsl::TlsV1_2OrLater;
|
||||
|
||||
#ifdef TLS1_3_VERSION
|
||||
protocols << QSsl::TlsV1_3;
|
||||
protocols << QSsl::TlsV1_3OrLater;
|
||||
#endif // TLS1_3_VERSION
|
||||
|
||||
#if QT_CONFIG(dtls)
|
||||
protocols << QSsl::DtlsV1_0;
|
||||
protocols << QSsl::DtlsV1_0OrLater;
|
||||
protocols << QSsl::DtlsV1_2;
|
||||
protocols << QSsl::DtlsV1_2OrLater;
|
||||
#endif // dtls
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override
|
||||
{
|
||||
QList<QSsl::SupportedFeature> features;
|
||||
|
||||
features << QSsl::SupportedFeature::CertificateVerification;
|
||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||
features << QSsl::SupportedFeature::ServerSideAlpn;
|
||||
features << QSsl::SupportedFeature::Ocsp;
|
||||
features << QSsl::SupportedFeature::Psk;
|
||||
features << QSsl::SupportedFeature::SessionTicket;
|
||||
features << QSsl::SupportedFeature::Alerts;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
QList<QSsl::ImplementedClass> implementedClasses() const override
|
||||
{
|
||||
QList<QSsl::ImplementedClass> classes;
|
||||
|
||||
classes << QSsl::ImplementedClass::Key;
|
||||
classes << QSsl::ImplementedClass::Certificate;
|
||||
classes << QSsl::ImplementedClass::Socket;
|
||||
classes << QSsl::ImplementedClass::Dtls;
|
||||
classes << QSsl::ImplementedClass::EllipticCurve;
|
||||
classes << QSsl::ImplementedClass::DiffieHellman;
|
||||
|
||||
return classes;
|
||||
}
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(OpenSSLBackend, backend)
|
||||
namespace {
|
||||
|
||||
QSsl::AlertLevel tlsAlertLevel(int value)
|
||||
{
|
||||
|
@ -46,8 +46,9 @@
|
||||
#include "qsslcertificateextension.h"
|
||||
#include "qsslcertificate_p.h"
|
||||
#include "qsslcipher_p.h"
|
||||
#include "qtlsbackend_p.h"
|
||||
#include "qtlsbackend_schannel_p.h"
|
||||
#include "qtlskey_schannel_p.h"
|
||||
#include "qx509_schannel_p.h"
|
||||
|
||||
#include <QtCore/qscopeguard.h>
|
||||
#include <QtCore/qoperatingsystemversion.h>
|
||||
@ -159,65 +160,79 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
bool supportsTls13();
|
||||
class SchannelBackend : public QTlsBackend
|
||||
}
|
||||
|
||||
QString QSchannelBackend::backendName() const
|
||||
{
|
||||
private:
|
||||
QString backendName() const override
|
||||
{
|
||||
return builtinBackendNames[nameIndexSchannel];
|
||||
return builtinBackendNames[nameIndexSchannel];
|
||||
}
|
||||
|
||||
QList<QSsl::SslProtocol> QSchannelBackend::supportedProtocols() const
|
||||
{
|
||||
QList<QSsl::SslProtocol> protocols;
|
||||
|
||||
protocols << QSsl::AnyProtocol;
|
||||
protocols << QSsl::SecureProtocols;
|
||||
protocols << QSsl::TlsV1_0;
|
||||
protocols << QSsl::TlsV1_0OrLater;
|
||||
protocols << QSsl::TlsV1_1;
|
||||
protocols << QSsl::TlsV1_1OrLater;
|
||||
protocols << QSsl::TlsV1_2;
|
||||
protocols << QSsl::TlsV1_2OrLater;
|
||||
|
||||
if (supportsTls13()) {
|
||||
protocols << QSsl::TlsV1_3;
|
||||
protocols << QSsl::TlsV1_3OrLater;
|
||||
}
|
||||
|
||||
QSsl::TlsKey *createKey() const override
|
||||
{
|
||||
return new QSsl::TlsKeySchannel;
|
||||
}
|
||||
return protocols;
|
||||
}
|
||||
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override
|
||||
{
|
||||
QList<QSsl::SslProtocol> protocols;
|
||||
QList<QSsl::SupportedFeature> QSchannelBackend::supportedFeatures() const
|
||||
{
|
||||
QList<QSsl::SupportedFeature> features;
|
||||
|
||||
protocols << QSsl::AnyProtocol;
|
||||
protocols << QSsl::SecureProtocols;
|
||||
protocols << QSsl::TlsV1_0;
|
||||
protocols << QSsl::TlsV1_0OrLater;
|
||||
protocols << QSsl::TlsV1_1;
|
||||
protocols << QSsl::TlsV1_1OrLater;
|
||||
protocols << QSsl::TlsV1_2;
|
||||
protocols << QSsl::TlsV1_2OrLater;
|
||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||
features << QSsl::SupportedFeature::ServerSideAlpn;
|
||||
|
||||
if (supportsTls13()) {
|
||||
protocols << QSsl::TlsV1_3;
|
||||
protocols << QSsl::TlsV1_3OrLater;
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
return protocols;
|
||||
}
|
||||
QList<QSsl::ImplementedClass> QSchannelBackend::implementedClasses() const
|
||||
{
|
||||
QList<QSsl::ImplementedClass> classes;
|
||||
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override
|
||||
{
|
||||
QList<QSsl::SupportedFeature> features;
|
||||
classes << QSsl::ImplementedClass::Socket;
|
||||
classes << QSsl::ImplementedClass::Certificate;
|
||||
classes << QSsl::ImplementedClass::Key;
|
||||
|
||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||
features << QSsl::SupportedFeature::ServerSideAlpn;
|
||||
return classes;
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
QSsl::TlsKey *QSchannelBackend::createKey() const
|
||||
{
|
||||
return new QSsl::TlsKeySchannel;
|
||||
}
|
||||
|
||||
QList<QSsl::ImplementedClass> implementedClasses() const override
|
||||
{
|
||||
QList<QSsl::ImplementedClass> classes;
|
||||
QSsl::X509Certificate *QSchannelBackend::createCertificate() const
|
||||
{
|
||||
return new QSsl::X509CertificateSchannel;
|
||||
}
|
||||
|
||||
classes << QSsl::ImplementedClass::Socket;
|
||||
classes << QSsl::ImplementedClass::Certificate;
|
||||
classes << QSsl::ImplementedClass::Key;
|
||||
QSsl::X509PemReaderPtr QSchannelBackend::X509PemReader() const
|
||||
{
|
||||
return QSsl::X509CertificateGeneric::certificatesFromPem;
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
};
|
||||
QSsl::X509DerReaderPtr QSchannelBackend::X509DerReader() const
|
||||
{
|
||||
return QSsl::X509CertificateGeneric::certificatesFromDer;
|
||||
}
|
||||
|
||||
Q_GLOBAL_STATIC(SchannelBackend, backend)
|
||||
Q_GLOBAL_STATIC(QSchannelBackend, backend)
|
||||
|
||||
namespace {
|
||||
|
||||
SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
|
||||
{
|
||||
|
@ -176,6 +176,7 @@ QByteArray TlsKey::pemFooter() const
|
||||
return {};
|
||||
}
|
||||
|
||||
X509Certificate::~X509Certificate() = default;
|
||||
|
||||
} // namespace QSsl
|
||||
|
||||
|
173
src/network/ssl/qtlsbackend_openssl.cpp
Normal file
173
src/network/ssl/qtlsbackend_openssl.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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 "qtlsbackend_openssl_p.h"
|
||||
#include "qtlskey_openssl_p.h"
|
||||
#include "qx509_openssl_p.h"
|
||||
|
||||
#include "qsslsocket_openssl_symbols_p.h"
|
||||
|
||||
#include <qssl.h>
|
||||
|
||||
#include <qlist.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl");
|
||||
|
||||
QString QTlsBackendOpenSSL::getErrorsFromOpenSsl()
|
||||
{
|
||||
QString errorString;
|
||||
char buf[256] = {}; // OpenSSL docs claim both 120 and 256; use the larger.
|
||||
unsigned long errNum;
|
||||
while ((errNum = q_ERR_get_error())) {
|
||||
if (!errorString.isEmpty())
|
||||
errorString.append(QLatin1String(", "));
|
||||
q_ERR_error_string_n(errNum, buf, sizeof buf);
|
||||
errorString.append(QString::fromLatin1(buf)); // error is ascii according to man ERR_error_string
|
||||
}
|
||||
return errorString;
|
||||
}
|
||||
|
||||
void QTlsBackendOpenSSL::logAndClearErrorQueue()
|
||||
{
|
||||
const auto errors = getErrorsFromOpenSsl();
|
||||
if (errors.size())
|
||||
qCWarning(lcTlsBackend) << "Discarding errors:" << errors;
|
||||
}
|
||||
|
||||
void QTlsBackendOpenSSL::clearErrorQueue()
|
||||
{
|
||||
const auto errs = getErrorsFromOpenSsl();
|
||||
Q_UNUSED(errs);
|
||||
}
|
||||
|
||||
QString QTlsBackendOpenSSL::backendName() const
|
||||
{
|
||||
return builtinBackendNames[nameIndexOpenSSL];
|
||||
}
|
||||
|
||||
QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
|
||||
{
|
||||
QList<QSsl::SslProtocol> protocols;
|
||||
|
||||
protocols << QSsl::AnyProtocol;
|
||||
protocols << QSsl::SecureProtocols;
|
||||
protocols << QSsl::TlsV1_0;
|
||||
protocols << QSsl::TlsV1_0OrLater;
|
||||
protocols << QSsl::TlsV1_1;
|
||||
protocols << QSsl::TlsV1_1OrLater;
|
||||
protocols << QSsl::TlsV1_2;
|
||||
protocols << QSsl::TlsV1_2OrLater;
|
||||
|
||||
#ifdef TLS1_3_VERSION
|
||||
protocols << QSsl::TlsV1_3;
|
||||
protocols << QSsl::TlsV1_3OrLater;
|
||||
#endif // TLS1_3_VERSION
|
||||
|
||||
#if QT_CONFIG(dtls)
|
||||
protocols << QSsl::DtlsV1_0;
|
||||
protocols << QSsl::DtlsV1_0OrLater;
|
||||
protocols << QSsl::DtlsV1_2;
|
||||
protocols << QSsl::DtlsV1_2OrLater;
|
||||
#endif // dtls
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
QList<QSsl::SupportedFeature> QTlsBackendOpenSSL::supportedFeatures() const
|
||||
{
|
||||
QList<QSsl::SupportedFeature> features;
|
||||
|
||||
features << QSsl::SupportedFeature::CertificateVerification;
|
||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||
features << QSsl::SupportedFeature::ServerSideAlpn;
|
||||
features << QSsl::SupportedFeature::Ocsp;
|
||||
features << QSsl::SupportedFeature::Psk;
|
||||
features << QSsl::SupportedFeature::SessionTicket;
|
||||
features << QSsl::SupportedFeature::Alerts;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
QList<QSsl::ImplementedClass> QTlsBackendOpenSSL::implementedClasses() const
|
||||
{
|
||||
QList<QSsl::ImplementedClass> classes;
|
||||
|
||||
classes << QSsl::ImplementedClass::Key;
|
||||
classes << QSsl::ImplementedClass::Certificate;
|
||||
classes << QSsl::ImplementedClass::Socket;
|
||||
classes << QSsl::ImplementedClass::Dtls;
|
||||
classes << QSsl::ImplementedClass::EllipticCurve;
|
||||
classes << QSsl::ImplementedClass::DiffieHellman;
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
QSsl::TlsKey *QTlsBackendOpenSSL::createKey() const
|
||||
{
|
||||
return new QSsl::TlsKeyOpenSSL;
|
||||
}
|
||||
|
||||
QSsl::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
|
||||
{
|
||||
return new QSsl::X509CertificateOpenSSL;
|
||||
}
|
||||
|
||||
QSsl::X509ChainVerifyPtr QTlsBackendOpenSSL::X509Verifier() const
|
||||
{
|
||||
return QSsl::X509CertificateOpenSSL::verify;
|
||||
}
|
||||
|
||||
QSsl::X509PemReaderPtr QTlsBackendOpenSSL::X509PemReader() const
|
||||
{
|
||||
return QSsl::X509CertificateOpenSSL::certificatesFromPem;
|
||||
}
|
||||
|
||||
QSsl::X509DerReaderPtr QTlsBackendOpenSSL::X509DerReader() const
|
||||
{
|
||||
return QSsl::X509CertificateOpenSSL::certificatesFromDer;
|
||||
}
|
||||
|
||||
QSsl::X509Pkcs12ReaderPtr QTlsBackendOpenSSL::X509Pkcs12Reader() const
|
||||
{
|
||||
return QSsl::X509CertificateOpenSSL::importPkcs12;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
91
src/network/ssl/qtlsbackend_openssl_p.h
Normal file
91
src/network/ssl/qtlsbackend_openssl_p.h
Normal file
@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTLSBACKEND_OPENSSL_P_H
|
||||
#define QTLSBACKEND_OPENSSL_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include "qtlsbackend_p.h"
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QTlsBackendOpenSSL final : public QTlsBackend
|
||||
{
|
||||
public:
|
||||
static QString getErrorsFromOpenSsl();
|
||||
static void logAndClearErrorQueue();
|
||||
static void clearErrorQueue();
|
||||
private:
|
||||
QString backendName() const override;
|
||||
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
||||
QList<QSsl::ImplementedClass> implementedClasses() const override;
|
||||
|
||||
// QSslKey:
|
||||
QSsl::TlsKey *createKey() const override;
|
||||
|
||||
// QSslCertificate:
|
||||
QSsl::X509Certificate *createCertificate() const override;
|
||||
QSsl::X509ChainVerifyPtr X509Verifier() const override;
|
||||
QSsl::X509PemReaderPtr X509PemReader() const override;
|
||||
QSsl::X509DerReaderPtr X509DerReader() const override;
|
||||
QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QTLSBACKEND_OPENSSL_P_H
|
||||
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include <QtNetwork/qsslkey.h>
|
||||
#include <QtNetwork/qssl.h>
|
||||
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qnamespace.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
@ -123,12 +124,48 @@ public:
|
||||
QByteArray pemFooter() const;
|
||||
};
|
||||
|
||||
// Abstraction above OpenSSL's X509, or our generic
|
||||
// An abstraction hiding OpenSSL's X509 or our generic
|
||||
// 'derData'-based code.
|
||||
class X509Certificate;
|
||||
class X509Certificate
|
||||
{
|
||||
public:
|
||||
virtual ~X509Certificate();
|
||||
|
||||
virtual bool isEqual(const X509Certificate &rhs) const = 0;
|
||||
virtual bool isNull() const = 0;
|
||||
virtual bool isSelfSigned() const = 0;
|
||||
virtual QByteArray version() const = 0;
|
||||
virtual QByteArray serialNumber() const = 0;
|
||||
virtual QStringList issuerInfo(QSslCertificate::SubjectInfo info) const = 0;
|
||||
virtual QStringList issuerInfo(const QByteArray &attribute) const = 0;
|
||||
virtual QStringList subjectInfo(QSslCertificate::SubjectInfo info) const = 0;
|
||||
virtual QStringList subjectInfo(const QByteArray &attribute) const = 0;
|
||||
|
||||
virtual QList<QByteArray> subjectInfoAttributes() const = 0;
|
||||
virtual QList<QByteArray> issuerInfoAttributes() const = 0;
|
||||
virtual QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const = 0;
|
||||
virtual QDateTime effectiveDate() const = 0;
|
||||
virtual QDateTime expiryDate() const = 0;
|
||||
virtual TlsKey *publicKey() const = 0;
|
||||
|
||||
// Extensions. Plugins do not expose internal representation
|
||||
// and cannot rely on QSslCertificate's internals.
|
||||
virtual qsizetype numberOfExtensions() const = 0;
|
||||
virtual QString oidForExtension(qsizetype index) const = 0;
|
||||
virtual QString nameForExtension(qsizetype index) const = 0;
|
||||
virtual QVariant valueForExtension(qsizetype index) const = 0;
|
||||
virtual bool isExtensionCritical(qsizetype index) const = 0;
|
||||
virtual bool isExtensionSupported(qsizetype index) const = 0;
|
||||
|
||||
virtual QByteArray toPem() const = 0;
|
||||
virtual QByteArray toDer() const = 0;
|
||||
virtual QString toText() const = 0;
|
||||
|
||||
virtual Qt::HANDLE handle() const = 0;
|
||||
|
||||
virtual size_t hash(size_t seed) const noexcept = 0;
|
||||
};
|
||||
|
||||
// X509-related auxiliary functions, previously static
|
||||
// member-functions in different classes.
|
||||
using X509ChainVerifyPtr = QList<QSslError> (*)(const QList<QSslCertificate> &chain,
|
||||
const QString &hostName);
|
||||
using X509PemReaderPtr = QList<QSslCertificate> (*)(const QByteArray &pem, int count);
|
||||
@ -201,6 +238,8 @@ public:
|
||||
Q_DISABLE_COPY_MOVE(QTlsBackend)
|
||||
};
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcTlsBackend)
|
||||
|
||||
#define QTlsBackend_iid "org.qt-project.Qt.QTlsBackend"
|
||||
Q_DECLARE_INTERFACE(QTlsBackend, QTlsBackend_iid);
|
||||
|
||||
|
82
src/network/ssl/qtlsbackend_schannel_p.h
Normal file
82
src/network/ssl/qtlsbackend_schannel_p.h
Normal file
@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTLSBACKEND_ST_P_H
|
||||
#define QTLSBACKEND_ST_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include "qtlsbackend_p.h"
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSchannelBackend : public QTlsBackend
|
||||
{
|
||||
private:
|
||||
QString backendName() const override;
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
||||
QList<QSsl::ImplementedClass> implementedClasses() const override;
|
||||
|
||||
QSsl::TlsKey *createKey() const override;
|
||||
QSsl::X509Certificate *createCertificate() const override;
|
||||
|
||||
QSsl::X509PemReaderPtr X509PemReader() const override;
|
||||
QSsl::X509DerReaderPtr X509DerReader() const override;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QTLSBACKEND_ST_P_H
|
||||
|
||||
|
108
src/network/ssl/qtlsbackend_st.cpp
Normal file
108
src/network/ssl/qtlsbackend_st.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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 "qtlsbackend_st_p.h"
|
||||
#include "qtlskey_st_p.h"
|
||||
#include "qx509_st_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.securetransport");
|
||||
|
||||
QString QSecureTransportBackend::backendName() const
|
||||
{
|
||||
return builtinBackendNames[nameIndexSecureTransport];
|
||||
}
|
||||
|
||||
QSsl::TlsKey *QSecureTransportBackend::createKey() const
|
||||
{
|
||||
return new QSsl::TlsKeySecureTransport;
|
||||
}
|
||||
|
||||
QSsl::X509Certificate *QSecureTransportBackend::createCertificate() const
|
||||
{
|
||||
return new QSsl::X509CertificateSecureTransport;
|
||||
}
|
||||
|
||||
QList<QSsl::SslProtocol> QSecureTransportBackend::supportedProtocols() const
|
||||
{
|
||||
QList<QSsl::SslProtocol> protocols;
|
||||
|
||||
protocols << QSsl::AnyProtocol;
|
||||
protocols << QSsl::SecureProtocols;
|
||||
protocols << QSsl::TlsV1_0;
|
||||
protocols << QSsl::TlsV1_0OrLater;
|
||||
protocols << QSsl::TlsV1_1;
|
||||
protocols << QSsl::TlsV1_1OrLater;
|
||||
protocols << QSsl::TlsV1_2;
|
||||
protocols << QSsl::TlsV1_2OrLater;
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
QList<QSsl::SupportedFeature> QSecureTransportBackend::supportedFeatures() const
|
||||
{
|
||||
QList<QSsl::SupportedFeature> features;
|
||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
QList<QSsl::ImplementedClass> QSecureTransportBackend::implementedClasses() const
|
||||
{
|
||||
QList<QSsl::ImplementedClass> classes;
|
||||
classes << QSsl::ImplementedClass::Socket;
|
||||
classes << QSsl::ImplementedClass::Certificate;
|
||||
classes << QSsl::ImplementedClass::Key;
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
QSsl::X509PemReaderPtr QSecureTransportBackend::X509PemReader() const
|
||||
{
|
||||
return QSsl::X509CertificateGeneric::certificatesFromPem;
|
||||
}
|
||||
|
||||
QSsl::X509DerReaderPtr QSecureTransportBackend::X509DerReader() const
|
||||
{
|
||||
return QSsl::X509CertificateGeneric::certificatesFromDer;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
83
src/network/ssl/qtlsbackend_st_p.h
Normal file
83
src/network/ssl/qtlsbackend_st_p.h
Normal file
@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTLSBACKEND_ST_P_H
|
||||
#define QTLSBACKEND_ST_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include "qtlsbackend_p.h"
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSecureTransportBackend : public QTlsBackend
|
||||
{
|
||||
private:
|
||||
QString backendName() const override;
|
||||
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
||||
QList<QSsl::ImplementedClass> implementedClasses() const override;
|
||||
|
||||
QSsl::TlsKey *createKey() const override;
|
||||
QSsl::X509Certificate *createCertificate() const override;
|
||||
|
||||
QSsl::X509PemReaderPtr X509PemReader() const override;
|
||||
QSsl::X509DerReaderPtr X509DerReader() const override;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QTLSBACKEND_ST_P_H
|
||||
|
||||
|
@ -68,6 +68,12 @@ namespace QSsl {
|
||||
class TlsKeyBase : public TlsKey
|
||||
{
|
||||
public:
|
||||
TlsKeyBase(KeyType type = PublicKey, KeyAlgorithm algorithm = Opaque)
|
||||
: keyType(type),
|
||||
keyAlgorithm(algorithm)
|
||||
{
|
||||
}
|
||||
|
||||
bool isNull() const override
|
||||
{
|
||||
return keyIsNull;
|
||||
@ -93,8 +99,8 @@ protected:
|
||||
static bool isEncryptedPkcs8(const QByteArray &der);
|
||||
|
||||
bool keyIsNull = true;
|
||||
QSsl::KeyType keyType = QSsl::PublicKey;
|
||||
QSsl::KeyAlgorithm keyAlgorithm = QSsl::Opaque;
|
||||
KeyType keyType = PublicKey;
|
||||
KeyAlgorithm keyAlgorithm = Opaque;
|
||||
};
|
||||
|
||||
} // namespace QSsl
|
||||
|
@ -73,10 +73,11 @@ namespace QSsl {
|
||||
class TlsKeyGeneric : public TlsKeyBase
|
||||
{
|
||||
public:
|
||||
TlsKeyGeneric()
|
||||
TlsKeyGeneric(KeyType type = PublicKey, KeyAlgorithm algorithm = Opaque)
|
||||
: TlsKeyBase(type, algorithm)
|
||||
{
|
||||
// Note, while clear is pure-virtual, the final-overrider
|
||||
// in this class is sufficient. Same for d-tor below.
|
||||
// Note, while clear is pure-virtual in the base class,
|
||||
// the final-overrider in this class is sufficient.
|
||||
clear(false);
|
||||
}
|
||||
~TlsKeyGeneric()
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include "qssl_p.h"
|
||||
#include "qtlskey_schannel_p.h"
|
||||
#include "qtlsbackend_p.h"
|
||||
#include "qsslkey_p.h"
|
||||
#include "qsslkey.h"
|
||||
|
||||
@ -77,8 +78,7 @@ BCRYPT_ALG_HANDLE getHandle(QSslKeyPrivate::Cipher cipher)
|
||||
0 // dwFlags
|
||||
);
|
||||
if (status < 0) {
|
||||
// TLSTODO:
|
||||
//qCWarning(lcSChannel, "Failed to open algorithm handle (%ld)!", status);
|
||||
qCWarning(lcTlsBackend, "Failed to open algorithm handle (%ld)!", status);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -99,8 +99,7 @@ BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
|
||||
0 // dwFlags
|
||||
);
|
||||
if (status < 0) {
|
||||
// TLSTODO - category
|
||||
//qCWarning(lcSChannel, "Failed to generate symmetric key (%ld)!", status);
|
||||
qCWarning(lcTlsBackend, "Failed to generate symmetric key (%ld)!", status);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -113,8 +112,7 @@ BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
|
||||
);
|
||||
if (status < 0) {
|
||||
BCryptDestroyKey(keyHandle);
|
||||
// TLSTODO: category
|
||||
//qCWarning(lcSChannel, "Failed to change the symmetric key's chaining mode (%ld)!", status);
|
||||
qCWarning(lcTlsBackend, "Failed to change the symmetric key's chaining mode (%ld)!", status);
|
||||
return nullptr;
|
||||
}
|
||||
return keyHandle;
|
||||
@ -159,7 +157,7 @@ QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const
|
||||
BCRYPT_BLOCK_PADDING // dwFlags
|
||||
);
|
||||
if (status < 0) {
|
||||
qCWarning(lcSsl, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt", status);
|
||||
qCWarning(lcTlsBackend, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt", status);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ namespace QSsl {
|
||||
class TlsKeySchannel final : public TlsKeyGeneric
|
||||
{
|
||||
public:
|
||||
TlsKeySchannel() = default;
|
||||
using TlsKeyGeneric::TlsKeyGeneric;
|
||||
|
||||
QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
|
||||
const QByteArray &iv) const override;
|
||||
|
@ -64,7 +64,7 @@ namespace QSsl {
|
||||
class TlsKeySecureTransport final : public TlsKeyGeneric
|
||||
{
|
||||
public:
|
||||
TlsKeySecureTransport() = default;
|
||||
using TlsKeyGeneric::TlsKeyGeneric;
|
||||
|
||||
QByteArray decrypt(Cipher cipher, const QByteArray &data,
|
||||
const QByteArray &key, const QByteArray &iv) const override;
|
||||
|
178
src/network/ssl/qx509_base.cpp
Normal file
178
src/network/ssl/qx509_base.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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 "qx509_base_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
QByteArray X509CertificateBase::subjectInfoToString(QSslCertificate::SubjectInfo info)
|
||||
{
|
||||
QByteArray str;
|
||||
switch (info) {
|
||||
case QSslCertificate::Organization: str = QByteArray("O"); break;
|
||||
case QSslCertificate::CommonName: str = QByteArray("CN"); break;
|
||||
case QSslCertificate::LocalityName: str = QByteArray("L"); break;
|
||||
case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
|
||||
case QSslCertificate::CountryName: str = QByteArray("C"); break;
|
||||
case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
|
||||
case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
|
||||
case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
|
||||
case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool X509CertificateBase::matchLineFeed(const QByteArray &pem, int *offset)
|
||||
{
|
||||
Q_ASSERT(offset);
|
||||
|
||||
char ch = 0;
|
||||
// ignore extra whitespace at the end of the line
|
||||
while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
|
||||
++*offset;
|
||||
|
||||
if (ch == '\n') {
|
||||
*offset += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
|
||||
*offset += 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool X509CertificateBase::isNull() const
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
QByteArray X509CertificateBase::version() const
|
||||
{
|
||||
return versionString;
|
||||
}
|
||||
|
||||
QByteArray X509CertificateBase::serialNumber() const
|
||||
{
|
||||
return serialNumberString;
|
||||
}
|
||||
|
||||
QStringList X509CertificateBase::issuerInfo(QSslCertificate::SubjectInfo info) const
|
||||
{
|
||||
return issuerInfo(subjectInfoToString(info));
|
||||
}
|
||||
|
||||
QStringList X509CertificateBase::issuerInfo(const QByteArray &attribute) const
|
||||
{
|
||||
return issuerInfoEntries.values(attribute);
|
||||
}
|
||||
|
||||
QStringList X509CertificateBase::subjectInfo(QSslCertificate::SubjectInfo info) const
|
||||
{
|
||||
return subjectInfo(subjectInfoToString(info));
|
||||
}
|
||||
|
||||
QStringList X509CertificateBase::subjectInfo(const QByteArray &attribute) const
|
||||
{
|
||||
return subjectInfoEntries.values(attribute);
|
||||
}
|
||||
|
||||
QList<QByteArray> X509CertificateBase::subjectInfoAttributes() const
|
||||
{
|
||||
return subjectInfoEntries.uniqueKeys();
|
||||
}
|
||||
|
||||
QList<QByteArray> X509CertificateBase::issuerInfoAttributes() const
|
||||
{
|
||||
return issuerInfoEntries.uniqueKeys();
|
||||
}
|
||||
|
||||
QDateTime X509CertificateBase::effectiveDate() const
|
||||
{
|
||||
return notValidBefore;
|
||||
}
|
||||
|
||||
QDateTime X509CertificateBase::expiryDate() const
|
||||
{
|
||||
return notValidAfter;
|
||||
}
|
||||
|
||||
qsizetype X509CertificateBase::numberOfExtensions() const
|
||||
{
|
||||
return extensions.size();
|
||||
}
|
||||
|
||||
QString X509CertificateBase::oidForExtension(qsizetype index) const
|
||||
{
|
||||
Q_ASSERT(validIndex(index));
|
||||
return extensions[index].oid;
|
||||
}
|
||||
|
||||
QString X509CertificateBase::nameForExtension(qsizetype index) const
|
||||
{
|
||||
Q_ASSERT(validIndex(index));
|
||||
return extensions[index].name;
|
||||
}
|
||||
|
||||
QVariant X509CertificateBase::valueForExtension(qsizetype index) const
|
||||
{
|
||||
Q_ASSERT(validIndex(index));
|
||||
return extensions[index].value;
|
||||
}
|
||||
|
||||
bool X509CertificateBase::isExtensionCritical(qsizetype index) const
|
||||
{
|
||||
Q_ASSERT(validIndex(index));
|
||||
return extensions[index].critical;
|
||||
}
|
||||
|
||||
bool X509CertificateBase::isExtensionSupported(qsizetype index) const
|
||||
{
|
||||
Q_ASSERT(validIndex(index));
|
||||
return extensions[index].supported;
|
||||
}
|
||||
|
||||
} // namespace QSsl
|
||||
|
||||
QT_END_NAMESPACE
|
125
src/network/ssl/qx509_base_p.h
Normal file
125
src/network/ssl/qx509_base_p.h
Normal file
@ -0,0 +1,125 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QX509CERTIFICATE_BASE_P_H
|
||||
#define QX509CERTIFICATE_BASE_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <private/qtlsbackend_p.h>
|
||||
|
||||
#include <qssl.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qlist.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
class X509CertificateBase : public X509Certificate
|
||||
{
|
||||
public:
|
||||
bool isNull() const override;
|
||||
QByteArray version() const override;
|
||||
QByteArray serialNumber() const override;
|
||||
QStringList issuerInfo(QSslCertificate::SubjectInfo info) const override;
|
||||
QStringList issuerInfo(const QByteArray &attribute) const override;
|
||||
QStringList subjectInfo(QSslCertificate::SubjectInfo info) const override;
|
||||
QStringList subjectInfo(const QByteArray &attribute) const override;
|
||||
QList<QByteArray> subjectInfoAttributes() const override;
|
||||
QList<QByteArray> issuerInfoAttributes() const override;
|
||||
QDateTime effectiveDate() const override;
|
||||
QDateTime expiryDate() const override;
|
||||
|
||||
qsizetype numberOfExtensions() const override;
|
||||
QString oidForExtension(qsizetype index) const override;
|
||||
QString nameForExtension(qsizetype index) const override;
|
||||
QVariant valueForExtension(qsizetype index) const override;
|
||||
bool isExtensionCritical(qsizetype index) const override;
|
||||
bool isExtensionSupported(qsizetype index) const override;
|
||||
|
||||
static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
|
||||
static bool matchLineFeed(const QByteArray &pem, int *offset);
|
||||
|
||||
protected:
|
||||
bool validIndex(qsizetype index) const
|
||||
{
|
||||
return index >= 0 && index < extensions.size();
|
||||
}
|
||||
|
||||
bool null = true;
|
||||
QByteArray versionString;
|
||||
QByteArray serialNumberString;
|
||||
|
||||
QMultiMap<QByteArray, QString> issuerInfoEntries;
|
||||
QMultiMap<QByteArray, QString> subjectInfoEntries;
|
||||
QDateTime notValidAfter;
|
||||
QDateTime notValidBefore;
|
||||
|
||||
struct X509CertificateExtension
|
||||
{
|
||||
QString oid;
|
||||
QString name;
|
||||
QVariant value;
|
||||
bool critical = false;
|
||||
bool supported = false;
|
||||
};
|
||||
|
||||
QList<X509CertificateExtension> extensions;
|
||||
};
|
||||
|
||||
} // namespace QSsl
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QX509CERTIFICATE_BASE_P_H
|
467
src/network/ssl/qx509_generic.cpp
Normal file
467
src/network/ssl/qx509_generic.cpp
Normal file
@ -0,0 +1,467 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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 "qtlskey_generic_p.h"
|
||||
#include "qx509_generic_p.h"
|
||||
#include "qasn1element_p.h"
|
||||
|
||||
#include "qssl_p.h"
|
||||
|
||||
#include <qhostaddress.h>
|
||||
#include <qendian.h>
|
||||
#include <qhash.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
namespace {
|
||||
|
||||
QByteArray colonSeparatedHex(const QByteArray &value)
|
||||
{
|
||||
const int size = value.size();
|
||||
int i = 0;
|
||||
while (i < size && !value.at(i)) // skip leading zeros
|
||||
++i;
|
||||
|
||||
return value.mid(i).toHex(':');
|
||||
}
|
||||
|
||||
} // Unnamed namespace.
|
||||
|
||||
bool X509CertificateGeneric::isEqual(const X509Certificate &rhs) const
|
||||
{
|
||||
const auto &other = static_cast<const X509CertificateGeneric &>(rhs);
|
||||
return derData == other.derData;
|
||||
}
|
||||
|
||||
bool X509CertificateGeneric::isSelfSigned() const
|
||||
{
|
||||
if (null)
|
||||
return false;
|
||||
|
||||
qCWarning(lcTlsBackend, "QSslCertificate::isSelfSigned: This function does not check, whether the certificate "
|
||||
"is actually signed. It just checks whether issuer and subject are identical");
|
||||
return subjectMatchesIssuer;
|
||||
}
|
||||
|
||||
QMultiMap<QSsl::AlternativeNameEntryType, QString> X509CertificateGeneric::subjectAlternativeNames() const
|
||||
{
|
||||
return saNames;
|
||||
}
|
||||
|
||||
#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
|
||||
#define ENDCERTSTRING "-----END CERTIFICATE-----"
|
||||
|
||||
QByteArray X509CertificateGeneric::toPem() const
|
||||
{
|
||||
QByteArray array = toDer();
|
||||
// Convert to Base64 - wrap at 64 characters.
|
||||
array = array.toBase64();
|
||||
QByteArray tmp;
|
||||
for (int i = 0; i <= array.size() - 64; i += 64) {
|
||||
tmp += QByteArray::fromRawData(array.data() + i, 64);
|
||||
tmp += '\n';
|
||||
}
|
||||
if (int remainder = array.size() % 64) {
|
||||
tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
|
||||
tmp += '\n';
|
||||
}
|
||||
|
||||
return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
|
||||
}
|
||||
|
||||
QByteArray X509CertificateGeneric::toDer() const
|
||||
{
|
||||
return derData;
|
||||
}
|
||||
|
||||
QString X509CertificateGeneric::toText() const
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Qt::HANDLE X509CertificateGeneric::handle() const
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t X509CertificateGeneric::hash(size_t seed) const noexcept
|
||||
{
|
||||
return qHash(toDer(), seed);
|
||||
}
|
||||
|
||||
QList<QSslCertificate> X509CertificateGeneric::certificatesFromPem(const QByteArray &pem, int count)
|
||||
{
|
||||
QList<QSslCertificate> certificates;
|
||||
int offset = 0;
|
||||
while (count == -1 || certificates.size() < count) {
|
||||
int startPos = pem.indexOf(BEGINCERTSTRING, offset);
|
||||
if (startPos == -1)
|
||||
break;
|
||||
startPos += sizeof(BEGINCERTSTRING) - 1;
|
||||
if (!matchLineFeed(pem, &startPos))
|
||||
break;
|
||||
|
||||
int endPos = pem.indexOf(ENDCERTSTRING, startPos);
|
||||
if (endPos == -1)
|
||||
break;
|
||||
|
||||
offset = endPos + sizeof(ENDCERTSTRING) - 1;
|
||||
if (offset < pem.size() && !matchLineFeed(pem, &offset))
|
||||
break;
|
||||
|
||||
QByteArray decoded = QByteArray::fromBase64(
|
||||
QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
|
||||
certificates << certificatesFromDer(decoded, 1);;
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> X509CertificateGeneric::certificatesFromDer(const QByteArray &der, int count)
|
||||
{
|
||||
QList<QSslCertificate> certificates;
|
||||
|
||||
QByteArray data = der;
|
||||
while (count == -1 || certificates.size() < count) {
|
||||
QSslCertificate cert;
|
||||
auto *certBackend = QTlsBackend::backend<X509CertificateGeneric>(cert);
|
||||
if (!certBackend->parse(data))
|
||||
break;
|
||||
|
||||
certificates << cert;
|
||||
data.remove(0, certBackend->derData.size());
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
bool X509CertificateGeneric::parse(const QByteArray &data)
|
||||
{
|
||||
QAsn1Element root;
|
||||
|
||||
QDataStream dataStream(data);
|
||||
if (!root.read(dataStream) || root.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
QDataStream rootStream(root.value());
|
||||
QAsn1Element cert;
|
||||
if (!cert.read(rootStream) || cert.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
// version or serial number
|
||||
QAsn1Element elem;
|
||||
QDataStream certStream(cert.value());
|
||||
if (!elem.read(certStream))
|
||||
return false;
|
||||
|
||||
if (elem.type() == QAsn1Element::Context0Type) {
|
||||
QDataStream versionStream(elem.value());
|
||||
if (!elem.read(versionStream)
|
||||
|| elem.type() != QAsn1Element::IntegerType
|
||||
|| elem.value().isEmpty())
|
||||
return false;
|
||||
|
||||
versionString = QByteArray::number(elem.value().at(0) + 1);
|
||||
if (!elem.read(certStream))
|
||||
return false;
|
||||
} else {
|
||||
versionString = QByteArray::number(1);
|
||||
}
|
||||
|
||||
// serial number
|
||||
if (elem.type() != QAsn1Element::IntegerType)
|
||||
return false;
|
||||
serialNumberString = colonSeparatedHex(elem.value());
|
||||
|
||||
// algorithm ID
|
||||
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
// issuer info
|
||||
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
QByteArray issuerDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
|
||||
issuerInfoEntries = elem.toInfo();
|
||||
|
||||
// validity period
|
||||
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
QDataStream validityStream(elem.value());
|
||||
if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
|
||||
return false;
|
||||
|
||||
notValidBefore = elem.toDateTime();
|
||||
if (!notValidBefore.isValid())
|
||||
return false;
|
||||
|
||||
if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
|
||||
return false;
|
||||
|
||||
notValidAfter = elem.toDateTime();
|
||||
if (!notValidAfter.isValid())
|
||||
return false;
|
||||
|
||||
|
||||
// subject name
|
||||
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
QByteArray subjectDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
|
||||
subjectInfoEntries = elem.toInfo();
|
||||
subjectMatchesIssuer = issuerDer == subjectDer;
|
||||
|
||||
// public key
|
||||
qint64 keyStart = certStream.device()->pos();
|
||||
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
publicKeyDerData.resize(certStream.device()->pos() - keyStart);
|
||||
QDataStream keyStream(elem.value());
|
||||
if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
|
||||
// key algorithm
|
||||
if (!elem.read(elem.value()) || elem.type() != QAsn1Element::ObjectIdentifierType)
|
||||
return false;
|
||||
|
||||
const QByteArray oid = elem.toObjectId();
|
||||
if (oid == RSA_ENCRYPTION_OID)
|
||||
publicKeyAlgorithm = QSsl::Rsa;
|
||||
else if (oid == DSA_ENCRYPTION_OID)
|
||||
publicKeyAlgorithm = QSsl::Dsa;
|
||||
else if (oid == EC_ENCRYPTION_OID)
|
||||
publicKeyAlgorithm = QSsl::Ec;
|
||||
else
|
||||
publicKeyAlgorithm = QSsl::Opaque;
|
||||
|
||||
certStream.device()->seek(keyStart);
|
||||
certStream.readRawData(publicKeyDerData.data(), publicKeyDerData.size());
|
||||
|
||||
// extensions
|
||||
while (elem.read(certStream)) {
|
||||
if (elem.type() == QAsn1Element::Context3Type) {
|
||||
if (elem.read(elem.value()) && elem.type() == QAsn1Element::SequenceType) {
|
||||
QDataStream extStream(elem.value());
|
||||
while (elem.read(extStream) && elem.type() == QAsn1Element::SequenceType) {
|
||||
X509CertificateExtension extension;
|
||||
if (!parseExtension(elem.value(), extension))
|
||||
return false;
|
||||
|
||||
if (extension.oid == QLatin1String("2.5.29.17")) {
|
||||
// subjectAltName
|
||||
|
||||
// Note, parseExtension() returns true for this extensions,
|
||||
// but considers it to be unsupported and assignes a useless
|
||||
// value. OpenSSL also treats this extension as unsupported,
|
||||
// but properly creates a map with 'name' and 'value' taken
|
||||
// from the extension. We only support 'email', 'IP' and 'DNS',
|
||||
// but this is what our subjectAlternativeNames map can contain
|
||||
// anyway.
|
||||
QVariantMap extValue;
|
||||
QAsn1Element sanElem;
|
||||
if (sanElem.read(extension.value.toByteArray()) && sanElem.type() == QAsn1Element::SequenceType) {
|
||||
QDataStream nameStream(sanElem.value());
|
||||
QAsn1Element nameElem;
|
||||
while (nameElem.read(nameStream)) {
|
||||
switch (nameElem.type()) {
|
||||
case QAsn1Element::Rfc822NameType:
|
||||
saNames.insert(QSsl::EmailEntry, nameElem.toString());
|
||||
extValue[QStringLiteral("email")] = nameElem.toString();
|
||||
break;
|
||||
case QAsn1Element::DnsNameType:
|
||||
saNames.insert(QSsl::DnsEntry, nameElem.toString());
|
||||
extValue[QStringLiteral("DNS")] = nameElem.toString();
|
||||
break;
|
||||
case QAsn1Element::IpAddressType: {
|
||||
QHostAddress ipAddress;
|
||||
QByteArray ipAddrValue = nameElem.value();
|
||||
switch (ipAddrValue.length()) {
|
||||
case 4: // IPv4
|
||||
ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(ipAddrValue.data())));
|
||||
break;
|
||||
case 16: // IPv6
|
||||
ipAddress = QHostAddress(reinterpret_cast<quint8 *>(ipAddrValue.data()));
|
||||
break;
|
||||
default: // Unknown IP address format
|
||||
break;
|
||||
}
|
||||
if (!ipAddress.isNull()) {
|
||||
saNames.insert(QSsl::IpAddressEntry, ipAddress.toString());
|
||||
extValue[QStringLiteral("IP")] = ipAddress.toString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
extension.value = extValue;
|
||||
extension.supported = true;
|
||||
}
|
||||
}
|
||||
|
||||
extensions << extension;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
derData = data.left(dataStream.device()->pos());
|
||||
null = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X509CertificateGeneric::parseExtension(const QByteArray &data, X509CertificateExtension &extension)
|
||||
{
|
||||
bool ok = false;
|
||||
bool critical = false;
|
||||
QAsn1Element oidElem, valElem;
|
||||
|
||||
QDataStream seqStream(data);
|
||||
|
||||
// oid
|
||||
if (!oidElem.read(seqStream) || oidElem.type() != QAsn1Element::ObjectIdentifierType)
|
||||
return false;
|
||||
|
||||
const QByteArray oid = oidElem.toObjectId();
|
||||
// critical and value
|
||||
if (!valElem.read(seqStream))
|
||||
return false;
|
||||
|
||||
if (valElem.type() == QAsn1Element::BooleanType) {
|
||||
critical = valElem.toBool(&ok);
|
||||
|
||||
if (!ok || !valElem.read(seqStream))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (valElem.type() != QAsn1Element::OctetStringType)
|
||||
return false;
|
||||
|
||||
// interpret value
|
||||
QAsn1Element val;
|
||||
bool supported = true;
|
||||
QVariant value;
|
||||
if (oid == "1.3.6.1.5.5.7.1.1") {
|
||||
// authorityInfoAccess
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
QVariantMap result;
|
||||
const auto elems = val.toList();
|
||||
for (const QAsn1Element &el : elems) {
|
||||
const auto items = el.toList();
|
||||
if (items.size() != 2)
|
||||
return false;
|
||||
const QString key = QString::fromLatin1(items.at(0).toObjectName());
|
||||
switch (items.at(1).type()) {
|
||||
case QAsn1Element::Rfc822NameType:
|
||||
case QAsn1Element::DnsNameType:
|
||||
case QAsn1Element::UniformResourceIdentifierType:
|
||||
result[key] = items.at(1).toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = result;
|
||||
} else if (oid == "2.5.29.14") {
|
||||
// subjectKeyIdentifier
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::OctetStringType)
|
||||
return false;
|
||||
value = colonSeparatedHex(val.value()).toUpper();
|
||||
} else if (oid == "2.5.29.19") {
|
||||
// basicConstraints
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
QVariantMap result;
|
||||
const auto items = val.toList();
|
||||
if (items.size() > 0) {
|
||||
result[QStringLiteral("ca")] = items.at(0).toBool(&ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
} else {
|
||||
result[QStringLiteral("ca")] = false;
|
||||
}
|
||||
if (items.size() > 1) {
|
||||
result[QStringLiteral("pathLenConstraint")] = items.at(1).toInteger(&ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
value = result;
|
||||
} else if (oid == "2.5.29.35") {
|
||||
// authorityKeyIdentifier
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
QVariantMap result;
|
||||
const auto elems = val.toList();
|
||||
for (const QAsn1Element &el : elems) {
|
||||
if (el.type() == 0x80) {
|
||||
const QString key = QStringLiteral("keyid");
|
||||
result[key] = el.value().toHex();
|
||||
} else if (el.type() == 0x82) {
|
||||
const QString serial = QStringLiteral("serial");
|
||||
result[serial] = colonSeparatedHex(el.value());
|
||||
}
|
||||
}
|
||||
value = result;
|
||||
} else {
|
||||
supported = false;
|
||||
value = valElem.value();
|
||||
}
|
||||
|
||||
extension.critical = critical;
|
||||
extension.supported = supported;
|
||||
extension.oid = QString::fromLatin1(oid);
|
||||
extension.name = QString::fromLatin1(oidElem.toObjectName());
|
||||
extension.value = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QSsl
|
||||
|
||||
QT_END_NAMESPACE
|
101
src/network/ssl/qx509_generic_p.h
Normal file
101
src/network/ssl/qx509_generic_p.h
Normal file
@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
#ifndef QX509_GENERIC_P_H
|
||||
#define QX509_GENERIC_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <private/qtlsbackend_p.h>
|
||||
#include <private/qx509_base_p.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
// TLSTODO: This class is what previously was known as qsslcertificate_qt.
|
||||
// A part of SecureTransport and Schannel plugin.
|
||||
class X509CertificateGeneric : public X509CertificateBase
|
||||
{
|
||||
public:
|
||||
bool isEqual(const X509Certificate &rhs) const override;
|
||||
bool isSelfSigned() const override;
|
||||
|
||||
QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const override;
|
||||
QByteArray toPem() const override;
|
||||
QByteArray toDer() const override;
|
||||
QString toText() const override;
|
||||
Qt::HANDLE handle() const override;
|
||||
|
||||
size_t hash(size_t seed) const noexcept override;
|
||||
|
||||
static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count);
|
||||
static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count);
|
||||
|
||||
protected:
|
||||
|
||||
bool subjectMatchesIssuer = false;
|
||||
QSsl::KeyAlgorithm publicKeyAlgorithm = QSsl::Rsa;
|
||||
QByteArray publicKeyDerData;
|
||||
|
||||
QMultiMap<QSsl::AlternativeNameEntryType, QString> saNames;
|
||||
QByteArray derData;
|
||||
|
||||
bool parse(const QByteArray &data);
|
||||
bool parseExtension(const QByteArray &data, X509CertificateExtension &extension);
|
||||
};
|
||||
|
||||
} // namespace QSsl
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QX509_GENERIC_P_H
|
927
src/network/ssl/qx509_openssl.cpp
Normal file
927
src/network/ssl/qx509_openssl.cpp
Normal file
@ -0,0 +1,927 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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 "qtlsbackend_openssl_p.h"
|
||||
#include "qtlskey_openssl_p.h"
|
||||
#include "qx509_openssl_p.h"
|
||||
|
||||
#include "qsslsocket_openssl_symbols_p.h"
|
||||
|
||||
#include "qsslsocket.h"
|
||||
|
||||
#include <QtNetwork/qhostaddress.h>
|
||||
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
#include <QtCore/qscopeguard.h>
|
||||
#include <QtCore/qdatetime.h>
|
||||
#include <QtCore/qiodevice.h>
|
||||
#include <QtCore/qendian.h>
|
||||
#include <QtCore/qhash.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
namespace {
|
||||
|
||||
// TLSTODO: These helper functions below were static member-functions of
|
||||
// QSslCertificatePrivate, if-defed with !QT_NO_OPENSSL, no need
|
||||
// for them to be exposed this way anymore. Remove this comment when
|
||||
// plugins are ready.
|
||||
QByteArray asn1ObjectId(ASN1_OBJECT *object)
|
||||
{
|
||||
if (!object)
|
||||
return {};
|
||||
|
||||
char buf[80] = {}; // The openssl docs a buffer length of 80 should be more than enough
|
||||
q_OBJ_obj2txt(buf, sizeof(buf), object, 1); // the 1 says always use the oid not the long name
|
||||
|
||||
return QByteArray(buf);
|
||||
}
|
||||
|
||||
QByteArray asn1ObjectName(ASN1_OBJECT *object)
|
||||
{
|
||||
if (!object)
|
||||
return {};
|
||||
|
||||
const int nid = q_OBJ_obj2nid(object);
|
||||
if (nid != NID_undef)
|
||||
return QByteArray(q_OBJ_nid2sn(nid));
|
||||
|
||||
return asn1ObjectId(object);
|
||||
}
|
||||
|
||||
QMultiMap<QByteArray, QString> mapFromX509Name(X509_NAME *name)
|
||||
{
|
||||
if (!name)
|
||||
return {};
|
||||
|
||||
QMultiMap<QByteArray, QString> info;
|
||||
for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) {
|
||||
X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i);
|
||||
|
||||
QByteArray name = asn1ObjectName(q_X509_NAME_ENTRY_get_object(e));
|
||||
unsigned char *data = nullptr;
|
||||
int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
|
||||
info.insert(name, QString::fromUtf8((char*)data, size));
|
||||
q_CRYPTO_free(data, nullptr, 0);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
|
||||
#define ENDCERTSTRING "-----END CERTIFICATE-----"
|
||||
|
||||
QByteArray x509ToQByteArray(X509 *x509, QSsl::EncodingFormat format)
|
||||
{
|
||||
Q_ASSERT(x509);
|
||||
|
||||
// Use i2d_X509 to convert the X509 to an array.
|
||||
const int length = q_i2d_X509(x509, nullptr);
|
||||
if (length <= 0) {
|
||||
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||
return {};
|
||||
}
|
||||
|
||||
QByteArray array;
|
||||
array.resize(length);
|
||||
|
||||
char *data = array.data();
|
||||
char **dataP = &data;
|
||||
unsigned char **dataPu = (unsigned char **)dataP;
|
||||
if (q_i2d_X509(x509, dataPu) < 0)
|
||||
return QByteArray();
|
||||
|
||||
if (format == QSsl::Der)
|
||||
return array;
|
||||
|
||||
// Convert to Base64 - wrap at 64 characters.
|
||||
array = array.toBase64();
|
||||
QByteArray tmp;
|
||||
for (int i = 0; i <= array.size() - 64; i += 64) {
|
||||
tmp += QByteArray::fromRawData(array.data() + i, 64);
|
||||
tmp += '\n';
|
||||
}
|
||||
if (int remainder = array.size() % 64) {
|
||||
tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
|
||||
tmp += '\n';
|
||||
}
|
||||
|
||||
return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
|
||||
}
|
||||
|
||||
QString x509ToText(X509 *x509)
|
||||
{
|
||||
Q_ASSERT(x509);
|
||||
|
||||
QByteArray result;
|
||||
BIO *bio = q_BIO_new(q_BIO_s_mem());
|
||||
if (!bio)
|
||||
return QString();
|
||||
const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
|
||||
|
||||
q_X509_print(bio, x509);
|
||||
|
||||
QVarLengthArray<char, 16384> data;
|
||||
int count = q_BIO_read(bio, data.data(), 16384);
|
||||
if ( count > 0 )
|
||||
result = QByteArray( data.data(), count );
|
||||
|
||||
return QString::fromLatin1(result);
|
||||
}
|
||||
|
||||
QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
|
||||
{
|
||||
// Get the extension specific method object if available
|
||||
// we cast away the const-ness here because some versions of openssl
|
||||
// don't use const for the parameters in the functions pointers stored
|
||||
// in the object.
|
||||
Q_ASSERT(ext);
|
||||
|
||||
X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
|
||||
if (!meth) {
|
||||
ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext);
|
||||
Q_ASSERT(value);
|
||||
QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(value)),
|
||||
q_ASN1_STRING_length(value));
|
||||
return result;
|
||||
}
|
||||
|
||||
void *ext_internal = q_X509V3_EXT_d2i(ext);
|
||||
|
||||
// If this extension can be converted
|
||||
if (meth->i2v && ext_internal) {
|
||||
STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, nullptr);
|
||||
|
||||
QVariantMap map;
|
||||
QVariantList list;
|
||||
bool isMap = false;
|
||||
|
||||
for (int j = 0; j < q_SKM_sk_num(CONF_VALUE, val); j++) {
|
||||
CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j);
|
||||
if (nval->name && nval->value) {
|
||||
isMap = true;
|
||||
map[QString::fromUtf8(nval->name)] = QString::fromUtf8(nval->value);
|
||||
} else if (nval->name) {
|
||||
list << QString::fromUtf8(nval->name);
|
||||
} else if (nval->value) {
|
||||
list << QString::fromUtf8(nval->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (isMap)
|
||||
return map;
|
||||
else
|
||||
return list;
|
||||
} else if (meth->i2s && ext_internal) {
|
||||
QVariant result(QString::fromUtf8(meth->i2s(meth, ext_internal)));
|
||||
return result;
|
||||
} else if (meth->i2r && ext_internal) {
|
||||
QByteArray result;
|
||||
|
||||
BIO *bio = q_BIO_new(q_BIO_s_mem());
|
||||
if (!bio)
|
||||
return result;
|
||||
|
||||
meth->i2r(meth, ext_internal, bio, 0);
|
||||
|
||||
char *bio_buffer;
|
||||
long bio_size = q_BIO_get_mem_data(bio, &bio_buffer);
|
||||
result = QByteArray(bio_buffer, bio_size);
|
||||
|
||||
q_BIO_free(bio);
|
||||
return result;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert extensions to a variant. The naming of the keys of the map are
|
||||
* taken from RFC 5280, however we decided the capitalisation in the RFC
|
||||
* was too silly for the real world.
|
||||
*/
|
||||
QVariant x509ExtensionToValue(X509_EXTENSION *ext)
|
||||
{
|
||||
ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
|
||||
int nid = q_OBJ_obj2nid(obj);
|
||||
switch (nid) {
|
||||
case NID_basic_constraints:
|
||||
{
|
||||
BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(ext));
|
||||
if (!basic)
|
||||
return {};
|
||||
QVariantMap result;
|
||||
result[QLatin1String("ca")] = basic->ca ? true : false;
|
||||
if (basic->pathlen)
|
||||
result[QLatin1String("pathLenConstraint")] = (qlonglong)q_ASN1_INTEGER_get(basic->pathlen);
|
||||
|
||||
q_BASIC_CONSTRAINTS_free(basic);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case NID_info_access:
|
||||
{
|
||||
AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(ext));
|
||||
if (!info)
|
||||
return {};
|
||||
QVariantMap result;
|
||||
for (int i=0; i < q_SKM_sk_num(ACCESS_DESCRIPTION, info); i++) {
|
||||
ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i);
|
||||
|
||||
GENERAL_NAME *name = ad->location;
|
||||
if (name->type == GEN_URI) {
|
||||
int len = q_ASN1_STRING_length(name->d.uniformResourceIdentifier);
|
||||
if (len < 0 || len >= 8192) {
|
||||
// broken name
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(name->d.uniformResourceIdentifier));
|
||||
const QString uri = QString::fromUtf8(uriStr, len);
|
||||
|
||||
result[QString::fromUtf8(asn1ObjectName(ad->method))] = uri;
|
||||
} else {
|
||||
qCWarning(lcTlsBackend) << "Strange location type" << name->type;
|
||||
}
|
||||
}
|
||||
|
||||
q_OPENSSL_sk_pop_free((OPENSSL_STACK*)info, reinterpret_cast<void(*)(void *)>(q_OPENSSL_sk_free));
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case NID_subject_key_identifier:
|
||||
{
|
||||
void *ext_internal = q_X509V3_EXT_d2i(ext);
|
||||
if (!ext_internal)
|
||||
return {};
|
||||
// we cast away the const-ness here because some versions of openssl
|
||||
// don't use const for the parameters in the functions pointers stored
|
||||
// in the object.
|
||||
X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
|
||||
|
||||
return QVariant(QString::fromUtf8(meth->i2s(meth, ext_internal)));
|
||||
}
|
||||
break;
|
||||
case NID_authority_key_identifier:
|
||||
{
|
||||
AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(ext));
|
||||
if (!auth_key)
|
||||
return {};
|
||||
QVariantMap result;
|
||||
|
||||
// keyid
|
||||
if (auth_key->keyid) {
|
||||
QByteArray keyid(reinterpret_cast<const char *>(auth_key->keyid->data),
|
||||
auth_key->keyid->length);
|
||||
result[QLatin1String("keyid")] = keyid.toHex();
|
||||
}
|
||||
|
||||
// issuer
|
||||
// TODO: GENERAL_NAMES
|
||||
|
||||
// serial
|
||||
if (auth_key->serial)
|
||||
result[QLatin1String("serial")] = (qlonglong)q_ASN1_INTEGER_get(auth_key->serial);
|
||||
|
||||
q_AUTHORITY_KEYID_free(auth_key);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // Unnamed namespace
|
||||
|
||||
extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
if (!ok) {
|
||||
// Store the error and at which depth the error was detected.
|
||||
using ErrorListPtr = QList<QSslErrorEntry> *;
|
||||
ErrorListPtr errors = nullptr;
|
||||
|
||||
// Error list is attached to either 'SSL' or 'X509_STORE'.
|
||||
if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first:
|
||||
errors = ErrorListPtr(q_X509_STORE_get_ex_data(store, 0));
|
||||
|
||||
if (!errors) {
|
||||
// Not found on store? Try SSL and its external data then. According to the OpenSSL's
|
||||
// documentation:
|
||||
//
|
||||
// "Whenever a X509_STORE_CTX object is created for the verification of the
|
||||
// peer's certificate during a handshake, a pointer to the SSL object is
|
||||
// stored into the X509_STORE_CTX object to identify the connection affected.
|
||||
// To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
|
||||
// used with the correct index."
|
||||
|
||||
// TLSTODO: verification callback has to change as soon as TlsCryptographer is in place.
|
||||
// This is a temporary solution for now to ease the transition.
|
||||
const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
|
||||
+ QSslSocketBackendPrivate::errorOffsetInExData;
|
||||
if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())))
|
||||
errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
|
||||
}
|
||||
|
||||
if (!errors) {
|
||||
qCWarning(lcTlsBackend, "Neither X509_STORE, nor SSL contains error list, verification failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errors->append(X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
|
||||
}
|
||||
// Always return OK to allow verification to continue. We handle the
|
||||
// errors gracefully after collecting all errors, after verification has
|
||||
// completed.
|
||||
return 1;
|
||||
}
|
||||
|
||||
X509CertificateOpenSSL::X509CertificateOpenSSL() = default;
|
||||
|
||||
X509CertificateOpenSSL::~X509CertificateOpenSSL()
|
||||
{
|
||||
if (x509)
|
||||
q_X509_free(x509);
|
||||
}
|
||||
|
||||
bool X509CertificateOpenSSL::isEqual(const X509Certificate &rhs) const
|
||||
{
|
||||
//TLSTODO: to make it safe I'll check the backend type later.
|
||||
const auto &other = static_cast<const X509CertificateOpenSSL &>(rhs);
|
||||
if (x509 && other.x509) {
|
||||
const int ret = q_X509_cmp(x509, other.x509);
|
||||
if (ret >= -1 && ret <= 1)
|
||||
return ret == 0;
|
||||
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool X509CertificateOpenSSL::isSelfSigned() const
|
||||
{
|
||||
if (!x509)
|
||||
return false;
|
||||
|
||||
return q_X509_check_issued(x509, x509) == X509_V_OK;
|
||||
}
|
||||
|
||||
QMultiMap<QSsl::AlternativeNameEntryType, QString>
|
||||
X509CertificateOpenSSL::subjectAlternativeNames() const
|
||||
{
|
||||
QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
|
||||
|
||||
if (!x509)
|
||||
return result;
|
||||
|
||||
auto *altNames = static_cast<STACK_OF(GENERAL_NAME) *>(q_X509_get_ext_d2i(x509, NID_subject_alt_name,
|
||||
nullptr, nullptr));
|
||||
if (!altNames)
|
||||
return result;
|
||||
|
||||
auto altName = [](ASN1_IA5STRING *ia5, int len) {
|
||||
const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(ia5));
|
||||
return QString::fromLatin1(altNameStr, len);
|
||||
};
|
||||
|
||||
for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
|
||||
const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
|
||||
if (genName->type != GEN_DNS && genName->type != GEN_EMAIL && genName->type != GEN_IPADD)
|
||||
continue;
|
||||
|
||||
const int len = q_ASN1_STRING_length(genName->d.ia5);
|
||||
if (len < 0 || len >= 8192) {
|
||||
// broken name
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (genName->type) {
|
||||
case GEN_DNS:
|
||||
result.insert(QSsl::DnsEntry, altName(genName->d.ia5, len));
|
||||
break;
|
||||
case GEN_EMAIL:
|
||||
result.insert(QSsl::EmailEntry, altName(genName->d.ia5, len));
|
||||
break;
|
||||
case GEN_IPADD: {
|
||||
QHostAddress ipAddress;
|
||||
switch (len) {
|
||||
case 4: // IPv4
|
||||
ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(genName->d.iPAddress->data)));
|
||||
break;
|
||||
case 16: // IPv6
|
||||
ipAddress = QHostAddress(reinterpret_cast<quint8 *>(genName->d.iPAddress->data));
|
||||
break;
|
||||
default: // Unknown IP address format
|
||||
break;
|
||||
}
|
||||
if (!ipAddress.isNull())
|
||||
result.insert(QSsl::IpAddressEntry, ipAddress.toString());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
q_OPENSSL_sk_pop_free((OPENSSL_STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_GENERAL_NAME_free));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TlsKey *X509CertificateOpenSSL::publicKey() const
|
||||
{
|
||||
if (!x509)
|
||||
return {};
|
||||
|
||||
return TlsKeyOpenSSL::publicKeyFromX509(x509);
|
||||
}
|
||||
|
||||
QByteArray X509CertificateOpenSSL::toPem() const
|
||||
{
|
||||
if (!x509)
|
||||
return {};
|
||||
|
||||
return x509ToQByteArray(x509, QSsl::Pem);
|
||||
}
|
||||
|
||||
QByteArray X509CertificateOpenSSL::toDer() const
|
||||
{
|
||||
if (!x509)
|
||||
return {};
|
||||
|
||||
return x509ToQByteArray(x509, QSsl::Der);
|
||||
|
||||
}
|
||||
QString X509CertificateOpenSSL::toText() const
|
||||
{
|
||||
if (!x509)
|
||||
return {};
|
||||
|
||||
return x509ToText(x509);
|
||||
}
|
||||
|
||||
Qt::HANDLE X509CertificateOpenSSL::handle() const
|
||||
{
|
||||
return Qt::HANDLE(x509);
|
||||
}
|
||||
|
||||
size_t X509CertificateOpenSSL::hash(size_t seed) const noexcept
|
||||
{
|
||||
if (x509) {
|
||||
const EVP_MD *sha1 = q_EVP_sha1();
|
||||
unsigned int len = 0;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
q_X509_digest(x509, sha1, md, &len);
|
||||
return qHashBits(md, len, seed);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
QSslCertificate X509CertificateOpenSSL::certificateFromX509(X509 *x509)
|
||||
{
|
||||
QSslCertificate certificate;
|
||||
|
||||
auto *backend = QTlsBackend::backend<X509CertificateOpenSSL>(certificate);
|
||||
if (!backend || !x509)
|
||||
return certificate;
|
||||
|
||||
ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
|
||||
if (nbef)
|
||||
backend->notValidBefore = q_getTimeFromASN1(nbef);
|
||||
|
||||
ASN1_TIME *naft = q_X509_getm_notAfter(x509);
|
||||
if (naft)
|
||||
backend->notValidAfter = q_getTimeFromASN1(naft);
|
||||
|
||||
backend->null = false;
|
||||
backend->x509 = q_X509_dup(x509);
|
||||
|
||||
backend->issuerInfoEntries = mapFromX509Name(q_X509_get_issuer_name(x509));
|
||||
backend->subjectInfoEntries = mapFromX509Name(q_X509_get_subject_name(x509));
|
||||
backend->versionString = QByteArray::number(qlonglong(q_X509_get_version(x509)) + 1);
|
||||
|
||||
if (ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(x509)) {
|
||||
QByteArray hexString;
|
||||
hexString.reserve(serialNumber->length * 3);
|
||||
for (int a = 0; a < serialNumber->length; ++a) {
|
||||
hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
|
||||
hexString += ':';
|
||||
}
|
||||
hexString.chop(1);
|
||||
backend->serialNumberString = hexString;
|
||||
}
|
||||
|
||||
backend->parseExtensions();
|
||||
|
||||
return certificate;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> X509CertificateOpenSSL::stackOfX509ToQSslCertificates(STACK_OF(X509) *x509)
|
||||
{
|
||||
if (!x509)
|
||||
return {};
|
||||
|
||||
QList<QSslCertificate> certificates;
|
||||
for (int i = 0; i < q_sk_X509_num(x509); ++i) {
|
||||
if (X509 *entry = q_sk_X509_value(x509, i))
|
||||
certificates << certificateFromX509(entry);
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
QSslErrorEntry X509CertificateOpenSSL::errorEntryFromStoreContext(X509_STORE_CTX *ctx)
|
||||
{
|
||||
Q_ASSERT(ctx);
|
||||
|
||||
return {q_X509_STORE_CTX_get_error(ctx), q_X509_STORE_CTX_get_error_depth(ctx)};
|
||||
}
|
||||
|
||||
QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &chain,
|
||||
const QString &hostName)
|
||||
{
|
||||
// This was previously QSslSocketPrivate::verify().
|
||||
auto roots = QSslConfiguration::defaultConfiguration().caCertificates();
|
||||
#ifndef Q_OS_WIN
|
||||
// On Windows, system CA certificates are already set as default ones.
|
||||
// No need to add them again (and again) and also, if the default configuration
|
||||
// has its own set of CAs, this probably should not be amended by the ones
|
||||
// from the 'ROOT' store, since it's not what an application chose to trust.
|
||||
if (QSslSocketPrivate::s_loadRootCertsOnDemand)
|
||||
roots.append(QSslSocketPrivate::systemCaCertificates());
|
||||
#endif // Q_OS_WIN
|
||||
return verify(roots, chain, hostName);
|
||||
}
|
||||
|
||||
QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &caCertificates,
|
||||
const QList<QSslCertificate> &certificateChain,
|
||||
const QString &hostName)
|
||||
{
|
||||
// This was previously QSslSocketPrivate::verify().
|
||||
if (certificateChain.count() <= 0)
|
||||
return {QSslError(QSslError::UnspecifiedError)};
|
||||
|
||||
QList<QSslError> errors;
|
||||
X509_STORE *certStore = q_X509_STORE_new();
|
||||
if (!certStore) {
|
||||
qCWarning(lcTlsBackend) << "Unable to create certificate store";
|
||||
errors << QSslError(QSslError::UnspecifiedError);
|
||||
return errors;
|
||||
}
|
||||
const std::unique_ptr<X509_STORE, decltype(&q_X509_STORE_free)> storeGuard(certStore, q_X509_STORE_free);
|
||||
|
||||
const QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
for (const QSslCertificate &caCertificate : caCertificates) {
|
||||
// From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
|
||||
//
|
||||
// If several CA certificates matching the name, key identifier, and
|
||||
// serial number condition are available, only the first one will be
|
||||
// examined. This may lead to unexpected results if the same CA
|
||||
// certificate is available with different expiration dates. If a
|
||||
// ``certificate expired'' verification error occurs, no other
|
||||
// certificate will be searched. Make sure to not have expired
|
||||
// certificates mixed with valid ones.
|
||||
//
|
||||
// See also: QSslContext::fromConfiguration()
|
||||
if (caCertificate.expiryDate() >= now) {
|
||||
q_X509_STORE_add_cert(certStore, reinterpret_cast<X509 *>(caCertificate.handle()));
|
||||
}
|
||||
}
|
||||
|
||||
QList<QSslErrorEntry> lastErrors;
|
||||
if (!q_X509_STORE_set_ex_data(certStore, 0, &lastErrors)) {
|
||||
qCWarning(lcTlsBackend) << "Unable to attach external data (error list) to a store";
|
||||
errors << QSslError(QSslError::UnspecifiedError);
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Register a custom callback to get all verification errors.
|
||||
q_X509_STORE_set_verify_cb(certStore, qt_X509Callback);
|
||||
|
||||
// Build the chain of intermediate certificates
|
||||
STACK_OF(X509) *intermediates = nullptr;
|
||||
if (certificateChain.length() > 1) {
|
||||
intermediates = (STACK_OF(X509) *) q_OPENSSL_sk_new_null();
|
||||
|
||||
if (!intermediates) {
|
||||
errors << QSslError(QSslError::UnspecifiedError);
|
||||
return errors;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
for (const QSslCertificate &cert : certificateChain) {
|
||||
if (first) {
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
q_OPENSSL_sk_push((OPENSSL_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle()));
|
||||
}
|
||||
}
|
||||
|
||||
X509_STORE_CTX *storeContext = q_X509_STORE_CTX_new();
|
||||
if (!storeContext) {
|
||||
errors << QSslError(QSslError::UnspecifiedError);
|
||||
return errors;
|
||||
}
|
||||
std::unique_ptr<X509_STORE_CTX, decltype(&q_X509_STORE_CTX_free)> ctxGuard(storeContext, q_X509_STORE_CTX_free);
|
||||
|
||||
if (!q_X509_STORE_CTX_init(storeContext, certStore, reinterpret_cast<X509 *>(certificateChain[0].handle()), intermediates)) {
|
||||
errors << QSslError(QSslError::UnspecifiedError);
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Now we can actually perform the verification of the chain we have built.
|
||||
// We ignore the result of this function since we process errors via the
|
||||
// callback.
|
||||
(void) q_X509_verify_cert(storeContext);
|
||||
ctxGuard.reset();
|
||||
q_OPENSSL_sk_free((OPENSSL_STACK *)intermediates);
|
||||
|
||||
// Now process the errors
|
||||
|
||||
if (certificateChain[0].isBlacklisted())
|
||||
errors << QSslError(QSslError::CertificateBlacklisted, certificateChain[0]);
|
||||
|
||||
// Check the certificate name against the hostname if one was specified
|
||||
if (!hostName.isEmpty() && !QSslSocketPrivate::isMatchingHostname(certificateChain[0], hostName)) {
|
||||
// No matches in common names or alternate names.
|
||||
QSslError error(QSslError::HostNameMismatch, certificateChain[0]);
|
||||
errors << error;
|
||||
}
|
||||
|
||||
// Translate errors from the error list into QSslErrors.
|
||||
errors.reserve(errors.size() + lastErrors.size());
|
||||
for (const auto &error : qAsConst(lastErrors))
|
||||
errors << openSSLErrorToQSslError(error.code, certificateChain.value(error.depth));
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromPem(const QByteArray &pem, int count)
|
||||
{
|
||||
QList<QSslCertificate> certificates;
|
||||
|
||||
int offset = 0;
|
||||
while (count == -1 || certificates.size() < count) {
|
||||
int startPos = pem.indexOf(BEGINCERTSTRING, offset);
|
||||
if (startPos == -1)
|
||||
break;
|
||||
startPos += sizeof(BEGINCERTSTRING) - 1;
|
||||
if (!matchLineFeed(pem, &startPos))
|
||||
break;
|
||||
|
||||
int endPos = pem.indexOf(ENDCERTSTRING, startPos);
|
||||
if (endPos == -1)
|
||||
break;
|
||||
|
||||
offset = endPos + sizeof(ENDCERTSTRING) - 1;
|
||||
if (offset < pem.size() && !matchLineFeed(pem, &offset))
|
||||
break;
|
||||
|
||||
QByteArray decoded = QByteArray::fromBase64(
|
||||
QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
|
||||
const unsigned char *data = (const unsigned char *)decoded.data();
|
||||
|
||||
if (X509 *x509 = q_d2i_X509(nullptr, &data, decoded.size())) {
|
||||
certificates << certificateFromX509(x509);
|
||||
q_X509_free(x509);
|
||||
}
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromDer(const QByteArray &der, int count)
|
||||
{
|
||||
QList<QSslCertificate> certificates;
|
||||
|
||||
const unsigned char *data = (const unsigned char *)der.data();
|
||||
int size = der.size();
|
||||
|
||||
while (size > 0 && (count == -1 || certificates.size() < count)) {
|
||||
if (X509 *x509 = q_d2i_X509(nullptr, &data, size)) {
|
||||
certificates << certificateFromX509(x509);
|
||||
q_X509_free(x509);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
size -= ((const char *)data - der.data());
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
bool X509CertificateOpenSSL::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
|
||||
QList<QSslCertificate> *caCertificates,
|
||||
const QByteArray &passPhrase)
|
||||
{
|
||||
// These are required
|
||||
Q_ASSERT(device);
|
||||
Q_ASSERT(key);
|
||||
Q_ASSERT(cert);
|
||||
|
||||
// Read the file into a BIO
|
||||
QByteArray pkcs12data = device->readAll();
|
||||
if (pkcs12data.size() == 0)
|
||||
return false;
|
||||
|
||||
BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pkcs12data.constData()), pkcs12data.size());
|
||||
if (!bio) {
|
||||
qCWarning(lcTlsBackend, "BIO_new_mem_buf returned null");
|
||||
return false;
|
||||
}
|
||||
const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
|
||||
|
||||
// Create the PKCS#12 object
|
||||
PKCS12 *p12 = q_d2i_PKCS12_bio(bio, nullptr);
|
||||
if (!p12) {
|
||||
qCWarning(lcTlsBackend, "Unable to read PKCS#12 structure, %s",
|
||||
q_ERR_error_string(q_ERR_get_error(), nullptr));
|
||||
return false;
|
||||
}
|
||||
const auto p12Raii = qScopeGuard([p12]{q_PKCS12_free(p12);});
|
||||
|
||||
// Extract the data
|
||||
EVP_PKEY *pkey = nullptr;
|
||||
X509 *x509 = nullptr;
|
||||
STACK_OF(X509) *ca = nullptr;
|
||||
|
||||
if (!q_PKCS12_parse(p12, passPhrase.constData(), &pkey, &x509, &ca)) {
|
||||
qCWarning(lcTlsBackend, "Unable to parse PKCS#12 structure, %s",
|
||||
q_ERR_error_string(q_ERR_get_error(), nullptr));
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto x509Raii = qScopeGuard([x509]{q_X509_free(x509);});
|
||||
const auto keyRaii = qScopeGuard([pkey]{q_EVP_PKEY_free(pkey);});
|
||||
const auto caRaii = qScopeGuard([ca] {
|
||||
q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
|
||||
reinterpret_cast<void (*)(void *)>(q_X509_free));
|
||||
});
|
||||
|
||||
// Convert to Qt types
|
||||
auto *tlsKey = QTlsBackend::backend<TlsKeyOpenSSL>(*key);
|
||||
if (!tlsKey || !tlsKey->fromEVP_PKEY(pkey)) {
|
||||
qCWarning(lcTlsBackend, "Unable to convert private key");
|
||||
return false;
|
||||
}
|
||||
|
||||
*cert = certificateFromX509(x509);
|
||||
|
||||
if (caCertificates)
|
||||
*caCertificates = stackOfX509ToQSslCertificates(ca);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QSslError X509CertificateOpenSSL::openSSLErrorToQSslError(int errorCode, const QSslCertificate &cert)
|
||||
{
|
||||
QSslError error;
|
||||
switch (errorCode) {
|
||||
case X509_V_OK:
|
||||
// X509_V_OK is also reported if the peer had no certificate.
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
error = QSslError(QSslError::UnableToGetIssuerCertificate, cert); break;
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
|
||||
error = QSslError(QSslError::UnableToDecryptCertificateSignature, cert); break;
|
||||
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
||||
error = QSslError(QSslError::UnableToDecodeIssuerPublicKey, cert); break;
|
||||
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
|
||||
error = QSslError(QSslError::CertificateSignatureFailed, cert); break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
error = QSslError(QSslError::CertificateNotYetValid, cert); break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
error = QSslError(QSslError::CertificateExpired, cert); break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
error = QSslError(QSslError::InvalidNotBeforeField, cert); break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
error = QSslError(QSslError::InvalidNotAfterField, cert); break;
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
error = QSslError(QSslError::SelfSignedCertificate, cert); break;
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
error = QSslError(QSslError::SelfSignedCertificateInChain, cert); break;
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||
error = QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert); break;
|
||||
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
||||
error = QSslError(QSslError::UnableToVerifyFirstCertificate, cert); break;
|
||||
case X509_V_ERR_CERT_REVOKED:
|
||||
error = QSslError(QSslError::CertificateRevoked, cert); break;
|
||||
case X509_V_ERR_INVALID_CA:
|
||||
error = QSslError(QSslError::InvalidCaCertificate, cert); break;
|
||||
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
|
||||
error = QSslError(QSslError::PathLengthExceeded, cert); break;
|
||||
case X509_V_ERR_INVALID_PURPOSE:
|
||||
error = QSslError(QSslError::InvalidPurpose, cert); break;
|
||||
case X509_V_ERR_CERT_UNTRUSTED:
|
||||
error = QSslError(QSslError::CertificateUntrusted, cert); break;
|
||||
case X509_V_ERR_CERT_REJECTED:
|
||||
error = QSslError(QSslError::CertificateRejected, cert); break;
|
||||
default:
|
||||
error = QSslError(QSslError::UnspecifiedError, cert); break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void X509CertificateOpenSSL::parseExtensions()
|
||||
{
|
||||
extensions.clear();
|
||||
|
||||
if (!x509)
|
||||
return;
|
||||
|
||||
int count = q_X509_get_ext_count(x509);
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
extensions.reserve(count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
X509_EXTENSION *ext = q_X509_get_ext(x509, i);
|
||||
if (!ext) {
|
||||
qCWarning(lcTlsBackend) << "Invalid (nullptr) extension at index" << i;
|
||||
continue;
|
||||
}
|
||||
|
||||
extensions << convertExtension(ext);
|
||||
}
|
||||
|
||||
// Converting an extension may result in an error(s), clean them up:
|
||||
QTlsBackendOpenSSL::clearErrorQueue();
|
||||
}
|
||||
|
||||
X509CertificateBase::X509CertificateExtension X509CertificateOpenSSL::convertExtension(X509_EXTENSION *ext)
|
||||
{
|
||||
Q_ASSERT(ext);
|
||||
|
||||
X509CertificateExtension result;
|
||||
|
||||
ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
|
||||
if (!obj)
|
||||
return result;
|
||||
|
||||
result.oid = QString::fromUtf8(asn1ObjectId(obj));
|
||||
result.name = QString::fromUtf8(asn1ObjectName(obj));
|
||||
|
||||
result.critical = bool(q_X509_EXTENSION_get_critical(ext));
|
||||
|
||||
// Lets see if we have custom support for this one
|
||||
QVariant extensionValue = x509ExtensionToValue(ext);
|
||||
if (extensionValue.isValid()) {
|
||||
result.value = extensionValue;
|
||||
result.supported = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
extensionValue = x509UnknownExtensionToValue(ext);
|
||||
if (extensionValue.isValid())
|
||||
result.value = extensionValue;
|
||||
|
||||
result.supported = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace QSsl
|
||||
|
||||
QT_END_NAMESPACE
|
134
src/network/ssl/qx509_openssl_p.h
Normal file
134
src/network/ssl/qx509_openssl_p.h
Normal file
@ -0,0 +1,134 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QX509_OPENSSL_P_H
|
||||
#define QX509_OPENSSL_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
// TLSTODO: only temporary, and only because of QSslErrorEntry!
|
||||
#include <private/qsslsocket_openssl_p.h>
|
||||
|
||||
#include <private/qtlsbackend_p.h>
|
||||
#include <private/qx509_base_p.h>
|
||||
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
// TLSTODO: This class is essentially what qsslcertificate_openssl.cpp
|
||||
// contains - OpenSSL-based version of QSslCertificatePrivate. Remove
|
||||
// this comment when plugins are ready.
|
||||
class X509CertificateOpenSSL final : public X509CertificateBase
|
||||
{
|
||||
public:
|
||||
X509CertificateOpenSSL();
|
||||
~X509CertificateOpenSSL();
|
||||
|
||||
// TLSTODO: in future may become movable/copyable (ref-counted based
|
||||
// OpenSSL's X509 implementation).
|
||||
|
||||
bool isEqual(const X509Certificate &rhs) const override;
|
||||
bool isSelfSigned() const override;
|
||||
QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const override;
|
||||
TlsKey *publicKey() const override;
|
||||
|
||||
QByteArray toPem() const override;
|
||||
QByteArray toDer() const override;
|
||||
QString toText() const override;
|
||||
Qt::HANDLE handle() const override;
|
||||
|
||||
size_t hash(size_t seed) const noexcept override;
|
||||
|
||||
// TLSTODO: these are needed by qsslsocket_openssl and later, by
|
||||
// TLS code inside OpenSSL plugin. Remove this comment when
|
||||
// plugins are ready.
|
||||
static QSslCertificate certificateFromX509(X509 *x);
|
||||
static QList<QSslCertificate> stackOfX509ToQSslCertificates(STACK_OF(X509) *x509);
|
||||
static QSslErrorEntry errorEntryFromStoreContext(X509_STORE_CTX *ctx);
|
||||
|
||||
// TLSTODO: remove this comment when plugins are in place. This is what QSslSocketPrivate::verify()
|
||||
// in qsslsocket_openssl.cpp is (was) doing (in the past).
|
||||
static QList<QSslError> verify(const QList<QSslCertificate> &chain, const QString &hostName);
|
||||
static QList<QSslError> verify(const QList<QSslCertificate> &caCertificates,
|
||||
const QList<QSslCertificate> &certificateChain,
|
||||
const QString &hostName);
|
||||
|
||||
static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count);
|
||||
static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count);
|
||||
static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
|
||||
QList<QSslCertificate> *caCertificates,
|
||||
const QByteArray &passPhrase);
|
||||
|
||||
static QSslError openSSLErrorToQSslError(int errorCode, const QSslCertificate &cert);
|
||||
private:
|
||||
void parseExtensions();
|
||||
static X509CertificateExtension convertExtension(X509_EXTENSION *ext);
|
||||
|
||||
X509 *x509 = nullptr;
|
||||
|
||||
Q_DISABLE_COPY_MOVE(X509CertificateOpenSSL)
|
||||
};
|
||||
|
||||
extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx);
|
||||
|
||||
} // namespace QSsl.
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QX509_OPENSSL_P_H
|
61
src/network/ssl/qx509_schannel.cpp
Normal file
61
src/network/ssl/qx509_schannel.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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 "qtlskey_schannel_p.h"
|
||||
#include "qx509_schannel_p.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
TlsKey *X509CertificateSchannel::publicKey() const
|
||||
{
|
||||
auto key = std::make_unique<TlsKeySchannel>(PublicKey);
|
||||
if (publicKeyAlgorithm != QSsl::Opaque)
|
||||
key->decodeDer(PublicKey, publicKeyAlgorithm, publicKeyDerData, {}, false);
|
||||
|
||||
return key.release();
|
||||
}
|
||||
|
||||
} // namespace QSsl.
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
74
src/network/ssl/qx509_schannel_p.h
Normal file
74
src/network/ssl/qx509_schannel_p.h
Normal file
@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QX509_SCHANNEL_P_H
|
||||
#define QX509_SCHANNEL_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <private/qx509_generic_p.h>
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
class X509CertificateSchannel final : public X509CertificateGeneric
|
||||
{
|
||||
public:
|
||||
TlsKey *publicKey() const override;
|
||||
};
|
||||
|
||||
} // namespace QSsl.
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QX509_SCHANNEL_P_H
|
61
src/network/ssl/qx509_st.cpp
Normal file
61
src/network/ssl/qx509_st.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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 "qtlskey_st_p.h"
|
||||
#include "qx509_st_p.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
TlsKey *X509CertificateSecureTransport::publicKey() const
|
||||
{
|
||||
auto key = std::make_unique<TlsKeySecureTransport>(PublicKey);
|
||||
if (publicKeyAlgorithm != QSsl::Opaque)
|
||||
key->decodeDer(PublicKey, publicKeyAlgorithm, publicKeyDerData, {}, false);
|
||||
|
||||
return key.release();
|
||||
}
|
||||
|
||||
} // namespace QSsl.
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
74
src/network/ssl/qx509_st_p.h
Normal file
74
src/network/ssl/qx509_st_p.h
Normal file
@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QX509_ST_P_H
|
||||
#define QX509_ST_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <private/qx509_generic_p.h>
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSsl {
|
||||
|
||||
class X509CertificateSecureTransport final : public X509CertificateGeneric
|
||||
{
|
||||
public:
|
||||
TlsKey *publicKey() const override;
|
||||
};
|
||||
|
||||
} // namespace QSsl.
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QX509_ST_P_H
|
Loading…
x
Reference in New Issue
Block a user