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>();
41 PCCERT_CHAIN_CONTEXT chainContext,
55 if (!chainContext->cChain)
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)
87 verifiedChain.
clear();
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"
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
qsizetype length() const noexcept
Same as size().
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
void start() noexcept
Starts this timer.
qsizetype size() const noexcept
bool isEmpty() const noexcept
void append(parameter_type t)
void moveToThread(QThread *thread)
Changes the thread affinity for this object and its children.
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
void start(Priority=InheritPriority)
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.
#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]