diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2022-12-02 11:41:11 +0100 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2022-12-04 15:06:58 +0000 |
commit | 8a18466e38779b63c19e281e92031cebaedbcba5 (patch) | |
tree | 464dfc7dfd33b1f83af68c2b0e979b714d383c99 /src/plugins/tls/shared | |
parent | bdc16f086f1664b56d8add0691c9a80d7997efd9 (diff) |
qsslsocket_shared_mac: add more logging into certificate parsing
On macOS we observe strange CA certificates that are coming from
Security framework and which it cannot later parse from the DER
format we feed it in. Add some more debugging in order to understand,
which certificate gives such result.
Pick-to: 6.4 6.2
Task-number: QTBUG-109135
Change-Id: I75cf4591e33c85db6fe80d37d84ede1456c56231
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/plugins/tls/shared')
-rw-r--r-- | src/plugins/tls/shared/qsslsocket_mac_shared.cpp | 64 |
1 files changed, 62 insertions, 2 deletions
diff --git a/src/plugins/tls/shared/qsslsocket_mac_shared.cpp b/src/plugins/tls/shared/qsslsocket_mac_shared.cpp index f40d2fb770..1257240ee2 100644 --- a/src/plugins/tls/shared/qsslsocket_mac_shared.cpp +++ b/src/plugins/tls/shared/qsslsocket_mac_shared.cpp @@ -6,6 +6,7 @@ #include <QtNetwork/qsslcertificate.h> +#include <QtCore/qloggingcategory.h> #include <QtCore/qglobal.h> #include <QtCore/qdebug.h> @@ -21,6 +22,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcX509, "qt.mac.shared.x509"); + #ifdef Q_OS_MACOS namespace { @@ -74,6 +77,52 @@ bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain) return false; } +bool canDERBeParsed(CFDataRef derData, const QSslCertificate &qtCert) +{ + // We are observing certificates, that while accepted when we copy them + // from the keychain(s), later give us 'Failed to create SslCertificate + // from QSslCertificate'. It's interesting to know at what step the failure + // occurred. Let's check it and skip it below if it's not valid. + + auto checkDer = [](CFDataRef derData, const char *source) + { + Q_ASSERT(source); + Q_ASSERT(derData); + + const auto cfLength = CFDataGetLength(derData); + if (cfLength <= 0) { + qCWarning(lcX509) << source << "returned faulty DER data with invalid length."; + return false; + } + + QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, derData); + if (!secRef) { + qCWarning(lcX509) << source << "returned faulty DER data which cannot be parsed back."; + return false; + } + return true; + }; + + if (!checkDer(derData, "SecCertificateCopyData")) { + qCDebug(lcX509) << "Faulty QSslCertificate is:" << qtCert;// Just in case we managed to parse something. + return false; + } + + // Generic parser failed? + if (qtCert.isNull()) { + qCWarning(lcX509, "QSslCertificate failed to parse DER"); + return false; + } + + const QCFType<CFDataRef> qtDerData = qtCert.toDer().toCFData(); + if (!checkDer(qtDerData, "QSslCertificate")) { + qCWarning(lcX509) << "Faulty QSslCertificate is:" << qtCert; + return false; + } + + return true; +} + } // unnamed namespace #endif // Q_OS_MACOS @@ -94,8 +143,19 @@ QList<QSslCertificate> systemCaCertificates() SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert); if (isCaCertificateTrusted(cfCert, dom)) { - if (derData) - systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der); + if (derData) { + const auto newCert = QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der); + if (!canDERBeParsed(derData, newCert)) { + // Last attempt to get some information about the certificate: + CFShow(cfCert); + continue; + } + systemCerts << newCert; + } else { + // "Returns NULL if the data passed in the certificate parameter + // is not a valid certificate object." + qCWarning(lcX509, "SecCertificateCopyData returned invalid DER data (nullptr)."); + } } } } |