summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmad Samir <[email protected]>2025-04-30 17:30:42 +0300
committerAhmad Samir <[email protected]>2025-05-14 04:41:13 +0300
commit2be51c692307f067bb5bdc011e5f3dca1dbe3ff8 (patch)
tree81367961331585b4ad02dd8773b467af929d67e5
parent2875c4358beedd0997b60d21df4b95dbfec4f9a6 (diff)
QSslCertificate: add fromFile() method
QSslCertificate::fromPath() does some extra work: - matching wildcard glob or regular expression patterns - checks if the string it's called on is a file or a dir That extra work isn't needed when you already have the path to a specific certificate file. E.g. qtlsbackend_openssl.cpp:systemCaCertificates() used to call fromPath() on *.pem/*.crt files that it got from iterating over system certifcates dirs. This also de-duplicates the code in fromPath(). [ChangeLog][QtNetwork][QSslCertificate] Added fromFile() method. Change-Id: I92ab358e4711866dd4510da42c47905c7dae58b1 Reviewed-by: Ivan Solovev <[email protected]> Reviewed-by: MÃ¥rten Nordheim <[email protected]>
-rw-r--r--src/network/ssl/qsslcertificate.cpp45
-rw-r--r--src/network/ssl/qsslcertificate.h2
-rw-r--r--src/plugins/tls/openssl/qtlsbackend_openssl.cpp2
-rw-r--r--tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp52
4 files changed, 82 insertions, 19 deletions
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index af3e47f66f9..38fea369055 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -633,6 +633,9 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
if (path.isEmpty())
return {};
+ if (syntax == PatternSyntax::FixedString && QFileInfo(path).isFile())
+ return fromFile(path, format);
+
// $, (,), *, +, ., ?, [, ,], ^, {, | and }.
// make sure to use the same path separators on Windows and Unix like systems.
@@ -665,15 +668,8 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
pathPrefix = {};
} else {
// Check if the path is a file.
- if (QFileInfo(sourcePath).isFile()) {
- QFile file(sourcePath);
- QIODevice::OpenMode openMode = QIODevice::ReadOnly;
- if (format == QSsl::Pem)
- openMode |= QIODevice::Text;
- if (file.open(openMode))
- return QSslCertificate::fromData(file.readAll(), format);
- return QList<QSslCertificate>();
- }
+ if (QFileInfo(sourcePath).isFile())
+ return fromFile(sourcePath, format);
}
// Special case - if the prefix ends up being nothing, use "." instead.
@@ -710,12 +706,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
continue;
#endif
- QFile file(filePath);
- QIODevice::OpenMode openMode = QIODevice::ReadOnly;
- if (format == QSsl::Pem)
- openMode |= QIODevice::Text;
- if (file.open(openMode))
- certs += QSslCertificate::fromData(file.readAll(), format);
+ certs += QSslCertificate::fromFile(filePath, format);
}
return certs;
}
@@ -760,6 +751,30 @@ QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::E
return reader(data, -1);
}
+/*!
+ \since 6.10
+
+ Reads the data from the file \a filePath and parses all certificates
+ that are encoded in the specified \a format and returns a list of
+ QSslCertificate objects.
+
+ If \a filePath isn't a regular file, this method will return an empty
+ list.
+
+ \sa fromData(), fromPath()
+*/
+QList<QSslCertificate> QSslCertificate::fromFile(const QString &filePath,
+ QSsl::EncodingFormat format)
+{
+ QFile file(filePath);
+ QIODevice::OpenMode openMode = QIODevice::ReadOnly;
+ if (format == QSsl::Pem)
+ openMode |= QIODevice::Text;
+ if (file.open(openMode))
+ return QSslCertificate::fromData(file.readAll(), format);
+ return {};
+}
+
#ifndef QT_NO_SSL
/*!
Verifies a certificate chain. The chain to be verified is passed in the
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
index e34fa4d92a3..17f931c1268 100644
--- a/src/network/ssl/qsslcertificate.h
+++ b/src/network/ssl/qsslcertificate.h
@@ -107,6 +107,8 @@ public:
QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
static QList<QSslCertificate> fromData(
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
+ static QList<QSslCertificate> fromFile(
+ const QString &filePath, QSsl::EncodingFormat format = QSsl::Pem);
#ifndef QT_NO_SSL
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName = QString());
diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
index 6a55f275943..bce31734f94 100644
--- a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
+++ b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
@@ -410,7 +410,7 @@ QList<QSslCertificate> systemCaCertificates()
}
}
for (const QString& file : std::as_const(certFiles))
- systemCerts.append(QSslCertificate::fromPath(file, QSsl::Pem));
+ systemCerts.append(QSslCertificate::fromFile(file, QSsl::Pem));
}
#endif // platform
#ifdef QSSLSOCKET_DEBUG
diff --git a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp
index b51053effde..7a9286b329c 100644
--- a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp
+++ b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp
@@ -20,6 +20,8 @@
#include <openssl/obj_mac.h>
#endif
+using namespace Qt::StringLiterals;
+
class tst_QSslCertificate : public QObject
{
Q_OBJECT
@@ -97,6 +99,9 @@ private slots:
// helper for verbose test failure messages
QString toString(const QList<QSslError>&);
+private:
+ void certInfo_helper(const char *methodName);
+
// ### add tests for certificate bundles (multiple certificates concatenated into a single
// structure); both PEM and DER formatted
#endif // QT_CONFIG(ssl)
@@ -494,12 +499,23 @@ void tst_QSslCertificate::subjectIssuerDisplayName()
QFETCH(const QString, certName);
QFETCH(const QString, expectedName);
+ {
const auto chain = QSslCertificate::fromPath(testDataDir + certName);
QCOMPARE(chain.size(), 1);
const auto cert = chain.at(0);
QVERIFY(!cert.isNull());
QCOMPARE(cert.subjectDisplayName(), expectedName);
QCOMPARE(cert.issuerDisplayName(), expectedName);
+ }
+
+ {
+ const auto chain = QSslCertificate::fromFile(testDataDir + certName);
+ QCOMPARE(chain.size(), 1);
+ const auto cert = chain.at(0);
+ QVERIFY(!cert.isNull());
+ QCOMPARE(cert.subjectDisplayName(), expectedName);
+ QCOMPARE(cert.issuerDisplayName(), expectedName);
+ }
}
void tst_QSslCertificate::utf8SubjectNames()
@@ -701,9 +717,14 @@ void tst_QSslCertificate::fromPath_qregularexpression()
pemencoding ? QSsl::Pem : QSsl::Der,
QSslCertificate::PatternSyntax(syntax)).size(),
numCerts);
+
+ if (QSslCertificate::PatternSyntax(syntax) == QSslCertificate::PatternSyntax::FixedString) {
+ const auto list = QSslCertificate::fromFile(path, pemencoding ? QSsl::Pem : QSsl::Der);
+ QCOMPARE(list.size(), numCerts);
+ }
}
-void tst_QSslCertificate::certInfo()
+void tst_QSslCertificate::certInfo_helper(const char *methodName)
{
// MD5 Fingerprint=B6:CF:57:34:DA:A9:73:21:82:F7:CF:4D:3D:85:31:88
// SHA1 Fingerprint=B6:D1:51:82:E0:29:CA:59:96:38:BD:B6:F9:40:05:91:6D:49:09:60
@@ -788,8 +809,14 @@ void tst_QSslCertificate::certInfo()
"dc:c2:eb:b7:bb:50:18:05:ba:ad:af:08:49:fe:98:63"
"55:ba:e7:fb:95:5d:91";
- QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
- QSslCertificate::PatternSyntax::FixedString).first();
+ QSslCertificate cert;
+ if (methodName == "fromPath"_L1) {
+ cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
+ QSslCertificate::PatternSyntax::FixedString).first();
+ } else if (methodName == "fromFile"_L1) {
+ cert = QSslCertificate::fromFile(testDataDir + "certificates/cert.pem", QSsl::Pem).first();
+ }
+
QVERIFY(!cert.isNull());
QCOMPARE(cert.issuerInfo(QSslCertificate::Organization)[0], QString("CryptSoft Pty Ltd"));
@@ -845,8 +872,15 @@ void tst_QSslCertificate::certInfo()
QCOMPARE(cert, QSslCertificate(QByteArray::fromHex(der), QSsl::Der));
}
+void tst_QSslCertificate::certInfo()
+{
+ certInfo_helper("fromPath");
+ certInfo_helper("fromFile");
+}
+
void tst_QSslCertificate::certInfoQByteArray()
{
+ {
QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
QSslCertificate::PatternSyntax::FixedString).first();
QVERIFY(!cert.isNull());
@@ -855,6 +889,18 @@ void tst_QSslCertificate::certInfoQByteArray()
// we fixed a bug we had with lazy initialization of the values.
QCOMPARE(cert.issuerInfo("CN")[0], QString("Test CA (1024 bit)"));
QCOMPARE(cert.subjectInfo("CN")[0], QString("name/with/slashes"));
+ }
+
+ {
+ QSslCertificate cert =
+ QSslCertificate::fromFile(testDataDir + "certificates/cert.pem", QSsl::Pem).first();
+ QVERIFY(!cert.isNull());
+
+ // in this test, check the bytearray variants before the enum variants to see if
+ // we fixed a bug we had with lazy initialization of the values.
+ QCOMPARE(cert.issuerInfo("CN")[0], QString("Test CA (1024 bit)"));
+ QCOMPARE(cert.subjectInfo("CN")[0], QString("name/with/slashes"));
+ }
}
void tst_QSslCertificate::task256066toPem()