8#include <QtCore/QThread>
11#include <QtCore/qscopeguard.h>
13#ifdef QSSLSOCKET_DEBUG
14#include <QtNetwork/private/qtlsbackend_p.h>
15#include <QtCore/QElapsedTimer>
25 qRegisterMetaType<QSslCertificate>();
40const QList<QSslCertificate> buildVerifiedChain(
const QList<QSslCertificate> &caCertificates,
41 PCCERT_CHAIN_CONTEXT chainContext,
55 if (!chainContext->cChain)
58 QList<QSslCertificate> verifiedChain;
60 CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
64 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
67 for (DWORD
i = 0;
i < chain->cElement; ++
i) {
68 CERT_CHAIN_ELEMENT *element = chain->rgpElement[
i];
70 int(element->pCertContext->cbCertEncoded)),
QSsl::Der);
72 if (
cert.isBlacklisted())
75 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
78 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
81 verifiedChain.append(
cert);
87 verifiedChain.clear();
95 const QList<QSslCertificate> &caCertificates,
const QString &hostName)
96 :
cert(certificate),
mode(sslMode), explicitlyTrustedCAs(caCertificates), peerVerifyName(hostName)
108 PCCERT_CONTEXT wincert = CertCreateCertificateContext(X509_ASN_ENCODING, (
const BYTE *)der.constData(), der.length());
110#ifdef QSSLSOCKET_DEBUG
111 qCDebug(lcTlsBackend,
"QWindowsCaRootFetcher failed to convert certificate to windows form");
118 CERT_CHAIN_PARA parameters;
119 memset(¶meters, 0,
sizeof(parameters));
120 parameters.cbSize =
sizeof(parameters);
122 parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
123 parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
125 parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
127#ifdef QSSLSOCKET_DEBUG
131 PCCERT_CHAIN_CONTEXT chain;
132 auto additionalStore = createAdditionalStore();
133 BOOL
result = CertGetCertificateChain(
137 additionalStore.get(),
142#ifdef QSSLSOCKET_DEBUG
143 qCDebug(lcSsl) <<
"QWindowsCaRootFetcher" << stopwatch.elapsed() <<
"ms to get chain";
148#ifdef QSSLSOCKET_DEBUG
149 qCDebug(lcSsl) <<
"QWindowsCaRootFetcher - examining windows chains";
150 if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
151 qCDebug(lcSsl) <<
" - TRUSTED";
153 qCDebug(lcSsl) <<
" - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
154 if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
155 qCDebug(lcSsl) <<
" - SELF SIGNED";
156 qCDebug(lcSsl) <<
"QWindowsCaRootFetcher - dumping simple chains";
157 for (
unsigned int i = 0;
i < chain->cChain;
i++) {
158 if (chain->rgpChain[
i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
159 qCDebug(lcSsl) <<
" - TRUSTED SIMPLE CHAIN" <<
i;
161 qCDebug(lcSsl) <<
" - UNTRUSTED SIMPLE CHAIN" <<
i <<
"reason:" << chain->rgpChain[
i]->TrustStatus.dwErrorStatus;
162 for (
unsigned int j = 0;
j < chain->rgpChain[
i]->cElement;
j++) {
164 , chain->rgpChain[
i]->rgpElement[
j]->pCertContext->cbCertEncoded),
QSsl::Der);
165 qCDebug(lcSsl) <<
" - " << foundCert;
168 qCDebug(lcSsl) <<
" - and" << chain->cLowerQualityChainContext <<
"low quality chains";
173 if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
174 && chain->cChain > 0) {
175 const PCERT_SIMPLE_CHAIN finalChain = chain->rgpChain[chain->cChain - 1];
178 if (finalChain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
179 && finalChain->cElement > 0) {
180 trustedRoot =
QSslCertificate(
QByteArray((
const char *)finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->pbCertEncoded
181 , finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->cbCertEncoded),
QSsl::Der);
183 }
else if (explicitlyTrustedCAs.
size()) {
185#if QT_CONFIG(openssl)
186 const auto verifiedChain = buildVerifiedChain(explicitlyTrustedCAs, chain, peerVerifyName);
187 if (verifiedChain.size())
188 trustedRoot = verifiedChain.last();
194 CertFreeCertificateChain(chain);
196 CertFreeCertificateContext(wincert);
205 if (explicitlyTrustedCAs.
isEmpty())
208 if (HCERTSTORE rawPtr = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0,
nullptr)) {
209 customStore.reset(rawPtr);
211 unsigned rootsAdded = 0;
213 const auto der = caCert.toDer();
214 PCCERT_CONTEXT winCert = CertCreateCertificateContext(X509_ASN_ENCODING,
215 reinterpret_cast<const BYTE *
>(der.data()),
216 DWORD(der.length()));
218#if defined(QSSLSOCKET_DEBUG)
219 qCWarning(lcSsl) <<
"CA fetcher, failed to convert QSslCertificate"
220 <<
"to the native representation";
225 CertFreeCertificateContext(winCert);
227 if (CertAddCertificateContextToStore(customStore.get(), winCert, CERT_STORE_ADD_ALWAYS,
nullptr))
229#if defined(QSSLSOCKET_DEBUG)
231 Q_ASSERT(
"CertAddCertificateContextToStore() failed");
236#if defined(QSSLSOCKET_DEBUG)
239 qCWarning(lcSsl) <<
"CA fetcher, failed to create a custom"
240 <<
"store for explicitly trusted CA certificate";
249#include "moc_qwindowscarootfetcher_p.cpp"
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
qsizetype size() const noexcept
bool isEmpty() const noexcept
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
void deleteLater()
\threadsafe
The QSslCertificate class provides a convenient API for an X509 certificate.
QByteArray toDer() const
Returns this certificate converted to a DER (binary) encoded representation.
SslMode
Describes the connection modes available for QSslSocket.
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
static QList< QSslError > verify(const QList< QSslCertificate > &chain, const QString &hostName)
QWindowsCaRootFetcherThread()
~QWindowsCaRootFetcherThread()
void finished(QSslCertificate brokenChain, QSslCertificate caroot)
QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode, const QList< QSslCertificate > &caCertificates={}, const QString &hostName={})
Combined button and popup list for selecting options.
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
#define QStringLiteral(str)
std::unique_ptr< void, QHCertStoreDeleter > QHCertStorePointer
QList< QSslCertificate > cert
[0]