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 <ivan.solovev@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
2875c4358b
commit
2be51c6923
@ -633,6 +633,9 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
|
|||||||
if (path.isEmpty())
|
if (path.isEmpty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
if (syntax == PatternSyntax::FixedString && QFileInfo(path).isFile())
|
||||||
|
return fromFile(path, format);
|
||||||
|
|
||||||
// $, (,), *, +, ., ?, [, ,], ^, {, | and }.
|
// $, (,), *, +, ., ?, [, ,], ^, {, | and }.
|
||||||
|
|
||||||
// make sure to use the same path separators on Windows and Unix like systems.
|
// 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 = {};
|
pathPrefix = {};
|
||||||
} else {
|
} else {
|
||||||
// Check if the path is a file.
|
// Check if the path is a file.
|
||||||
if (QFileInfo(sourcePath).isFile()) {
|
if (QFileInfo(sourcePath).isFile())
|
||||||
QFile file(sourcePath);
|
return fromFile(sourcePath, format);
|
||||||
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>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case - if the prefix ends up being nothing, use "." instead.
|
// Special case - if the prefix ends up being nothing, use "." instead.
|
||||||
@ -710,12 +706,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
|
|||||||
continue;
|
continue;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QFile file(filePath);
|
certs += QSslCertificate::fromFile(filePath, format);
|
||||||
QIODevice::OpenMode openMode = QIODevice::ReadOnly;
|
|
||||||
if (format == QSsl::Pem)
|
|
||||||
openMode |= QIODevice::Text;
|
|
||||||
if (file.open(openMode))
|
|
||||||
certs += QSslCertificate::fromData(file.readAll(), format);
|
|
||||||
}
|
}
|
||||||
return certs;
|
return certs;
|
||||||
}
|
}
|
||||||
@ -760,6 +751,30 @@ QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::E
|
|||||||
return reader(data, -1);
|
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
|
#ifndef QT_NO_SSL
|
||||||
/*!
|
/*!
|
||||||
Verifies a certificate chain. The chain to be verified is passed in the
|
Verifies a certificate chain. The chain to be verified is passed in the
|
||||||
|
@ -107,6 +107,8 @@ public:
|
|||||||
QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
|
QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
|
||||||
static QList<QSslCertificate> fromData(
|
static QList<QSslCertificate> fromData(
|
||||||
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
|
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
|
||||||
|
static QList<QSslCertificate> fromFile(
|
||||||
|
const QString &filePath, QSsl::EncodingFormat format = QSsl::Pem);
|
||||||
|
|
||||||
#ifndef QT_NO_SSL
|
#ifndef QT_NO_SSL
|
||||||
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName = QString());
|
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName = QString());
|
||||||
|
@ -410,7 +410,7 @@ QList<QSslCertificate> systemCaCertificates()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const QString& file : std::as_const(certFiles))
|
for (const QString& file : std::as_const(certFiles))
|
||||||
systemCerts.append(QSslCertificate::fromPath(file, QSsl::Pem));
|
systemCerts.append(QSslCertificate::fromFile(file, QSsl::Pem));
|
||||||
}
|
}
|
||||||
#endif // platform
|
#endif // platform
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include <openssl/obj_mac.h>
|
#include <openssl/obj_mac.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
class tst_QSslCertificate : public QObject
|
class tst_QSslCertificate : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -97,6 +99,9 @@ private slots:
|
|||||||
// helper for verbose test failure messages
|
// helper for verbose test failure messages
|
||||||
QString toString(const QList<QSslError>&);
|
QString toString(const QList<QSslError>&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void certInfo_helper(const char *methodName);
|
||||||
|
|
||||||
// ### add tests for certificate bundles (multiple certificates concatenated into a single
|
// ### add tests for certificate bundles (multiple certificates concatenated into a single
|
||||||
// structure); both PEM and DER formatted
|
// structure); both PEM and DER formatted
|
||||||
#endif // QT_CONFIG(ssl)
|
#endif // QT_CONFIG(ssl)
|
||||||
@ -494,12 +499,23 @@ void tst_QSslCertificate::subjectIssuerDisplayName()
|
|||||||
QFETCH(const QString, certName);
|
QFETCH(const QString, certName);
|
||||||
QFETCH(const QString, expectedName);
|
QFETCH(const QString, expectedName);
|
||||||
|
|
||||||
|
{
|
||||||
const auto chain = QSslCertificate::fromPath(testDataDir + certName);
|
const auto chain = QSslCertificate::fromPath(testDataDir + certName);
|
||||||
QCOMPARE(chain.size(), 1);
|
QCOMPARE(chain.size(), 1);
|
||||||
const auto cert = chain.at(0);
|
const auto cert = chain.at(0);
|
||||||
QVERIFY(!cert.isNull());
|
QVERIFY(!cert.isNull());
|
||||||
QCOMPARE(cert.subjectDisplayName(), expectedName);
|
QCOMPARE(cert.subjectDisplayName(), expectedName);
|
||||||
QCOMPARE(cert.issuerDisplayName(), 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()
|
void tst_QSslCertificate::utf8SubjectNames()
|
||||||
@ -701,9 +717,14 @@ void tst_QSslCertificate::fromPath_qregularexpression()
|
|||||||
pemencoding ? QSsl::Pem : QSsl::Der,
|
pemencoding ? QSsl::Pem : QSsl::Der,
|
||||||
QSslCertificate::PatternSyntax(syntax)).size(),
|
QSslCertificate::PatternSyntax(syntax)).size(),
|
||||||
numCerts);
|
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
|
// 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
|
// 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"
|
"dc:c2:eb:b7:bb:50:18:05:ba:ad:af:08:49:fe:98:63"
|
||||||
"55:ba:e7:fb:95:5d:91";
|
"55:ba:e7:fb:95:5d:91";
|
||||||
|
|
||||||
QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
|
QSslCertificate cert;
|
||||||
|
if (methodName == "fromPath"_L1) {
|
||||||
|
cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
|
||||||
QSslCertificate::PatternSyntax::FixedString).first();
|
QSslCertificate::PatternSyntax::FixedString).first();
|
||||||
|
} else if (methodName == "fromFile"_L1) {
|
||||||
|
cert = QSslCertificate::fromFile(testDataDir + "certificates/cert.pem", QSsl::Pem).first();
|
||||||
|
}
|
||||||
|
|
||||||
QVERIFY(!cert.isNull());
|
QVERIFY(!cert.isNull());
|
||||||
|
|
||||||
QCOMPARE(cert.issuerInfo(QSslCertificate::Organization)[0], QString("CryptSoft Pty Ltd"));
|
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));
|
QCOMPARE(cert, QSslCertificate(QByteArray::fromHex(der), QSsl::Der));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSslCertificate::certInfo()
|
||||||
|
{
|
||||||
|
certInfo_helper("fromPath");
|
||||||
|
certInfo_helper("fromFile");
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QSslCertificate::certInfoQByteArray()
|
void tst_QSslCertificate::certInfoQByteArray()
|
||||||
{
|
{
|
||||||
|
{
|
||||||
QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
|
QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
|
||||||
QSslCertificate::PatternSyntax::FixedString).first();
|
QSslCertificate::PatternSyntax::FixedString).first();
|
||||||
QVERIFY(!cert.isNull());
|
QVERIFY(!cert.isNull());
|
||||||
@ -855,6 +889,18 @@ void tst_QSslCertificate::certInfoQByteArray()
|
|||||||
// we fixed a bug we had with lazy initialization of the values.
|
// we fixed a bug we had with lazy initialization of the values.
|
||||||
QCOMPARE(cert.issuerInfo("CN")[0], QString("Test CA (1024 bit)"));
|
QCOMPARE(cert.issuerInfo("CN")[0], QString("Test CA (1024 bit)"));
|
||||||
QCOMPARE(cert.subjectInfo("CN")[0], QString("name/with/slashes"));
|
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()
|
void tst_QSslCertificate::task256066toPem()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user