summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2021-02-22 13:45:07 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2021-02-25 18:44:17 +0100
commit41fc143635c25f937a557f09890601f6c7d38736 (patch)
tree26b3b9ab137b60f6ab0f90f7b878a132f1247b72 /src
parent0ea39a7c42c923b107ae5057562b4a831f72d01d (diff)
Move QSslCertificate's details and cert-related code to the plugins
Also since we have to properly support 'no-ssl' configure option (alas, we support QSslCertificate on such builds) - introduce a minimal crippled QTlsBackendCertOnly, which depends on X509CertificateGeneric. Pick-to: dev Fixes: QTBUG-90954 Task-number: QTBUG-65922 Change-Id: Ib9d62903f16b7c0eaaa23e319a822c24a7631dc6 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/network/CMakeLists.txt15
-rw-r--r--src/network/ssl/qdtls_openssl.cpp15
-rw-r--r--src/network/ssl/qsslcertificate.cpp316
-rw-r--r--src/network/ssl/qsslcertificate.h10
-rw-r--r--src/network/ssl/qsslcertificate_openssl.cpp799
-rw-r--r--src/network/ssl/qsslcertificate_p.h96
-rw-r--r--src/network/ssl/qsslcertificate_qt.cpp580
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp2
-rw-r--r--src/network/ssl/qsslsocket_mac_shared.cpp1
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp160
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h8
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp4
-rw-r--r--src/network/ssl/qtlsbackend.cpp43
-rw-r--r--src/network/ssl/qtlsbackend_cert.cpp96
-rw-r--r--src/network/ssl/qtlsbackend_cert_p.h (renamed from src/network/ssl/qsslcertificate_schannel.cpp)48
-rw-r--r--src/network/ssl/qtlsbackend_p.h12
-rw-r--r--src/network/ssl/qtlskey_generic_p.h22
-rw-r--r--src/network/ssl/qx509_generic.cpp1
-rw-r--r--src/network/ssl/qx509_schannel.cpp25
-rw-r--r--src/network/ssl/qx509_schannel_p.h13
20 files changed, 540 insertions, 1726 deletions
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index 3ba4ef6015..03fc8ab879 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -47,6 +47,10 @@ qt_internal_add_module(Network
ssl/qsslcertificate.cpp ssl/qsslcertificate.h ssl/qsslcertificate_p.h
ssl/qsslcertificateextension.cpp ssl/qsslcertificateextension.h ssl/qsslcertificateextension_p.h
ssl/qtls_utils_p.h
+ ssl/qtlsbackend.cpp ssl/qtlsbackend_p.h
+ ssl/qtlsbackend_cert.cpp ssl/qtlsbackend_cert_p.h
+ ssl/qx509_base.cpp ssl/qx509_base_p.h
+ ssl/qx509_generic.cpp ssl/qx509_generic_p.h
DEFINES
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
@@ -310,11 +314,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_system_proxies
QT_USE_SYSTEM_PROXIES
)
-qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_openssl
- SOURCES
- ssl/qsslcertificate_qt.cpp
-)
-
qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
SOURCES
ssl/qocspresponse.cpp ssl/qocspresponse.h ssl/qocspresponse_p.h
@@ -326,14 +325,11 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
ssl/qsslkey.h ssl/qsslkey_p.cpp ssl/qsslkey_p.h
ssl/qsslpresharedkeyauthenticator.cpp ssl/qsslpresharedkeyauthenticator.h ssl/qsslpresharedkeyauthenticator_p.h
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
SOURCES
- ssl/qsslcertificate_schannel.cpp
ssl/qssldiffiehellmanparameters_dummy.cpp
ssl/qsslellipticcurve_dummy.cpp
ssl/qsslsocket_qt.cpp
@@ -341,7 +337,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_s
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
@@ -360,7 +355,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FE
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
)
@@ -371,7 +365,6 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_ssl
qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl
SOURCES
- ssl/qsslcertificate_openssl.cpp
ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h
ssl/qssldiffiehellmanparameters_openssl.cpp
ssl/qsslellipticcurve_openssl.cpp
diff --git a/src/network/ssl/qdtls_openssl.cpp b/src/network/ssl/qdtls_openssl.cpp
index 3f04ab97cd..4fc2f0a4d6 100644
--- a/src/network/ssl/qdtls_openssl.cpp
+++ b/src/network/ssl/qdtls_openssl.cpp
@@ -47,6 +47,7 @@
#include "qsslsocket_openssl_p.h"
#include "qsslcertificate_p.h"
#include "qdtls_openssl_p.h"
+#include "qx509_openssl_p.h"
#include "qudpsocket.h"
#include "qssl_p.h"
@@ -258,7 +259,7 @@ extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
}
auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
- dtls->x509Errors.append(QSslErrorEntry::fromStoreContext(ctx));
+ dtls->x509Errors.append(QSsl::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
}
// Always return 1 (OK) to allow verification to continue. We handle the
@@ -1263,9 +1264,6 @@ unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned c
return pskLength;
}
-// The definition is located in qsslsocket_openssl.cpp.
-QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &cert);
-
bool QDtlsPrivateOpenSSL::verifyPeer()
{
// DTLSTODO: Windows-specific code for CA fetcher is not here yet.
@@ -1300,10 +1298,11 @@ bool QDtlsPrivateOpenSSL::verifyPeer()
}
// Translate errors from the error list into QSslErrors
+ using CertClass = QSsl::X509CertificateOpenSSL;
errors.reserve(errors.size() + opensslErrors.size());
for (const auto &error : qAsConst(opensslErrors)) {
- errors << _q_OpenSSL_to_QSslError(error.code,
- dtlsConfiguration.peerCertificateChain.value(error.depth));
+ const auto value = dtlsConfiguration.peerCertificateChain.value(error.depth);
+ errors << CertClass::openSSLErrorToQSslError(error.code, value);
}
tlsErrors = errors;
@@ -1318,11 +1317,11 @@ void QDtlsPrivateOpenSSL::storePeerCertificates()
// peer certificate and the chain may be empty if the peer didn't present
// any certificate.
X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data());
- dtlsConfiguration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
+ dtlsConfiguration.peerCertificate = QSsl::X509CertificateOpenSSL::certificateFromX509(x509);
q_X509_free(x509);
if (dtlsConfiguration.peerCertificateChain.isEmpty()) {
auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
- dtlsConfiguration.peerCertificateChain = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(stack);
+ dtlsConfiguration.peerCertificateChain = QSsl::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack);
if (!dtlsConfiguration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
dtlsConfiguration.peerCertificateChain.prepend(dtlsConfiguration.peerCertificate);
}
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index c63ef5d205..530a9b61ca 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -131,22 +131,18 @@
*/
#include <QtNetwork/qtnetworkglobal.h>
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_symbols_p.h"
-#endif
-#ifdef QT_SECURETRANSPORT
-#include "qsslsocket_mac_p.h"
-#endif
-#if QT_CONFIG(schannel)
-#include "qsslsocket_schannel_p.h"
-#endif
+
#if QT_CONFIG(regularexpression)
#include "qregularexpression.h"
#endif
-#include "qssl_p.h"
-#include "qsslcertificate.h"
+
+#include "qsslcertificateextension_p.h"
#include "qsslcertificate_p.h"
+#include "qsslcertificate.h"
+#include "qssl_p.h"
+
#ifndef QT_NO_SSL
+#include "qsslsocket_p.h"
#include "qsslkey_p.h"
#endif
@@ -156,6 +152,21 @@
QT_BEGIN_NAMESPACE
+QSslCertificatePrivate::QSslCertificatePrivate()
+{
+#ifndef QT_NO_SSL
+ QSslSocketPrivate::ensureInitialized();
+#endif
+
+ const QTlsBackend *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (tlsBackend)
+ backend.reset(tlsBackend->createCertificate());
+ else
+ qCWarning(lcSsl, "No TLS backend is available");
+}
+
+QSslCertificatePrivate::~QSslCertificatePrivate() = default;
+
/*!
Constructs a QSslCertificate by reading \a format encoded data
from \a device and using the first certificate found. You can
@@ -165,13 +176,25 @@ QT_BEGIN_NAMESPACE
QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
: d(new QSslCertificatePrivate)
{
-#ifndef QT_NO_OPENSSL
- QSslSocketPrivate::ensureInitialized();
- if (device && QSslSocket::supportsSsl())
-#else
- if (device)
-#endif
- d->init(device->readAll(), format);
+ if (device) {
+ const auto data = device->readAll();
+ if (data.isEmpty())
+ return;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend)
+ return;
+
+ auto *X509Reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!X509Reader) {
+ qCWarning(lcSsl, "Current TLS plugin does not support reading from PEM/DER");
+ return;
+ }
+
+ QList<QSslCertificate> certs = X509Reader(data, 1);
+ if (!certs.isEmpty())
+ d = certs.first().d;
+ }
}
/*!
@@ -183,11 +206,22 @@ QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
: d(new QSslCertificatePrivate)
{
-#ifndef QT_NO_OPENSSL
- QSslSocketPrivate::ensureInitialized();
- if (QSslSocket::supportsSsl())
-#endif
- d->init(data, format);
+ if (data.isEmpty())
+ return;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend)
+ return;
+
+ auto *X509Reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!X509Reader) {
+ qCWarning(lcSsl, "Current TLS plugin does not support reading from PEM/DER");
+ return;
+ }
+
+ QList<QSslCertificate> certs = X509Reader(data, 1);
+ if (!certs.isEmpty())
+ d = certs.first().d;
}
/*!
@@ -229,6 +263,20 @@ QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
returns \c false.
*/
+bool QSslCertificate::operator==(const QSslCertificate &other) const
+{
+ if (d == other.d)
+ return true;
+
+ if (isNull() && other.isNull())
+ return true;
+
+ if (d->backend.get() && other.d->backend.get())
+ return d->backend->isEqual(*other.d->backend.get());
+
+ return false;
+}
+
/*!
\fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
@@ -246,6 +294,13 @@ QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
\sa clear()
*/
+bool QSslCertificate::isNull() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->isNull();
+
+ return true;
+}
/*!
Returns \c true if this certificate is blacklisted; otherwise
@@ -268,6 +323,13 @@ bool QSslCertificate::isBlacklisted() const
A certificate is considered self-signed its issuer and subject
are identical.
*/
+bool QSslCertificate::isSelfSigned() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->isSelfSigned();
+
+ return false;
+}
/*!
Clears the contents of this certificate, making it a null
@@ -286,12 +348,26 @@ void QSslCertificate::clear()
\fn QByteArray QSslCertificate::version() const
Returns the certificate's version string.
*/
+QByteArray QSslCertificate::version() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->version();
+
+ return {};
+}
/*!
\fn QByteArray QSslCertificate::serialNumber() const
Returns the certificate's serial number string in hexadecimal format.
*/
+QByteArray QSslCertificate::serialNumber() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->serialNumber();
+
+ return {};
+}
/*!
Returns a cryptographic digest of this certificate. By default,
@@ -313,6 +389,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfo(info);
+
+ return {};
+}
/*!
\fn QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
@@ -323,6 +406,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfo(attribute);
+
+ return {};
+}
/*!
\fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
@@ -333,6 +423,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa issuerInfo()
*/
+QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfo(info);
+
+ return {};
+}
/*!
\fn QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
@@ -343,6 +440,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa issuerInfo()
*/
+QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfo(attribute);
+
+ return {};
+}
/*!
\fn QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
@@ -356,6 +460,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfoAttributes();
+
+ return {};
+}
/*!
\fn QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
@@ -369,6 +480,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfoAttributes();
+
+ return {};
+}
/*!
\fn QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
@@ -385,6 +503,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectAlternativeNames();
+
+ return {};
+}
/*!
\fn QDateTime QSslCertificate::effectiveDate() const
@@ -394,6 +519,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa expiryDate()
*/
+QDateTime QSslCertificate::effectiveDate() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->effectiveDate();
+
+ return {};
+}
/*!
\fn QDateTime QSslCertificate::expiryDate() const
@@ -403,6 +535,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa effectiveDate()
*/
+QDateTime QSslCertificate::expiryDate() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->expiryDate();
+
+ return {};
+}
/*!
\fn Qt::HANDLE QSslCertificate::handle() const
@@ -416,11 +555,29 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
non-portable, and its return value may vary from platform to
platform or change from minor release to minor release.
*/
+Qt::HANDLE QSslCertificate::handle() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->handle();
+ return {};
+}
+
+#ifndef QT_NO_SSL
/*!
\fn QSslKey QSslCertificate::publicKey() const
Returns the certificate subject's public key.
*/
+QSslKey QSslCertificate::publicKey() const
+{
+ QSslKey key;
+ if (const auto *backend = d->backend.get())
+ QTlsBackend::resetBackend(key, backend->publicKey());
+
+ return key;
+}
+#endif // QT_NO_SSL
+
/*!
\fn QList<QSslCertificateExtension> QSslCertificate::extensions() const
@@ -428,6 +585,10 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns a list containing the X509 extensions of this certificate.
\since 5.0
*/
+QList<QSslCertificateExtension> QSslCertificate::extensions() const
+{
+ return d->extensions();
+}
/*!
\fn QByteArray QSslCertificate::toPem() const
@@ -435,6 +596,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns this certificate converted to a PEM (Base64) encoded
representation.
*/
+QByteArray QSslCertificate::toPem() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toPem();
+
+ return {};
+}
/*!
\fn QByteArray QSslCertificate::toDer() const
@@ -442,6 +610,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns this certificate converted to a DER (binary) encoded
representation.
*/
+QByteArray QSslCertificate::toDer() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toDer();
+
+ return {};
+}
/*!
\fn QString QSslCertificate::toText() const
@@ -451,6 +626,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\since 5.0
*/
+QString QSslCertificate::toText() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toText();
+
+ return {};
+}
/*!
\since 5.15
@@ -576,13 +758,22 @@ QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::Enco
*/
QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
{
- return (format == QSsl::Pem)
- ? QSslCertificatePrivate::certificatesFromPem(data)
- : QSslCertificatePrivate::certificatesFromDer(data);
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return {};
+ }
+
+ auto reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!reader) {
+ qCWarning(lcSsl, "The available TLS backend does not support reading PEM/DER");
+ return {};
+ }
+
+ return reader(data, -1);
}
#ifndef QT_NO_SSL
-
/*!
Verifies a certificate chain. The chain to be verified is passed in the
\a certificateChain parameter. The first certificate in the list should
@@ -597,13 +788,19 @@ QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::E
\since 5.0
*/
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
QList<QSslError> QSslCertificate::verify(const QList<QSslCertificate> &certificateChain, const QString &hostName)
-#else
-QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
-#endif
{
- return QSslSocketBackendPrivate::verify(certificateChain, hostName);
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return {};
+ }
+ auto verifyPtr = tlsBackend->X509Verifier();
+ if (!verifyPtr) {
+ qCWarning(lcSsl, "Available TLS backend does not support manual certificate verification");
+ return {};
+ }
+ return verifyPtr(certificateChain, hostName);
}
/*!
@@ -623,10 +820,43 @@ bool QSslCertificate::importPkcs12(QIODevice *device,
QList<QSslCertificate> *caCertificates,
const QByteArray &passPhrase)
{
- return QSslSocketBackendPrivate::importPkcs12(device, key, certificate, caCertificates, passPhrase);
+ if (!device || !key || !certificate)
+ return false;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return false;
+ }
+
+ if (auto reader = tlsBackend->X509Pkcs12Reader())
+ return reader(device, key, certificate, caCertificates, passPhrase);
+
+ qCWarning(lcSsl, "Available TLS backend does not support PKCS12");
+
+ return false;
}
+#endif // QT_NO_SSL
-#endif
+QList<QSslCertificateExtension> QSslCertificatePrivate::extensions() const
+{
+ QList<QSslCertificateExtension> result;
+
+ if (backend.get()) {
+ auto nExt = backend->numberOfExtensions();
+ for (decltype (nExt) i = 0; i < nExt; ++i) {
+ QSslCertificateExtension ext;
+ ext.d->oid = backend->oidForExtension(i);
+ ext.d->name = backend->nameForExtension(i);
+ ext.d->value = backend->valueForExtension(i);
+ ext.d->critical = backend->isExtensionCritical(i);
+ ext.d->supported = backend->isExtensionSupported(i);
+ result << ext;
+ }
+ }
+
+ return result;
+}
// These certificates are known to be fraudulent and were created during the comodo
// compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html
@@ -758,12 +988,30 @@ QString QSslCertificate::subjectDisplayName() const
}
/*!
+ \internal
+
+ Returns X509 backend this QSslCertificate is using.
+*/
+QSsl::X509Certificate *QSslCertificate::backendImplementation() const
+{
+ return d->backend.get();
+}
+
+/*!
\fn size_t qHash(const QSslCertificate &key, size_t seed)
Returns the hash value for the \a key, using \a seed to seed the calculation.
\since 5.4
\relates QHash
*/
+size_t qHash(const QSslCertificate &key, size_t seed) noexcept
+{
+ if (const auto *backend = key.d->backend.get())
+ return backend->hash(seed);
+
+ return seed;
+
+}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
index a2ba90465f..ea9c99adda 100644
--- a/src/network/ssl/qsslcertificate.h
+++ b/src/network/ssl/qsslcertificate.h
@@ -148,12 +148,7 @@ public:
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
#ifndef QT_NO_SSL
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName = QString());
-#else
- static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName = QString());
-#endif
-
static bool importPkcs12(QIODevice *device,
QSslKey *key, QSslCertificate *cert,
QList<QSslCertificate> *caCertificates = nullptr,
@@ -163,10 +158,7 @@ public:
Qt::HANDLE handle() const;
private:
- QSsl::X509Certificate *backendImplementation() const
- {
- return nullptr; // TLSTODO
- }
+ QSsl::X509Certificate *backendImplementation() const;
QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
friend class QSslCertificatePrivate;
friend class QSslSocketBackendPrivate;
diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp
deleted file mode 100644
index 2d85171c75..0000000000
--- a/src/network/ssl/qsslcertificate_openssl.cpp
+++ /dev/null
@@ -1,799 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qssl_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslcertificate_p.h"
-#include "qsslkey_p.h"
-#include "qsslcertificateextension_p.h"
-#include "qtlsbackend_openssl_p.h"
-#include "qtlskey_openssl_p.h"
-
-#include <QtCore/qendian.h>
-#include <QtCore/qmutex.h>
-
-QT_BEGIN_NAMESPACE
-
-constexpr int MutexPoolSize = 17;
-static QBasicMutex mutexPool[MutexPoolSize];
-namespace QMutexPool {
- static QBasicMutex *globalInstanceGet(const void *addr)
- {
- return mutexPool + (quintptr(addr) % MutexPoolSize);
- }
-}
-
-// forward declaration
-static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name);
-
-bool QSslCertificate::operator==(const QSslCertificate &other) const
-{
- if (d == other.d)
- return true;
-
- if (d->null && other.d->null)
- return true;
-
- if (d->x509 && other.d->x509) {
- const int ret = q_X509_cmp(d->x509, other.d->x509);
- if (ret >= -1 && ret <= 1)
- return ret == 0;
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- }
-
- return false;
-}
-
-size_t qHash(const QSslCertificate &key, size_t seed) noexcept
-{
- if (X509 * const x509 = key.d->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;
-}
-
-bool QSslCertificate::isNull() const
-{
- return d->null;
-}
-
-bool QSslCertificate::isSelfSigned() const
-{
- if (!d->x509)
- return false;
-
- return (q_X509_check_issued(d->x509, d->x509) == X509_V_OK);
-}
-
-QByteArray QSslCertificate::version() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- if (d->versionString.isEmpty() && d->x509)
- d->versionString = QByteArray::number(qlonglong(q_X509_get_version(d->x509)) + 1);
-
- return d->versionString;
-}
-
-QByteArray QSslCertificate::serialNumber() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- if (d->serialNumberString.isEmpty() && d->x509) {
- ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(d->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);
- d->serialNumberString = hexString;
- }
- return d->serialNumberString;
-}
-
-QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.values(d->subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.values(attribute);
-}
-
-QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.values(d->subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.values(attribute);
-}
-
-QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.uniqueKeys();
-}
-
-QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.uniqueKeys();
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
-{
- QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
-
- if (!d->x509)
- return result;
-
- STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME) *)q_X509_get_ext_d2i(
- d->x509, NID_subject_alt_name, nullptr, nullptr);
-
- 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);
- };
- if (altNames) {
- 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;
-
- 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;
-}
-
-QDateTime QSslCertificate::effectiveDate() const
-{
- return d->notValidBefore;
-}
-
-QDateTime QSslCertificate::expiryDate() const
-{
- return d->notValidAfter;
-}
-
-Qt::HANDLE QSslCertificate::handle() const
-{
- return Qt::HANDLE(d->x509);
-}
-
-QSslKey QSslCertificate::publicKey() const
-{
- if (!d->x509)
- return QSslKey();
-
- QSslKey key;
-
- auto *tlsKey = QTlsBackend::backend<QSsl::TlsKeyOpenSSL>(key);
- tlsKey->keyType = QSsl::PublicKey;
-
- EVP_PKEY *pkey = q_X509_get_pubkey(d->x509);
- Q_ASSERT(pkey);
- const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
-
- if (keyType == EVP_PKEY_RSA) {
- tlsKey->rsa = q_EVP_PKEY_get1_RSA(pkey);
- tlsKey->keyAlgorithm = QSsl::Rsa;
- tlsKey->keyIsNull = false;
- } else if (keyType == EVP_PKEY_DSA) {
- tlsKey->dsa = q_EVP_PKEY_get1_DSA(pkey);
- tlsKey->keyAlgorithm = QSsl::Dsa;
- tlsKey->keyIsNull = false;
-#ifndef OPENSSL_NO_EC
- } else if (keyType == EVP_PKEY_EC) {
- tlsKey->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
- tlsKey->keyAlgorithm = QSsl::Ec;
- tlsKey->keyIsNull = false;
-#endif
- } else if (keyType == EVP_PKEY_DH) {
- // DH unsupported
- } else {
- // error?
- }
-
- q_EVP_PKEY_free(pkey);
- return key;
-}
-
-/*
- * Convert unknown extensions to a QVariant.
- */
-static 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;
- }
-
- //const unsigned char *data = ext->value->data;
- 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.
- */
-static 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 QVariant();
-
- 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 QVariant();
-
- 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(QSslCertificatePrivate::asn1ObjectName(ad->method))] = uri;
- } else {
- qCWarning(lcSsl) << "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 QVariant();
- // 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 QVariant();
-
- 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 QVariant();
-}
-
-QSslCertificateExtension QSslCertificatePrivate::convertExtension(X509_EXTENSION *ext)
-{
- Q_ASSERT(ext);
-
- QSslCertificateExtension result;
-
- ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
- if (!obj) {
- qCWarning(lcSsl, "Invalid (nullptr) ASN1_OBJECT");
- return result;
- }
-
- QByteArray oid = QSslCertificatePrivate::asn1ObjectId(obj);
- QByteArray name = QSslCertificatePrivate::asn1ObjectName(obj);
-
- result.d->oid = QString::fromUtf8(oid);
- result.d->name = QString::fromUtf8(name);
-
- bool critical = q_X509_EXTENSION_get_critical(ext);
- result.d->critical = critical;
-
- // Lets see if we have custom support for this one
- QVariant extensionValue = x509ExtensionToValue(ext);
- if (extensionValue.isValid()) {
- result.d->value = extensionValue;
- result.d->supported = true;
-
- return result;
- }
-
- extensionValue = x509UnknownExtensionToValue(ext);
- if (extensionValue.isValid()) {
- result.d->value = extensionValue;
- result.d->supported = false;
- return result;
- }
-
- return result;
-}
-
-QList<QSslCertificateExtension> QSslCertificate::extensions() const
-{
- QList<QSslCertificateExtension> result;
-
- if (!d->x509)
- return result;
-
- int count = q_X509_get_ext_count(d->x509);
- if (count <= 0)
- return result;
-
- result.reserve(count);
-
- for (int i = 0; i < count; i++) {
- X509_EXTENSION *ext = q_X509_get_ext(d->x509, i);
- if (!ext) {
- qCWarning(lcSsl) << "Invalid (nullptr) extension at index" << i;
- continue;
- }
- result << QSslCertificatePrivate::convertExtension(ext);
- }
-
- // Converting an extension may result in an error(s), clean them up.
- Q_UNUSED(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
-
- return result;
-}
-
-QByteArray QSslCertificate::toPem() const
-{
- if (!d->x509)
- return QByteArray();
- return d->QByteArray_from_X509(d->x509, QSsl::Pem);
-}
-
-QByteArray QSslCertificate::toDer() const
-{
- if (!d->x509)
- return QByteArray();
- return d->QByteArray_from_X509(d->x509, QSsl::Der);
-}
-
-QString QSslCertificate::toText() const
-{
- if (!d->x509)
- return QString();
- return d->text_from_X509(d->x509);
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
-{
- if (!data.isEmpty()) {
- const QList<QSslCertificate> certs = (format == QSsl::Pem)
- ? certificatesFromPem(data, 1)
- : certificatesFromDer(data, 1);
- if (!certs.isEmpty()) {
- *this = *certs.first().d;
- if (x509)
- x509 = q_X509_dup(x509);
- }
- }
-}
-
-// ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
-QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
-{
- if (!x509) {
- qCWarning(lcSsl, "QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
- return QByteArray();
- }
-
- // Use i2d_X509 to convert the X509 to an array.
- int length = q_i2d_X509(x509, nullptr);
- 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 QSslCertificatePrivate::text_from_X509(X509 *x509)
-{
- if (!x509) {
- qCWarning(lcSsl, "QSslSocketBackendPrivate::text_from_X509: null X509");
- return QString();
- }
-
- QByteArray result;
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return QString();
-
- 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 );
- }
-
- q_BIO_free(bio);
-
- return QString::fromLatin1(result);
-}
-
-QByteArray QSslCertificatePrivate::asn1ObjectId(ASN1_OBJECT *object)
-{
- 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 QSslCertificatePrivate::asn1ObjectName(ASN1_OBJECT *object)
-{
- int nid = q_OBJ_obj2nid(object);
- if (nid != NID_undef)
- return QByteArray(q_OBJ_nid2sn(nid));
-
- return asn1ObjectId(object);
-}
-
-static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name)
-{
- 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 = QSslCertificatePrivate::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));
-#if QT_CONFIG(opensslv11)
- q_CRYPTO_free(data, nullptr, 0);
-#else
- q_CRYPTO_free(data);
-#endif
- }
-
- return info;
-}
-
-QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
-{
- QSslCertificate certificate;
- if (!x509 || !QSslSocket::supportsSsl())
- return certificate;
-
- ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
- ASN1_TIME *naft = q_X509_getm_notAfter(x509);
-
- certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
- certificate.d->notValidAfter = q_getTimeFromASN1(naft);
- certificate.d->null = false;
- certificate.d->x509 = q_X509_dup(x509);
-
- return certificate;
-}
-
-static bool matchLineFeed(const QByteArray &pem, int *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;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
-{
- QList<QSslCertificate> certificates;
- QSslSocketPrivate::ensureInitialized();
-
- 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 << QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- }
- }
-
- return certificates;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
- QSslSocketPrivate::ensureInitialized();
-
- 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 << QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- } else {
- break;
- }
- size -= ((const char *)data - der.data());
- }
-
- return certificates;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
index 4588aa7d6f..33db88d8fa 100644
--- a/src/network/ssl/qsslcertificate_p.h
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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.
@@ -38,11 +38,8 @@
****************************************************************************/
-#ifndef QSSLCERTIFICATE_OPENSSL_P_H
-#define QSSLCERTIFICATE_OPENSSL_P_H
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qsslcertificate.h"
+#ifndef QSSLCERTIFICATE_P_H
+#define QSSLCERTIFICATE_P_H
//
// W A R N I N G
@@ -55,99 +52,34 @@
// We mean it.
//
-#ifndef QT_NO_SSL
-#include "qsslsocket_p.h"
-#endif
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
#include "qsslcertificateextension.h"
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmap.h>
+#include "qsslcertificate.h"
+#include "qtlsbackend_p.h"
-#ifndef QT_NO_OPENSSL
-#include <openssl/x509.h>
-#else
-struct X509;
-struct X509_EXTENSION;
-struct ASN1_OBJECT;
-#endif
+#include <qlist.h>
-#if QT_CONFIG(schannel)
-#include <wincrypt.h>
-#endif
+#include <memory>
QT_BEGIN_NAMESPACE
-// forward declaration
-
class QSslCertificatePrivate
{
public:
- QSslCertificatePrivate()
- : null(true), x509(nullptr)
- {
-#ifndef QT_NO_SSL
- QSslSocketPrivate::ensureInitialized();
-#endif
- }
-
- ~QSslCertificatePrivate()
- {
-#ifndef QT_NO_OPENSSL
- if (x509)
- q_X509_free(x509);
-#endif
-#if QT_CONFIG(schannel)
- if (certificateContext)
- CertFreeCertificateContext(certificateContext);
-#endif
- }
+ QSslCertificatePrivate();
+ ~QSslCertificatePrivate();
- bool null;
- QByteArray versionString;
- QByteArray serialNumberString;
-
- QMultiMap<QByteArray, QString> issuerInfo;
- QMultiMap<QByteArray, QString> subjectInfo;
- QDateTime notValidAfter;
- QDateTime notValidBefore;
-
-#ifdef QT_NO_OPENSSL
- bool subjectMatchesIssuer;
- QSsl::KeyAlgorithm publicKeyAlgorithm;
- QByteArray publicKeyDerData;
- QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames;
- QList<QSslCertificateExtension> extensions;
-
- QByteArray derData;
-
- bool parse(const QByteArray &data);
- bool parseExtension(const QByteArray &data, QSslCertificateExtension *extension);
-#endif
- X509 *x509;
-
- void init(const QByteArray &data, QSsl::EncodingFormat format);
-
- static QByteArray asn1ObjectId(ASN1_OBJECT *object);
- static QByteArray asn1ObjectName(ASN1_OBJECT *object);
- static QByteArray QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format);
- static QString text_from_X509(X509 *x509);
- static QSslCertificate QSslCertificate_from_X509(X509 *x509);
- static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count = -1);
- static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count = -1);
+ QList<QSslCertificateExtension> extensions() const;
static bool isBlacklisted(const QSslCertificate &certificate);
- static QSslCertificateExtension convertExtension(X509_EXTENSION *ext);
static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
friend class QSslSocketBackendPrivate;
QAtomicInt ref;
-
-#if QT_CONFIG(schannel)
- const CERT_CONTEXT *certificateContext = nullptr;
-
- static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext);
-#endif
+ std::unique_ptr<QSsl::X509Certificate> backend;
};
QT_END_NAMESPACE
-#endif // QSSLCERTIFICATE_OPENSSL_P_H
+#endif // QSSLCERTIFICATE_P_H
diff --git a/src/network/ssl/qsslcertificate_qt.cpp b/src/network/ssl/qsslcertificate_qt.cpp
deleted file mode 100644
index a8efecc3f6..0000000000
--- a/src/network/ssl/qsslcertificate_qt.cpp
+++ /dev/null
@@ -1,580 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qsslcertificate.h"
-#include "qsslcertificate_p.h"
-
-#include "qssl_p.h"
-#ifndef QT_NO_SSL
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-#include "qtlskey_generic_p.h"
-#include "qtlsbackend_p.h"
-#endif
-#include "qsslcertificateextension.h"
-#include "qsslcertificateextension_p.h"
-#include "qasn1element_p.h"
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qendian.h>
-#include <QtNetwork/qhostaddress.h>
-
-QT_BEGIN_NAMESPACE
-
-bool QSslCertificate::operator==(const QSslCertificate &other) const
-{
- if (d == other.d)
- return true;
- if (d->null && other.d->null)
- return true;
- return d->derData == other.d->derData;
-}
-
-size_t qHash(const QSslCertificate &key, size_t seed) noexcept
-{
- // DER is the native encoding here, so toDer() is just "return d->derData":
- return qHash(key.toDer(), seed);
-}
-
-bool QSslCertificate::isNull() const
-{
- return d->null;
-}
-
-bool QSslCertificate::isSelfSigned() const
-{
- if (d->null)
- return false;
-
- qCWarning(lcSsl,
- "QSslCertificate::isSelfSigned: This function does not check, whether the certificate "
- "is actually signed. It just checks whether issuer and subject are identical");
- return d->subjectMatchesIssuer;
-}
-
-QByteArray QSslCertificate::version() const
-{
- return d->versionString;
-}
-
-QByteArray QSslCertificate::serialNumber() const
-{
- return d->serialNumberString;
-}
-
-QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
-{
- return issuerInfo(QSslCertificatePrivate::subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
-{
- return d->issuerInfo.values(attribute);
-}
-
-QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
-{
- return subjectInfo(QSslCertificatePrivate::subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
-{
- return d->subjectInfo.values(attribute);
-}
-
-QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
-{
- return d->subjectInfo.uniqueKeys();
-}
-
-QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
-{
- return d->issuerInfo.uniqueKeys();
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
-{
- return d->subjectAlternativeNames;
-}
-
-QDateTime QSslCertificate::effectiveDate() const
-{
- return d->notValidBefore;
-}
-
-QDateTime QSslCertificate::expiryDate() const
-{
- return d->notValidAfter;
-}
-
-#if !QT_CONFIG(schannel) // implemented in qsslcertificate_schannel.cpp
-Qt::HANDLE QSslCertificate::handle() const
-{
- Q_UNIMPLEMENTED();
- return nullptr;
-}
-#endif
-
-#ifndef QT_NO_SSL
-QSslKey QSslCertificate::publicKey() const
-{
- QSslKey key;
- auto *tlsKey = QTlsBackend::backend<QSsl::TlsKeyGeneric>(key);
- if (!tlsKey)
- return key;
-
- tlsKey->keyType = QSsl::PublicKey;
- if (d->publicKeyAlgorithm != QSsl::Opaque)
- tlsKey->decodeDer(QSsl::PublicKey, d->publicKeyAlgorithm, d->publicKeyDerData, {}, false);
-
- return key;
-}
-#endif
-
-QList<QSslCertificateExtension> QSslCertificate::extensions() const
-{
- return d->extensions;
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-QByteArray QSslCertificate::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 QSslCertificate::toDer() const
-{
- return d->derData;
-}
-
-QString QSslCertificate::toText() const
-{
- Q_UNIMPLEMENTED();
- return QString();
-}
-
-void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
-{
- if (!data.isEmpty()) {
- const QList<QSslCertificate> certs = (format == QSsl::Pem)
- ? certificatesFromPem(data, 1)
- : certificatesFromDer(data, 1);
- if (!certs.isEmpty()) {
- *this = *certs.first().d;
-#if QT_CONFIG(schannel)
- if (certificateContext)
- certificateContext = CertDuplicateCertificateContext(certificateContext);
-#endif
- }
- }
-}
-
-static bool matchLineFeed(const QByteArray &pem, int *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;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::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> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
-
- QByteArray data = der;
- while (count == -1 || certificates.size() < count) {
- QSslCertificate cert;
- if (!cert.d->parse(data))
- break;
-
- certificates << cert;
- data.remove(0, cert.d->derData.size());
- }
-
- return certificates;
-}
-
-static 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(':');
-}
-
-bool QSslCertificatePrivate::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());
- issuerInfo = 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());
- subjectInfo = 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) {
- QSslCertificateExtension 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:
- subjectAlternativeNames.insert(QSsl::EmailEntry, nameElem.toString());
- extValue[QStringLiteral("email")] = nameElem.toString();
- break;
- case QAsn1Element::DnsNameType:
- subjectAlternativeNames.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()) {
- subjectAlternativeNames.insert(QSsl::IpAddressEntry, ipAddress.toString());
- extValue[QStringLiteral("IP")] = ipAddress.toString();
- }
- break;
- }
- default:
- break;
- }
- }
- extension.d->value = extValue;
- extension.d->supported = true;
- }
- }
-
- extensions << extension;
- }
- }
- }
- }
-
- derData = data.left(dataStream.device()->pos());
- null = false;
- return true;
-}
-
-bool QSslCertificatePrivate::parseExtension(const QByteArray &data, QSslCertificateExtension *extension)
-{
- bool ok;
- 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->d->critical = critical;
- extension->d->supported = supported;
- extension->d->oid = QString::fromLatin1(oid);
- extension->d->name = QString::fromLatin1(oidElem.toObjectName());
- extension->d->value = value;
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index 3747456bf7..9bcec5f7b3 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -1382,7 +1382,7 @@ bool QSslSocketBackendPrivate::verifyPeerTrust()
// verify certificate chain
QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
for (const QSslCertificate &cert : qAsConst(configuration.caCertificates)) {
- QCFType<CFDataRef> certData = cert.d->derData.toCFData();
+ QCFType<CFDataRef> certData = cert.toDer().toCFData();
if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
CFArrayAppendValue(certArray, secRef);
else
diff --git a/src/network/ssl/qsslsocket_mac_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp
index 09f283775b..c2ade1c702 100644
--- a/src/network/ssl/qsslsocket_mac_shared.cpp
+++ b/src/network/ssl/qsslsocket_mac_shared.cpp
@@ -43,6 +43,7 @@
#include "qssl_p.h"
#include "qsslsocket.h"
+#include "qsslsocket_p.h"
#ifndef QT_NO_OPENSSL
# include "qsslsocket_openssl_p.h"
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index bd3cf4d797..fe59d6dab2 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -65,6 +65,7 @@
#include "qsslellipticcurve.h"
#include "qsslpresharedkeyauthenticator.h"
#include "qsslpresharedkeyauthenticator_p.h"
+#include "qtlsbackend_openssl_p.h"
#include "qocspresponse_p.h"
#include "qsslkey.h"
#include "qtlsbackend_openssl_p.h"
@@ -463,14 +464,6 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER
return ciph;
}
-QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
-{
- return {
- q_X509_STORE_CTX_get_error(ctx),
- q_X509_STORE_CTX_get_error_depth(ctx)
- };
-}
-
#if QT_CONFIG(ocsp)
QSslError::SslError qt_OCSP_response_status_to_SslError(long code)
@@ -612,7 +605,7 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx)
return 0;
}
- errors->append(QSslErrorEntry::fromStoreContext(ctx));
+ errors->append(QSsl::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
}
// Always return OK to allow verification to continue. We handle the
// errors gracefully after collecting all errors, after verification has
@@ -1334,55 +1327,6 @@ void QSslSocketBackendPrivate::transmit()
} while (ssl && transmitting);
}
-QSslError _q_OpenSSL_to_QSslError(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;
-}
-
QString QSslSocketBackendPrivate::msgErrorsDuringHandshake()
{
return QSslSocket::tr("Error during SSL handshake: %1")
@@ -1422,7 +1366,7 @@ bool QSslSocketBackendPrivate::startHandshake()
if (!errorsReportedFromCallback) {
for (const auto &currentError : qAsConst(lastErrors)) {
- emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.code,
+ emit q->peerVerifyError(QSsl::X509CertificateOpenSSL::openSSLErrorToQSslError(currentError.code,
configuration.peerCertificateChain.value(currentError.depth)));
if (q->state() != QAbstractSocket::ConnectedState)
break;
@@ -1538,7 +1482,7 @@ bool QSslSocketBackendPrivate::startHandshake()
// Translate errors from the error list into QSslErrors.
errors.reserve(errors.size() + errorList.size());
for (const auto &error : qAsConst(errorList))
- errors << _q_OpenSSL_to_QSslError(error.code, configuration.peerCertificateChain.value(error.depth));
+ errors << QSsl::X509CertificateOpenSSL::openSSLErrorToQSslError(error.code, configuration.peerCertificateChain.value(error.depth));
if (!errors.isEmpty()) {
sslErrors = errors;
@@ -1589,10 +1533,10 @@ void QSslSocketBackendPrivate::storePeerCertificates()
// peer certificate and the chain may be empty if the peer didn't present
// any certificate.
X509 *x509 = q_SSL_get_peer_certificate(ssl);
- configuration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
+ configuration.peerCertificate = QSsl::X509CertificateOpenSSL::certificateFromX509(x509);
q_X509_free(x509);
if (configuration.peerCertificateChain.isEmpty()) {
- configuration.peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl));
+ configuration.peerCertificateChain = QSsl::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(q_SSL_get_peer_cert_chain(ssl));
if (!configuration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
configuration.peerCertificateChain.prepend(configuration.peerCertificate);
}
@@ -1932,7 +1876,7 @@ bool QSslSocketBackendPrivate::checkOcspStatus()
matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, issuer);
if (matchFound) {
if (q_X509_check_issued(issuer, peerX509) == X509_V_OK) {
- dResponse->signerCert = QSslCertificatePrivate::QSslCertificate_from_X509(issuer);
+ dResponse->signerCert = QSsl::X509CertificateOpenSSL::certificateFromX509(issuer);
break;
}
matchFound = false;
@@ -2033,10 +1977,10 @@ int QSslSocketBackendPrivate::emitErrorFromCallback(X509_STORE_CTX *ctx)
qCWarning(lcSsl, "Could not obtain the certificate (that failed to verify)");
return 0;
}
- const QSslCertificate certificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
- const auto errorAndDepth = QSslErrorEntry::fromStoreContext(ctx);
- const QSslError tlsError = _q_OpenSSL_to_QSslError(errorAndDepth.code, certificate);
+ const QSslCertificate certificate = QSsl::X509CertificateOpenSSL::certificateFromX509(x509);
+ const auto errorAndDepth = QSsl::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx);
+ const QSslError tlsError = QSsl::X509CertificateOpenSSL::openSSLErrorToQSslError(errorAndDepth.code, certificate);
errorsReportedFromCallback = true;
handshakeInterrupted = true;
@@ -2310,17 +2254,6 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
#endif
}
-QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509)
-{
- ensureInitialized();
- QList<QSslCertificate> certificates;
- for (int i = 0; i < q_sk_X509_num(x509); ++i) {
- if (X509 *entry = q_sk_X509_value(x509, i))
- certificates << QSslCertificatePrivate::QSslCertificate_from_X509(entry);
- }
- return certificates;
-}
-
QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain,
const QString &hostName)
{
@@ -2334,79 +2267,6 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &
return QSsl::X509CertificateOpenSSL::verify(caCertificates, certificateChain, hostName);
}
-bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- if (!supportsSsl())
- return false;
-
- // 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());
-
- // Create the PKCS#12 object
- PKCS12 *p12 = q_d2i_PKCS12_bio(bio, nullptr);
- if (!p12) {
- qCWarning(lcSsl, "Unable to read PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- q_BIO_free(bio);
- return false;
- }
-
- // Extract the data
- EVP_PKEY *pkey = nullptr;
- X509 *x509;
- STACK_OF(X509) *ca = nullptr;
-
- if (!q_PKCS12_parse(p12, passPhrase.constData(), &pkey, &x509, &ca)) {
- qCWarning(lcSsl, "Unable to parse PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- q_PKCS12_free(p12);
- q_BIO_free(bio);
- return false;
- }
-
- // Convert to Qt types
- auto *tlsKey = QTlsBackend::backend<QSsl::TlsKeyOpenSSL>(*key);
- if (!tlsKey || !tlsKey->fromEVP_PKEY(pkey)) {
- qCWarning(lcSsl, "Unable to convert private key");
- q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
- reinterpret_cast<void (*)(void *)>(q_X509_free));
- q_X509_free(x509);
- q_EVP_PKEY_free(pkey);
- q_PKCS12_free(p12);
- q_BIO_free(bio);
-
- return false;
- }
-
- *cert = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
-
- if (caCertificates)
- *caCertificates = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(ca);
-
- // Clean up
- q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
- reinterpret_cast<void (*)(void *)>(q_X509_free));
-
- q_X509_free(x509);
- q_EVP_PKEY_free(pkey);
- q_PKCS12_free(p12);
- q_BIO_free(bio);
-
- return true;
-}
-
void QSslSocketPrivate::registerAdHocFactory()
{
// TLSTODO: this is a temporary solution, waiting for
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index b45bbb0a30..1e79468958 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -110,9 +110,8 @@ QT_BEGIN_NAMESPACE
struct QSslErrorEntry {
int code;
int depth;
-
- static QSslErrorEntry fromStoreContext(X509_STORE_CTX *ctx);
};
+
Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
class QSslSocketBackendPrivate : public QSslSocketPrivate
@@ -179,16 +178,11 @@ public:
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher);
- static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName);
static QList<QSslError> verify(const QList<QSslCertificate> &cas, const QList<QSslCertificate> &certificateChain,
const QString &hostName);
static QString getErrorsFromOpenSsl();
static void logAndClearErrorQueue();
- static bool importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase);
static QString msgErrorsDuringHandshake();
};
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
index b9ee321939..c417ca747e 100644
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ b/src/network/ssl/qsslsocket_schannel.cpp
@@ -630,7 +630,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
PCCERT_CONTEXT pc = nullptr;
while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
CERT_FIND_ANY, nullptr, pc))) {
- systemCerts.append(QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(pc));
+ systemCerts.append(QSsl::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(pc));
}
}
return systemCerts;
@@ -1991,7 +1991,7 @@ bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
return QSslCertificate();
const CERT_CONTEXT *certContext = element->pCertContext;
- return QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(certContext);
+ return QSsl::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(certContext);
};
// Pick a chain to use as the certificate chain, if multiple are available:
diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp
index 1df462e362..dcffb0afd1 100644
--- a/src/network/ssl/qtlsbackend.cpp
+++ b/src/network/ssl/qtlsbackend.cpp
@@ -38,7 +38,15 @@
****************************************************************************/
#include "qtlsbackend_p.h"
+
+#if QT_CONFIG(ssl)
#include "qsslsocket_p.h"
+#include "qsslkey_p.h"
+#include "qsslkey.h"
+#else
+#include "qtlsbackend_cert_p.h"
+#endif
+
#include "qssl_p.h"
#include <QtCore/private/qfactoryloader_p.h>
@@ -93,8 +101,13 @@ public:
while (loader->instance(index))
++index;
- // TLSTODO: obviously, this one should go away:
+ // TLSTODO: obviously, these two below should
+ // disappear as soon as plugins are in place.
+#if QT_CONFIG(ssl)
QSslSocketPrivate::registerAdHocFactory();
+#else
+ static QTlsBackendCertOnly certGenerator;
+#endif // QT_CONFIG(ssl)
return loaded = true;
}
@@ -180,6 +193,12 @@ QByteArray TlsKey::pemFooter() const
X509Certificate::~X509Certificate() = default;
+TlsKey *X509Certificate::publicKey() const
+{
+ // 'no-ssl' build has no key support either.
+ return nullptr;
+}
+
} // namespace QSsl
const QString QTlsBackend::builtinBackendNames[] = {
@@ -286,6 +305,9 @@ QString QTlsBackend::defaultBackendName()
if (names.contains(name))
return name;
+ if (names.size())
+ return names[0];
+
return {};
}
@@ -301,6 +323,15 @@ QTlsBackend *QTlsBackend::findBackend(const QString &backendName)
return nullptr;
}
+QTlsBackend *QTlsBackend::activeOrAnyBackend()
+{
+#if QT_CONFIG(ssl)
+ return QSslSocketPrivate::tlsBackendInUse();
+#else
+ return findBackend(defaultBackendName());
+#endif // QT_CONFIG(ssl)
+}
+
QList<QSsl::SslProtocol> QTlsBackend::supportedProtocols(const QString &backendName)
{
if (!backends())
@@ -334,4 +365,14 @@ QList<QSsl::ImplementedClass> QTlsBackend::implementedClasses(const QString &bac
return {};
}
+void QTlsBackend::resetBackend(QSslKey &key, QSsl::TlsKey *keyBackend)
+{
+#if QT_CONFIG(ssl)
+ key.d->keyBackend.reset(keyBackend);
+#else
+ Q_UNUSED(key);
+ Q_UNUSED(keyBackend);
+#endif // QT_CONFIG(ssl)
+}
+
QT_END_NAMESPACE
diff --git a/src/network/ssl/qtlsbackend_cert.cpp b/src/network/ssl/qtlsbackend_cert.cpp
new file mode 100644
index 0000000000..03451b2ad1
--- /dev/null
+++ b/src/network/ssl/qtlsbackend_cert.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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_cert_p.h"
+
+#ifdef QT_NO_SSL
+
+#include "qx509_generic_p.h"
+
+#include <qssl.h>
+
+#include <qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.cert-only");
+
+QString QTlsBackendCertOnly::backendName() const
+{
+ return QStringLiteral("cert-only");
+}
+
+
+QList<QSsl::SslProtocol> QTlsBackendCertOnly::supportedProtocols() const
+{
+ return {};
+}
+
+QList<QSsl::SupportedFeature> QTlsBackendCertOnly::supportedFeatures() const
+{
+ return {};
+}
+
+QList<QSsl::ImplementedClass> QTlsBackendCertOnly::implementedClasses() const
+{
+ QList<QSsl::ImplementedClass> classes;
+ classes << QSsl::ImplementedClass::Certificate;
+
+ return classes;
+}
+
+QSsl::X509Certificate *QTlsBackendCertOnly::createCertificate() const
+{
+ return new QSsl::X509CertificateGeneric;
+}
+
+QSsl::X509PemReaderPtr QTlsBackendCertOnly::X509PemReader() const
+{
+ return QSsl::X509CertificateGeneric::certificatesFromPem;
+}
+
+QSsl::X509DerReaderPtr QTlsBackendCertOnly::X509DerReader() const
+{
+ return QSsl::X509CertificateGeneric::certificatesFromDer;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SSL
+
diff --git a/src/network/ssl/qsslcertificate_schannel.cpp b/src/network/ssl/qtlsbackend_cert_p.h
index 5ea713612a..86c93dc310 100644
--- a/src/network/ssl/qsslcertificate_schannel.cpp
+++ b/src/network/ssl/qtlsbackend_cert_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** 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.
@@ -37,26 +37,44 @@
**
****************************************************************************/
-#include "qsslcertificate.h"
-#include "qsslcertificate_p.h"
+#ifndef QTLSBACKEND_CERT_P_H
+#define QTLSBACKEND_CERT_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>
-#include <wincrypt.h>
QT_BEGIN_NAMESPACE
-QSslCertificate QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
+class QTlsBackendCertOnly final : public QTlsBackend
{
- QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
- certificateContext->cbCertEncoded);
+public:
+private:
+ QString backendName() const override;
- QSslCertificate certificate(derData, QSsl::Der);
- certificate.d->certificateContext = CertDuplicateCertificateContext(certificateContext);
- return certificate;
-}
+ QList<QSsl::SslProtocol> supportedProtocols() const override;
+ QList<QSsl::SupportedFeature> supportedFeatures() const override;
+ QList<QSsl::ImplementedClass> implementedClasses() const override;
-Qt::HANDLE QSslCertificate::handle() const
-{
- return Qt::HANDLE(d->certificateContext);
-}
+ QSsl::X509Certificate *createCertificate() const override;
+ QSsl::X509PemReaderPtr X509PemReader() const override;
+ QSsl::X509DerReaderPtr X509DerReader() const override;
+};
QT_END_NAMESPACE
+
+#endif // QTLSBACKEND_CERT_P_H
diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h
index c1d5137ca3..d560288b5e 100644
--- a/src/network/ssl/qtlsbackend_p.h
+++ b/src/network/ssl/qtlsbackend_p.h
@@ -51,10 +51,9 @@
// We mean it.
//
-#include <private/qtnetworkglobal_p.h>
+#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <private/qsslkey_p.h>
-#include <private/qssl_p.h>
+#include "qssl_p.h"
#include <QtNetwork/qsslcertificate.h>
#include <QtNetwork/qsslerror.h>
@@ -76,6 +75,7 @@ QT_BEGIN_NAMESPACE
class QByteArray;
class QIODevice;
+class QSslKey;
namespace QSsl {
@@ -147,7 +147,8 @@ public:
virtual QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const = 0;
virtual QDateTime effectiveDate() const = 0;
virtual QDateTime expiryDate() const = 0;
- virtual TlsKey *publicKey() const = 0;
+
+ virtual TlsKey *publicKey() const;
// Extensions. Plugins do not expose internal representation
// and cannot rely on QSslCertificate's internals.
@@ -220,6 +221,7 @@ public:
static QList<QString> availableBackendNames();
static QString defaultBackendName();
static QTlsBackend *findBackend(const QString &backendName);
+ static QTlsBackend *activeOrAnyBackend();
static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName);
static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName);
@@ -238,6 +240,8 @@ public:
return static_cast<DynamicType *>(o.backendImplementation());
}
+ static void resetBackend(QSslKey &key, QSsl::TlsKey *keyBackend);
+
Q_DISABLE_COPY_MOVE(QTlsBackend)
};
diff --git a/src/network/ssl/qtlskey_generic_p.h b/src/network/ssl/qtlskey_generic_p.h
index acda061d08..6c2666bcf0 100644
--- a/src/network/ssl/qtlskey_generic_p.h
+++ b/src/network/ssl/qtlskey_generic_p.h
@@ -101,28 +101,6 @@ public:
return pkcs8;
}
- QByteArray decrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const override
- {
- // The real implementation is to be provided by Schannel or SecureTransport.
- Q_UNUSED(cipher)
- Q_UNUSED(data)
- Q_UNUSED(key)
- Q_UNUSED(iv)
-
- return {};
- }
- QByteArray encrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const override
- {
- // The real implementation is to be provided by Schannel or SecureTransport.
- Q_UNUSED(cipher)
- Q_UNUSED(data)
- Q_UNUSED(key)
- Q_UNUSED(iv)
-
- return {};
- }
private:
QByteArray decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase);
diff --git a/src/network/ssl/qx509_generic.cpp b/src/network/ssl/qx509_generic.cpp
index 9d982d31f5..535fbe5fd2 100644
--- a/src/network/ssl/qx509_generic.cpp
+++ b/src/network/ssl/qx509_generic.cpp
@@ -37,7 +37,6 @@
**
****************************************************************************/
-#include "qtlskey_generic_p.h"
#include "qx509_generic_p.h"
#include "qasn1element_p.h"
diff --git a/src/network/ssl/qx509_schannel.cpp b/src/network/ssl/qx509_schannel.cpp
index 252bb470cb..6019fccb23 100644
--- a/src/network/ssl/qx509_schannel.cpp
+++ b/src/network/ssl/qx509_schannel.cpp
@@ -46,6 +46,14 @@ QT_BEGIN_NAMESPACE
namespace QSsl {
+X509CertificateSchannel::X509CertificateSchannel() = default;
+
+X509CertificateSchannel::~X509CertificateSchannel()
+{
+ if (certificateContext)
+ CertFreeCertificateContext(certificateContext);
+}
+
TlsKey *X509CertificateSchannel::publicKey() const
{
auto key = std::make_unique<TlsKeySchannel>(PublicKey);
@@ -55,6 +63,23 @@ TlsKey *X509CertificateSchannel::publicKey() const
return key.release();
}
+Qt::HANDLE X509CertificateSchannel::handle() const
+{
+ return Qt::HANDLE(certificateContext);
+}
+
+QSslCertificate X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
+{
+ QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
+ certificateContext->cbCertEncoded);
+ QSslCertificate certificate(derData, QSsl::Der);
+
+ auto *certBackend = QTlsBackend::backend<X509CertificateSchannel>(certificate);
+ Q_ASSERT(certBackend);
+ certBackend->certificateContext = CertDuplicateCertificateContext(certificateContext);
+ return certificate;
+}
+
} // namespace QSsl.
QT_END_NAMESPACE
diff --git a/src/network/ssl/qx509_schannel_p.h b/src/network/ssl/qx509_schannel_p.h
index 5408ea5a8e..40fb292acf 100644
--- a/src/network/ssl/qx509_schannel_p.h
+++ b/src/network/ssl/qx509_schannel_p.h
@@ -57,6 +57,9 @@
#include <QtCore/qglobal.h>
+#include <QtCore/qt_windows.h>
+#include <wincrypt.h>
+
QT_BEGIN_NAMESPACE
namespace QSsl {
@@ -64,7 +67,17 @@ namespace QSsl {
class X509CertificateSchannel final : public X509CertificateGeneric
{
public:
+ X509CertificateSchannel();
+ ~X509CertificateSchannel();
+
TlsKey *publicKey() const override;
+ Qt::HANDLE handle() const override;
+
+ static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext);
+private:
+ const CERT_CONTEXT *certificateContext = nullptr;
+
+ Q_DISABLE_COPY_MOVE(X509CertificateSchannel);
};
} // namespace QSsl.