| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 | #include <qsslcertificate.h> | 
| 32 | #include <qsslkey.h> | 
| 33 | #include <qsslsocket.h> | 
| 34 | #include <qsslcertificateextension.h> | 
| 35 |  | 
| 36 | #ifndef QT_NO_OPENSSL | 
| 37 | #include <openssl/obj_mac.h> | 
| 38 | #endif | 
| 39 |  | 
| 40 | class tst_QSslCertificate : public QObject | 
| 41 | { | 
| 42 |     Q_OBJECT | 
| 43 |  | 
| 44 |     struct CertInfo { | 
| 45 |         QFileInfo fileInfo; | 
| 46 |         QFileInfo fileInfo_digest_md5; | 
| 47 |         QFileInfo fileInfo_digest_sha1; | 
| 48 |         QSsl::EncodingFormat format; | 
| 49 |         CertInfo(const QFileInfo &fileInfo, QSsl::EncodingFormat format) | 
| 50 |             : fileInfo(fileInfo), format(format) {} | 
| 51 |     }; | 
| 52 |  | 
| 53 |     QList<CertInfo> certInfoList; | 
| 54 |     QMap<QString, QString> subjAltNameMap; | 
| 55 |     QMap<QString, QString> pubkeyMap; | 
| 56 |     QMap<QString, QString> md5Map; | 
| 57 |     QMap<QString, QString> sha1Map; | 
| 58 |  | 
| 59 |     void createTestRows(); | 
| 60 | #ifndef QT_NO_SSL | 
| 61 |     void compareCertificates(const QSslCertificate & cert1, const QSslCertificate & cert2); | 
| 62 | #endif | 
| 63 |  | 
| 64 | public slots: | 
| 65 |     void initTestCase(); | 
| 66 |  | 
| 67 | #ifndef QT_NO_SSL | 
| 68 | private slots: | 
| 69 |     void hash(); | 
| 70 |     void emptyConstructor(); | 
| 71 |     void constructor_data(); | 
| 72 |     void constructor(); | 
| 73 |     void constructor_device(); | 
| 74 |     void constructingGarbage(); | 
| 75 |     void copyAndAssign_data(); | 
| 76 |     void copyAndAssign(); | 
| 77 |     void digest_data(); | 
| 78 |     void digest(); | 
| 79 |     void subjectAlternativeNames_data(); | 
| 80 |     void utf8SubjectNames(); | 
| 81 |     void subjectAlternativeNames(); | 
| 82 |     void subjectInfoToString(); | 
| 83 |     void subjectIssuerDisplayName_data(); | 
| 84 |     void subjectIssuerDisplayName(); | 
| 85 |     void publicKey_data(); | 
| 86 |     void publicKey(); | 
| 87 |     void toPemOrDer_data(); | 
| 88 |     void toPemOrDer(); | 
| 89 |     void fromDevice(); | 
| 90 |     void fromPath_data(); | 
| 91 |     void fromPath(); | 
| 92 |     void fromPath_qregularexpression_data(); | 
| 93 |     void fromPath_qregularexpression(); | 
| 94 |     void certInfo(); | 
| 95 |     void certInfoQByteArray(); | 
| 96 |     void task256066toPem(); | 
| 97 |     void nulInCN(); | 
| 98 |     void nulInSan(); | 
| 99 |     void largeSerialNumber(); | 
| 100 |     void largeExpirationDate(); | 
| 101 |     void blacklistedCertificates(); | 
| 102 |     void selfsignedCertificates(); | 
| 103 |     void toText(); | 
| 104 |     void multipleCommonNames(); | 
| 105 |     void subjectAndIssuerAttributes(); | 
| 106 |     void verify(); | 
| 107 |     void extensions(); | 
| 108 |     void extensionsCritical(); | 
| 109 |     void threadSafeConstMethods(); | 
| 110 |     void version_data(); | 
| 111 |     void version(); | 
| 112 |     void pkcs12(); | 
| 113 |  | 
| 114 |     // helper for verbose test failure messages | 
| 115 |     QString toString(const QList<QSslError>&); | 
| 116 |  | 
| 117 | // ### add tests for certificate bundles (multiple certificates concatenated into a single | 
| 118 | //     structure); both PEM and DER formatted | 
| 119 | #endif | 
| 120 | private: | 
| 121 |     QString testDataDir; | 
| 122 | }; | 
| 123 |  | 
| 124 | void tst_QSslCertificate::initTestCase() | 
| 125 | { | 
| 126 |     testDataDir = QFileInfo(QFINDTESTDATA("certificates" )).absolutePath(); | 
| 127 |     if (testDataDir.isEmpty()) | 
| 128 |         testDataDir = QCoreApplication::applicationDirPath(); | 
| 129 |     if (!testDataDir.endsWith(s: QLatin1String("/" ))) | 
| 130 |         testDataDir += QLatin1String("/" ); | 
| 131 |  | 
| 132 |     QDir dir(testDataDir + "certificates" ); | 
| 133 |     QFileInfoList fileInfoList = dir.entryInfoList(filters: QDir::Files | QDir::Readable); | 
| 134 |     QRegExp rxCert(QLatin1String("^.+\\.(pem|der)$" )); | 
| 135 |     QRegExp rxSan(QLatin1String("^(.+\\.(?:pem|der))\\.san$" )); | 
| 136 |     QRegExp rxPubKey(QLatin1String("^(.+\\.(?:pem|der))\\.pubkey$" )); | 
| 137 |     QRegExp rxDigest(QLatin1String("^(.+\\.(?:pem|der))\\.digest-(md5|sha1)$" )); | 
| 138 |     foreach (QFileInfo fileInfo, fileInfoList) { | 
| 139 |         if (rxCert.indexIn(str: fileInfo.fileName()) >= 0) | 
| 140 |             certInfoList << | 
| 141 |                 CertInfo(fileInfo, | 
| 142 |                          rxCert.cap(nth: 1) == QLatin1String("pem" ) ? QSsl::Pem : QSsl::Der); | 
| 143 |         if (rxSan.indexIn(str: fileInfo.fileName()) >= 0) | 
| 144 |             subjAltNameMap.insert(key: rxSan.cap(nth: 1), value: fileInfo.absoluteFilePath()); | 
| 145 |         if (rxPubKey.indexIn(str: fileInfo.fileName()) >= 0) | 
| 146 |             pubkeyMap.insert(key: rxPubKey.cap(nth: 1), value: fileInfo.absoluteFilePath()); | 
| 147 |         if (rxDigest.indexIn(str: fileInfo.fileName()) >= 0) { | 
| 148 |             if (rxDigest.cap(nth: 2) == QLatin1String("md5" )) | 
| 149 |                 md5Map.insert(key: rxDigest.cap(nth: 1), value: fileInfo.absoluteFilePath()); | 
| 150 |             else | 
| 151 |                 sha1Map.insert(key: rxDigest.cap(nth: 1), value: fileInfo.absoluteFilePath()); | 
| 152 |         } | 
| 153 |     } | 
| 154 | } | 
| 155 |  | 
| 156 | #ifndef QT_NO_SSL | 
| 157 |  | 
| 158 | void tst_QSslCertificate::hash() | 
| 159 | { | 
| 160 |     // mostly a compile-only test, to check that qHash(QSslCertificate) is found. | 
| 161 |     QSet<QSslCertificate> certs; | 
| 162 |     certs << QSslCertificate(); | 
| 163 |     QCOMPARE(certs.size(), 1); | 
| 164 | } | 
| 165 |  | 
| 166 | static QByteArray readFile(const QString &absFilePath) | 
| 167 | { | 
| 168 |     QFile file(absFilePath); | 
| 169 |     if (!file.open(flags: QIODevice::ReadOnly)) { | 
| 170 |         QWARN("failed to open file" ); | 
| 171 |         return QByteArray(); | 
| 172 |     } | 
| 173 |     return file.readAll(); | 
| 174 | } | 
| 175 |  | 
| 176 | void tst_QSslCertificate::emptyConstructor() | 
| 177 | { | 
| 178 |     if (!QSslSocket::supportsSsl()) | 
| 179 |         return; | 
| 180 |  | 
| 181 |     QSslCertificate certificate; | 
| 182 |     QVERIFY(certificate.isNull()); | 
| 183 |     //make sure none of the functions crash  (task 203035) | 
| 184 |     QVERIFY(!certificate.isBlacklisted()); | 
| 185 |     QCOMPARE(certificate.version() , QByteArray()); | 
| 186 |     QCOMPARE(certificate.serialNumber(), QByteArray()); | 
| 187 |     QCOMPARE(certificate.digest(), QCryptographicHash::hash(QByteArray(), QCryptographicHash::Md5)); | 
| 188 |     QCOMPARE(certificate.issuerInfo(QSslCertificate::Organization), QStringList()); | 
| 189 |     QCOMPARE(certificate.subjectInfo(QSslCertificate::Organization), QStringList()); | 
| 190 |     QCOMPARE(certificate.subjectAlternativeNames(),(QMultiMap<QSsl::AlternativeNameEntryType, QString>())); | 
| 191 |     QCOMPARE(certificate.effectiveDate(), QDateTime()); | 
| 192 |     QCOMPARE(certificate.expiryDate(), QDateTime()); | 
| 193 | } | 
| 194 |  | 
| 195 | Q_DECLARE_METATYPE(QSsl::EncodingFormat); | 
| 196 |  | 
| 197 | void tst_QSslCertificate::createTestRows() | 
| 198 | { | 
| 199 |     QTest::addColumn<QString>(name: "absFilePath" ); | 
| 200 |     QTest::addColumn<QSsl::EncodingFormat>(name: "format" ); | 
| 201 |     foreach (CertInfo certInfo, certInfoList) { | 
| 202 |         QTest::newRow(dataTag: certInfo.fileInfo.fileName().toLatin1()) | 
| 203 |             << certInfo.fileInfo.absoluteFilePath() << certInfo.format; | 
| 204 |     } | 
| 205 | } | 
| 206 |  | 
| 207 | void tst_QSslCertificate::constructor_data() | 
| 208 | { | 
| 209 |     createTestRows(); | 
| 210 | } | 
| 211 |  | 
| 212 | void tst_QSslCertificate::constructor() | 
| 213 | { | 
| 214 |     if (!QSslSocket::supportsSsl()) | 
| 215 |         return; | 
| 216 |  | 
| 217 |     QFETCH(QString, absFilePath); | 
| 218 |     QFETCH(QSsl::EncodingFormat, format); | 
| 219 |  | 
| 220 |     QByteArray encoded = readFile(absFilePath); | 
| 221 |     QSslCertificate certificate(encoded, format); | 
| 222 |     QVERIFY(!certificate.isNull()); | 
| 223 | } | 
| 224 |  | 
| 225 | void tst_QSslCertificate::constructor_device() | 
| 226 | { | 
| 227 |     if (!QSslSocket::supportsSsl()) | 
| 228 |         return; | 
| 229 |  | 
| 230 |     QFile f(testDataDir + "verify-certs/test-ocsp-good-cert.pem" ); | 
| 231 |     bool ok = f.open(flags: QIODevice::ReadOnly); | 
| 232 |     QVERIFY(ok); | 
| 233 |  | 
| 234 |     QSslCertificate cert(&f); | 
| 235 |     QVERIFY(!cert.isNull()); | 
| 236 |     f.close(); | 
| 237 |  | 
| 238 |     // Check opening a DER as a PEM fails | 
| 239 |     QFile f2(testDataDir + "certificates/cert.der" ); | 
| 240 |     ok = f2.open(flags: QIODevice::ReadOnly); | 
| 241 |     QVERIFY(ok); | 
| 242 |  | 
| 243 |     QSslCertificate cert2(&f2); | 
| 244 |     QVERIFY(cert2.isNull()); | 
| 245 |     f2.close(); | 
| 246 |  | 
| 247 |     // Check opening a DER as a DER works | 
| 248 |     QFile f3(testDataDir + "certificates/cert.der" ); | 
| 249 |     ok = f3.open(flags: QIODevice::ReadOnly); | 
| 250 |     QVERIFY(ok); | 
| 251 |  | 
| 252 |     QSslCertificate cert3(&f3, QSsl::Der); | 
| 253 |     QVERIFY(!cert3.isNull()); | 
| 254 |     f3.close(); | 
| 255 |  | 
| 256 |     // Check opening a PEM as a DER fails | 
| 257 |     QFile f4(testDataDir + "verify-certs/test-ocsp-good-cert.pem" ); | 
| 258 |     ok = f4.open(flags: QIODevice::ReadOnly); | 
| 259 |     QVERIFY(ok); | 
| 260 |  | 
| 261 |     QSslCertificate cert4(&f4, QSsl::Der); | 
| 262 |     QVERIFY(cert4.isNull()); | 
| 263 |     f4.close(); | 
| 264 | } | 
| 265 |  | 
| 266 | void tst_QSslCertificate::constructingGarbage() | 
| 267 | { | 
| 268 |     if (!QSslSocket::supportsSsl()) | 
| 269 |         return; | 
| 270 |  | 
| 271 |     QByteArray garbage("garbage" ); | 
| 272 |     QSslCertificate certificate(garbage); | 
| 273 |     QVERIFY(certificate.isNull()); | 
| 274 | } | 
| 275 |  | 
| 276 | void tst_QSslCertificate::copyAndAssign_data() | 
| 277 | { | 
| 278 |     createTestRows(); | 
| 279 | } | 
| 280 |  | 
| 281 | void tst_QSslCertificate::compareCertificates( | 
| 282 |     const QSslCertificate & cert1, const QSslCertificate & cert2) | 
| 283 | { | 
| 284 |     QCOMPARE(cert1.isNull(), cert2.isNull()); | 
| 285 |     // Note: in theory, the next line could fail even if the certificates are identical! | 
| 286 |     QCOMPARE(cert1.isBlacklisted(), cert2.isBlacklisted()); | 
| 287 |     QCOMPARE(cert1.version(), cert2.version()); | 
| 288 |     QCOMPARE(cert1.serialNumber(), cert2.serialNumber()); | 
| 289 |     QCOMPARE(cert1.digest(), cert2.digest()); | 
| 290 |     QCOMPARE(cert1.toPem(), cert2.toPem()); | 
| 291 |     QCOMPARE(cert1.toDer(), cert2.toDer()); | 
| 292 |     for (int info = QSslCertificate::Organization; | 
| 293 |          info <= QSslCertificate::StateOrProvinceName; info++) { | 
| 294 |         const QSslCertificate::SubjectInfo subjectInfo = (QSslCertificate::SubjectInfo)info; | 
| 295 |         QCOMPARE(cert1.issuerInfo(subjectInfo), cert2.issuerInfo(subjectInfo)); | 
| 296 |         QCOMPARE(cert1.subjectInfo(subjectInfo), cert2.subjectInfo(subjectInfo)); | 
| 297 |     } | 
| 298 |     QCOMPARE(cert1.subjectAlternativeNames(), cert2.subjectAlternativeNames()); | 
| 299 |     QCOMPARE(cert1.effectiveDate(), cert2.effectiveDate()); | 
| 300 |     QCOMPARE(cert1.expiryDate(), cert2.expiryDate()); | 
| 301 |     QCOMPARE(cert1.version(), cert2.version()); | 
| 302 |     QCOMPARE(cert1.serialNumber(), cert2.serialNumber()); | 
| 303 |     // ### add more functions here ... | 
| 304 | } | 
| 305 |  | 
| 306 | void tst_QSslCertificate::copyAndAssign() | 
| 307 | { | 
| 308 |     if (!QSslSocket::supportsSsl()) | 
| 309 |         return; | 
| 310 |  | 
| 311 |     QFETCH(QString, absFilePath); | 
| 312 |     QFETCH(QSsl::EncodingFormat, format); | 
| 313 |  | 
| 314 |     QByteArray encoded = readFile(absFilePath); | 
| 315 |     QSslCertificate certificate(encoded, format); | 
| 316 |  | 
| 317 |     QVERIFY(!certificate.isNull()); | 
| 318 |  | 
| 319 |     QSslCertificate copied(certificate); | 
| 320 |     compareCertificates(cert1: certificate, cert2: copied); | 
| 321 |  | 
| 322 |     QSslCertificate assigned = certificate; | 
| 323 |     compareCertificates(cert1: certificate, cert2: assigned); | 
| 324 | } | 
| 325 |  | 
| 326 | void tst_QSslCertificate::digest_data() | 
| 327 | { | 
| 328 |     QTest::addColumn<QString>(name: "absFilePath" ); | 
| 329 |     QTest::addColumn<QSsl::EncodingFormat>(name: "format" ); | 
| 330 |     QTest::addColumn<QString>(name: "absFilePath_digest_md5" ); | 
| 331 |     QTest::addColumn<QString>(name: "absFilePath_digest_sha1" ); | 
| 332 |     foreach (CertInfo certInfo, certInfoList) { | 
| 333 |         QString certName = certInfo.fileInfo.fileName(); | 
| 334 |         QTest::newRow(dataTag: certName.toLatin1()) | 
| 335 |             << certInfo.fileInfo.absoluteFilePath() | 
| 336 |             << certInfo.format | 
| 337 |             << md5Map.value(akey: certName) | 
| 338 |             << sha1Map.value(akey: certName); | 
| 339 |     } | 
| 340 | } | 
| 341 |  | 
| 342 | // Converts a digest of the form '{MD5|SHA1} Fingerprint=AB:B8:32...' to binary format. | 
| 343 | static QByteArray convertDigest(const QByteArray &input) | 
| 344 | { | 
| 345 |     QByteArray result; | 
| 346 |     QRegExp rx(QLatin1String("(?:=|:)([0-9A-Fa-f]{2})" )); | 
| 347 |     int pos = 0; | 
| 348 |     while ((pos = rx.indexIn(str: input, offset: pos)) != -1) { | 
| 349 |         result.append(a: rx.cap(nth: 1).toLatin1()); | 
| 350 |         pos += rx.matchedLength(); | 
| 351 |     } | 
| 352 |     return QByteArray::fromHex(hexEncoded: result); | 
| 353 | } | 
| 354 |  | 
| 355 | void tst_QSslCertificate::digest() | 
| 356 | { | 
| 357 |     if (!QSslSocket::supportsSsl()) | 
| 358 |         return; | 
| 359 |  | 
| 360 |     QFETCH(QString, absFilePath); | 
| 361 |     QFETCH(QSsl::EncodingFormat, format); | 
| 362 |     QFETCH(QString, absFilePath_digest_md5); | 
| 363 |     QFETCH(QString, absFilePath_digest_sha1); | 
| 364 |  | 
| 365 |     QByteArray encoded = readFile(absFilePath); | 
| 366 |     QSslCertificate certificate(encoded, format); | 
| 367 |     QVERIFY(!certificate.isNull()); | 
| 368 |  | 
| 369 |     if (!absFilePath_digest_md5.isEmpty()) | 
| 370 |         QCOMPARE(convertDigest(readFile(absFilePath_digest_md5)), | 
| 371 |                  certificate.digest(QCryptographicHash::Md5)); | 
| 372 |  | 
| 373 |     if (!absFilePath_digest_sha1.isEmpty()) | 
| 374 |         QCOMPARE(convertDigest(readFile(absFilePath_digest_sha1)), | 
| 375 |                  certificate.digest(QCryptographicHash::Sha1)); | 
| 376 | } | 
| 377 |  | 
| 378 | void tst_QSslCertificate::subjectAlternativeNames_data() | 
| 379 | { | 
| 380 |     QTest::addColumn<QString>(name: "certFilePath" ); | 
| 381 |     QTest::addColumn<QSsl::EncodingFormat>(name: "format" ); | 
| 382 |     QTest::addColumn<QString>(name: "subjAltNameFilePath" ); | 
| 383 |  | 
| 384 |     foreach (CertInfo certInfo, certInfoList) { | 
| 385 |         QString certName = certInfo.fileInfo.fileName(); | 
| 386 |         if (subjAltNameMap.contains(key: certName)) | 
| 387 |             QTest::newRow(dataTag: certName.toLatin1()) | 
| 388 |                 << certInfo.fileInfo.absoluteFilePath() | 
| 389 |                 << certInfo.format | 
| 390 |                 << subjAltNameMap.value(akey: certName); | 
| 391 |     } | 
| 392 | } | 
| 393 |  | 
| 394 | void tst_QSslCertificate::subjectAlternativeNames() | 
| 395 | { | 
| 396 |     if (!QSslSocket::supportsSsl()) | 
| 397 |         return; | 
| 398 |  | 
| 399 |     QFETCH(QString, certFilePath); | 
| 400 |     QFETCH(QSsl::EncodingFormat, format); | 
| 401 |     QFETCH(QString, subjAltNameFilePath); | 
| 402 |  | 
| 403 |     QByteArray encodedCert = readFile(absFilePath: certFilePath); | 
| 404 |     QSslCertificate certificate(encodedCert, format); | 
| 405 |     QVERIFY(!certificate.isNull()); | 
| 406 |  | 
| 407 |     QByteArray fileContents = readFile(absFilePath: subjAltNameFilePath); | 
| 408 |  | 
| 409 |     const QMultiMap<QSsl::AlternativeNameEntryType, QString> altSubjectNames = | 
| 410 |         certificate.subjectAlternativeNames(); | 
| 411 |  | 
| 412 |     // verify that each entry in subjAltNames is present in fileContents | 
| 413 |     for (auto it = altSubjectNames.cbegin(), end = altSubjectNames.cend(); it != end; ++it) { | 
| 414 |         QByteArray type; | 
| 415 |         if (it.key() == QSsl::EmailEntry) | 
| 416 |             type = "email" ; | 
| 417 |         else if (it.key() == QSsl::DnsEntry) | 
| 418 |             type = "DNS" ; | 
| 419 |         else | 
| 420 |             QFAIL("unsupported alternative name type" ); | 
| 421 |         const QByteArray entry = type + ':' + it.value().toLatin1(); | 
| 422 |         QVERIFY(fileContents.contains(entry)); | 
| 423 |     } | 
| 424 |  | 
| 425 |     // verify that each entry in fileContents is present in subjAltNames | 
| 426 |     QRegExp rx(QLatin1String("(email|DNS):([^,\\r\\n]+)" )); | 
| 427 |     for (int pos = 0; (pos = rx.indexIn(str: fileContents, offset: pos)) != -1; pos += rx.matchedLength()) { | 
| 428 |         QSsl::AlternativeNameEntryType key; | 
| 429 |         if (rx.cap(nth: 1) == QLatin1String("email" )) | 
| 430 |             key = QSsl::EmailEntry; | 
| 431 |         else if (rx.cap(nth: 1) == QLatin1String("DNS" )) | 
| 432 |             key = QSsl::DnsEntry; | 
| 433 |         else | 
| 434 |             QFAIL("unsupported alternative name type" ); | 
| 435 |         QVERIFY(altSubjectNames.contains(key, rx.cap(2))); | 
| 436 |     } | 
| 437 | } | 
| 438 |  | 
| 439 | void tst_QSslCertificate::subjectInfoToString() | 
| 440 | { | 
| 441 |     QFile certFile(testDataDir + "more-certificates/aspiriniks.ca.crt" ); | 
| 442 |     const bool ok = certFile.open(flags: QIODevice::ReadOnly); | 
| 443 |     QVERIFY(ok); | 
| 444 |     const auto chain = QSslCertificate::fromDevice(device: &certFile, format: QSsl::Pem); | 
| 445 |     QCOMPARE(chain.size(), 1); | 
| 446 |     const auto cert = chain.at(i: 0); | 
| 447 |     QVERIFY(!cert.isNull()); | 
| 448 |  | 
| 449 |     const auto testInfo = [&cert](QSslCertificate::SubjectInfo info, const QString &expected) { | 
| 450 |         const auto infoAsList = cert.subjectInfo(info); | 
| 451 |         if (infoAsList.size()) | 
| 452 |             return expected == infoAsList.at(i: 0); | 
| 453 |         return expected == QString(); | 
| 454 |     }; | 
| 455 |  | 
| 456 |     QVERIFY(testInfo(QSslCertificate::Organization, QStringLiteral("TT ASA" ))); | 
| 457 |     QVERIFY(testInfo(QSslCertificate::CommonName, QStringLiteral("aspiriniks.troll.no" ))); | 
| 458 |     QVERIFY(testInfo(QSslCertificate::LocalityName, QStringLiteral("Oslo" ))); | 
| 459 |     QVERIFY(testInfo(QSslCertificate::OrganizationalUnitName, QStringLiteral("QT SW" ))); | 
| 460 |     QVERIFY(testInfo(QSslCertificate::CountryName, QStringLiteral("NO" ))); | 
| 461 |     QVERIFY(testInfo(QSslCertificate::StateOrProvinceName, QStringLiteral("Oslo" ))); | 
| 462 |     QVERIFY(testInfo(QSslCertificate::DistinguishedNameQualifier, QString())); | 
| 463 |     QVERIFY(testInfo(QSslCertificate::SerialNumber, QString())); | 
| 464 | #ifndef QT_NO_OPENSSL | 
| 465 |     // TODO: check why generic code does not handle this! | 
| 466 |     QVERIFY(testInfo(QSslCertificate::EmailAddress, QStringLiteral("ababic@trolltech.com" ))); | 
| 467 | #endif | 
| 468 | } | 
| 469 |  | 
| 470 | void tst_QSslCertificate::subjectIssuerDisplayName_data() | 
| 471 | { | 
| 472 |     QTest::addColumn<QString>(name: "certName" ); | 
| 473 |     QTest::addColumn<QString>(name: "expectedName" ); | 
| 474 |  | 
| 475 |     QTest::addRow(format: "CommonName" ) << QStringLiteral("more-certificates/cert-cn.pem" ) << QStringLiteral("YOUR name" ); | 
| 476 |     QTest::addRow(format: "OrganizationName" ) << QStringLiteral("more-certificates/cert-on.pem" ) << QStringLiteral("R&D" ); | 
| 477 |     QTest::addRow(format: "OrganizationUnitName" ) << QStringLiteral("more-certificates/cert-oun.pem" ) << QStringLiteral("Foundations" ); | 
| 478 | #ifndef QT_NO_OPENSSL | 
| 479 |     QTest::addRow(format: "NoSubjectName" ) << QStringLiteral("more-certificates/cert-noname.pem" ) << QString(); | 
| 480 | #endif | 
| 481 | } | 
| 482 |  | 
| 483 | void tst_QSslCertificate::subjectIssuerDisplayName() | 
| 484 | { | 
| 485 |     QFETCH(const QString, certName); | 
| 486 |     QFETCH(const QString, expectedName); | 
| 487 |  | 
| 488 |     const auto chain = QSslCertificate::fromPath(path: testDataDir + certName); | 
| 489 |     QCOMPARE(chain.size(), 1); | 
| 490 |     const auto cert = chain.at(i: 0); | 
| 491 |     QVERIFY(!cert.isNull()); | 
| 492 |     QCOMPARE(cert.subjectDisplayName(), expectedName); | 
| 493 |     QCOMPARE(cert.issuerDisplayName(), expectedName); | 
| 494 | } | 
| 495 |  | 
| 496 | void tst_QSslCertificate::utf8SubjectNames() | 
| 497 | { | 
| 498 |     QSslCertificate cert = QSslCertificate::fromPath(path: testDataDir + "certificates/cert-ss-san-utf8.pem" , format: QSsl::Pem, | 
| 499 |                                                      syntax: QSslCertificate::PatternSyntax::FixedString).first(); | 
| 500 |     QVERIFY(!cert.isNull()); | 
| 501 |  | 
| 502 |     // O is "Heavy Metal Records" with heavy use of "decorations" like accents, umlauts etc., | 
| 503 |     // OU uses arabian / asian script letters near codepoint 64K. | 
| 504 |     // strings split where the compiler would otherwise find three-digit hex numbers | 
| 505 |     static const char *o = "H\xc4\x95\xc4\x82\xc6\xb2\xc3\xbf \xca\x8d\xe1\xba\xbf\xca\x88\xe1\xba"  | 
| 506 |             "\xb7\xe1\xb8\xbb R\xc3\xa9"  "c"  "\xc3\xb6rd\xc5\x9d" ; | 
| 507 |     static const char *ou = "\xe3\x88\xa7"  "A"  "\xe3\x89\x81\xef\xbd\xab"  "BC" ; | 
| 508 |  | 
| 509 |     // the following two tests should help find "\x"-literal encoding bugs in the test itself | 
| 510 |     QCOMPARE(cert.subjectInfo("O" )[0].length(), QString::fromUtf8(o).length()); | 
| 511 |     QCOMPARE (cert.subjectInfo("O" )[0].toUtf8().toHex(), QByteArray(o).toHex()); | 
| 512 |  | 
| 513 |     QCOMPARE(cert.subjectInfo("O" )[0], QString::fromUtf8(o)); | 
| 514 |     QCOMPARE(cert.subjectInfo("OU" )[0], QString::fromUtf8(ou)); | 
| 515 | } | 
| 516 |  | 
| 517 | void tst_QSslCertificate::publicKey_data() | 
| 518 | { | 
| 519 |     QTest::addColumn<QString>(name: "certFilePath" ); | 
| 520 |     QTest::addColumn<QSsl::EncodingFormat>(name: "format" ); | 
| 521 |     QTest::addColumn<QString>(name: "pubkeyFilePath" ); | 
| 522 |  | 
| 523 |     foreach (CertInfo certInfo, certInfoList) { | 
| 524 |         QString certName = certInfo.fileInfo.fileName(); | 
| 525 |         if (pubkeyMap.contains(key: certName)) | 
| 526 |             QTest::newRow(dataTag: certName.toLatin1()) | 
| 527 |                 << certInfo.fileInfo.absoluteFilePath() | 
| 528 |                 << certInfo.format | 
| 529 |                 << pubkeyMap.value(akey: certName); | 
| 530 |     } | 
| 531 | } | 
| 532 |  | 
| 533 | void tst_QSslCertificate::publicKey() | 
| 534 | { | 
| 535 |     if (!QSslSocket::supportsSsl()) | 
| 536 |         return; | 
| 537 |  | 
| 538 |     QFETCH(QString, certFilePath); | 
| 539 |     QFETCH(QSsl::EncodingFormat, format); | 
| 540 |     QFETCH(QString, pubkeyFilePath); | 
| 541 |  | 
| 542 |     QSsl::KeyAlgorithm algorithm; | 
| 543 |     if (QFileInfo(pubkeyFilePath).fileName().startsWith(s: "dsa-" )) | 
| 544 |         algorithm = QSsl::Dsa; | 
| 545 |     else if (QFileInfo(pubkeyFilePath).fileName().startsWith(s: "ec-" )) | 
| 546 |         algorithm = QSsl::Ec; | 
| 547 |     else | 
| 548 |         algorithm = QSsl::Rsa; | 
| 549 |  | 
| 550 |     QByteArray encodedCert = readFile(absFilePath: certFilePath); | 
| 551 |     QSslCertificate certificate(encodedCert, format); | 
| 552 |     QVERIFY(!certificate.isNull()); | 
| 553 |  | 
| 554 |     QByteArray encodedPubkey = readFile(absFilePath: pubkeyFilePath); | 
| 555 |     QSslKey pubkey(encodedPubkey, algorithm, format, QSsl::PublicKey); | 
| 556 |     QVERIFY(!pubkey.isNull()); | 
| 557 |  | 
| 558 |     QCOMPARE(certificate.publicKey(), pubkey); | 
| 559 | } | 
| 560 |  | 
| 561 | void tst_QSslCertificate::toPemOrDer_data() | 
| 562 | { | 
| 563 |     createTestRows(); | 
| 564 | } | 
| 565 |  | 
| 566 | static const char BeginCertString[] = "-----BEGIN CERTIFICATE-----" ; | 
| 567 | static const char EndCertString[] = "-----END CERTIFICATE-----" ; | 
| 568 |  | 
| 569 | // Returns, in Pem-format, the first certificate found in a Pem-formatted block | 
| 570 | // (Note that such a block may contain e.g. a private key at the end). | 
| 571 | static QByteArray firstPemCertificateFromPem(const QByteArray &pem) | 
| 572 | { | 
| 573 |     int startPos = pem.indexOf(c: BeginCertString); | 
| 574 |     int endPos = pem.indexOf(c: EndCertString); | 
| 575 |     if (startPos == -1 || endPos == -1) | 
| 576 |         return QByteArray(); | 
| 577 |     return pem.mid(index: startPos, len: endPos + sizeof(EndCertString) - startPos); | 
| 578 | } | 
| 579 |  | 
| 580 | void tst_QSslCertificate::toPemOrDer() | 
| 581 | { | 
| 582 |     if (!QSslSocket::supportsSsl()) | 
| 583 |         return; | 
| 584 |  | 
| 585 |     QFETCH(QString, absFilePath); | 
| 586 |     QFETCH(QSsl::EncodingFormat, format); | 
| 587 |  | 
| 588 |     QByteArray encoded = readFile(absFilePath); | 
| 589 |     QSslCertificate certificate(encoded, format); | 
| 590 |     QVERIFY(!certificate.isNull()); | 
| 591 |     if (format == QSsl::Pem) { | 
| 592 |         encoded.replace(before: '\r',c: "" ); | 
| 593 |         QByteArray firstPem = firstPemCertificateFromPem(pem: encoded); | 
| 594 |         QCOMPARE(certificate.toPem(), firstPem); | 
| 595 |     } else { | 
| 596 |         // ### for now, we assume that DER-encoded certificates don't contain bundled stuff | 
| 597 |         QCOMPARE(certificate.toDer(), encoded); | 
| 598 |     } | 
| 599 | } | 
| 600 |  | 
| 601 | void tst_QSslCertificate::fromDevice() | 
| 602 | { | 
| 603 |     QTest::ignoreMessage(type: QtWarningMsg, message: "QSslCertificate::fromDevice: cannot read from a null device" ); | 
| 604 |     QList<QSslCertificate> certs = QSslCertificate::fromDevice(device: nullptr); // don't crash | 
| 605 |     QVERIFY(certs.isEmpty()); | 
| 606 |  | 
| 607 |     QFile certFile(testDataDir + "certificates/cert.der" ); | 
| 608 |     const bool ok = certFile.open(flags: QIODevice::ReadOnly); | 
| 609 |     QVERIFY(ok); | 
| 610 |     const auto chain = QSslCertificate::fromDevice(device: &certFile, format: QSsl::Der); | 
| 611 |     QCOMPARE(chain.size(), 1); | 
| 612 |     QVERIFY(!chain.at(0).isNull()); | 
| 613 | } | 
| 614 |  | 
| 615 | void tst_QSslCertificate::fromPath_data() | 
| 616 | { | 
| 617 |     QTest::addColumn<QString>(name: "path" ); | 
| 618 |     QTest::addColumn<int>(name: "syntax" ); | 
| 619 |     QTest::addColumn<bool>(name: "pemencoding" ); | 
| 620 |     QTest::addColumn<int>(name: "numCerts" ); | 
| 621 |  | 
| 622 |     QTest::newRow(dataTag: "empty fixed pem" ) << QString() << int(QRegExp::FixedString) << true << 0; | 
| 623 |     QTest::newRow(dataTag: "empty fixed der" ) << QString() << int(QRegExp::FixedString) << false << 0; | 
| 624 |     QTest::newRow(dataTag: "empty regexp pem" ) << QString() << int(QRegExp::RegExp) << true << 0; | 
| 625 |     QTest::newRow(dataTag: "empty regexp der" ) << QString() << int(QRegExp::RegExp) << false << 0; | 
| 626 |     QTest::newRow(dataTag: "empty wildcard pem" ) << QString() << int(QRegExp::Wildcard) << true << 0; | 
| 627 |     QTest::newRow(dataTag: "empty wildcard der" ) << QString() << int(QRegExp::Wildcard) << false << 0; | 
| 628 |     QTest::newRow(dataTag: "\"certificates\" fixed pem" ) << (testDataDir + "certificates" ) << int(QRegExp::FixedString) << true << 0; | 
| 629 |     QTest::newRow(dataTag: "\"certificates\" fixed der" ) << (testDataDir + "certificates" ) << int(QRegExp::FixedString) << false << 0; | 
| 630 |     QTest::newRow(dataTag: "\"certificates\" regexp pem" ) << (testDataDir + "certificates" ) << int(QRegExp::RegExp) << true << 0; | 
| 631 |     QTest::newRow(dataTag: "\"certificates\" regexp der" ) << (testDataDir + "certificates" ) << int(QRegExp::RegExp) << false << 0; | 
| 632 |     QTest::newRow(dataTag: "\"certificates\" wildcard pem" ) << (testDataDir + "certificates" ) << int(QRegExp::Wildcard) << true << 0; | 
| 633 |     QTest::newRow(dataTag: "\"certificates\" wildcard der" ) << (testDataDir + "certificates" ) << int(QRegExp::Wildcard) << false << 0; | 
| 634 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" fixed pem" ) << (testDataDir + "certificates/cert.pem" ) << int(QRegExp::FixedString) << true << 1; | 
| 635 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" fixed der" ) << (testDataDir + "certificates/cert.pem" ) << int(QRegExp::FixedString) << false << 0; | 
| 636 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" regexp pem" ) << (testDataDir + "certificates/cert.pem" ) << int(QRegExp::RegExp) << true << 1; | 
| 637 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" regexp der" ) << (testDataDir + "certificates/cert.pem" ) << int(QRegExp::RegExp) << false << 0; | 
| 638 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" wildcard pem" ) << (testDataDir + "certificates/cert.pem" ) << int(QRegExp::Wildcard) << true << 1; | 
| 639 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" wildcard der" ) << (testDataDir + "certificates/cert.pem" ) << int(QRegExp::Wildcard) << false << 0; | 
| 640 |     QTest::newRow(dataTag: "\"certificates/*\" fixed pem" ) << (testDataDir + "certificates/*" ) << int(QRegExp::FixedString) << true << 0; | 
| 641 |     QTest::newRow(dataTag: "\"certificates/*\" fixed der" ) << (testDataDir + "certificates/*" ) << int(QRegExp::FixedString) << false << 0; | 
| 642 |     QTest::newRow(dataTag: "\"certificates/*\" regexp pem" ) << (testDataDir + "certificates/*" ) << int(QRegExp::RegExp) << true << 0; | 
| 643 |     QTest::newRow(dataTag: "\"certificates/*\" regexp der" ) << (testDataDir + "certificates/*" ) << int(QRegExp::RegExp) << false << 0; | 
| 644 |     QTest::newRow(dataTag: "\"certificates/*\" wildcard pem" ) << (testDataDir + "certificates/*" ) << int(QRegExp::Wildcard) << true << 7; | 
| 645 |     QTest::newRow(dataTag: "\"certificates/ca*\" wildcard pem" ) << (testDataDir + "certificates/ca*" ) << int(QRegExp::Wildcard) << true << 1; | 
| 646 |     QTest::newRow(dataTag: "\"certificates/cert*\" wildcard pem" ) << (testDataDir + "certificates/cert*" ) << int(QRegExp::Wildcard) << true << 4; | 
| 647 |     QTest::newRow(dataTag: "\"certificates/cert-[sure]*\" wildcard pem" ) << (testDataDir + "certificates/cert-[sure]*" ) << int(QRegExp::Wildcard) << true << 3; | 
| 648 |     QTest::newRow(dataTag: "\"certificates/cert-[not]*\" wildcard pem" ) << (testDataDir + "certificates/cert-[not]*" ) << int(QRegExp::Wildcard) << true << 0; | 
| 649 |     QTest::newRow(dataTag: "\"certificates/*\" wildcard der" ) << (testDataDir + "certificates/*" ) << int(QRegExp::Wildcard) << false << 2; | 
| 650 |     QTest::newRow(dataTag: "\"c*/c*.pem\" fixed pem" ) << (testDataDir + "c*/c*.pem" ) << int(QRegExp::FixedString) << true << 0; | 
| 651 |     QTest::newRow(dataTag: "\"c*/c*.pem\" fixed der" ) << (testDataDir + "c*/c*.pem" ) << int(QRegExp::FixedString) << false << 0; | 
| 652 |     QTest::newRow(dataTag: "\"c*/c*.pem\" regexp pem" ) << (testDataDir + "c*/c*.pem" ) << int(QRegExp::RegExp) << true << 0; | 
| 653 |     QTest::newRow(dataTag: "\"c*/c*.pem\" regexp der" ) << (testDataDir + "c*/c*.pem" ) << int(QRegExp::RegExp) << false << 0; | 
| 654 |     QTest::newRow(dataTag: "\"c*/c*.pem\" wildcard pem" ) << (testDataDir + "c*/c*.pem" ) << int(QRegExp::Wildcard) << true << 5; | 
| 655 |     QTest::newRow(dataTag: "\"c*/c*.pem\" wildcard der" ) << (testDataDir + "c*/c*.pem" ) << int(QRegExp::Wildcard) << false << 0; | 
| 656 |     QTest::newRow(dataTag: "\"d*/c*.pem\" fixed pem" ) << (testDataDir + "d*/c*.pem" ) << int(QRegExp::FixedString) << true << 0; | 
| 657 |     QTest::newRow(dataTag: "\"d*/c*.pem\" fixed der" ) << (testDataDir + "d*/c*.pem" ) << int(QRegExp::FixedString) << false << 0; | 
| 658 |     QTest::newRow(dataTag: "\"d*/c*.pem\" regexp pem" ) << (testDataDir + "d*/c*.pem" ) << int(QRegExp::RegExp) << true << 0; | 
| 659 |     QTest::newRow(dataTag: "\"d*/c*.pem\" regexp der" ) << (testDataDir + "d*/c*.pem" ) << int(QRegExp::RegExp) << false << 0; | 
| 660 |     QTest::newRow(dataTag: "\"d*/c*.pem\" wildcard pem" ) << (testDataDir + "d*/c*.pem" ) << int(QRegExp::Wildcard) << true << 0; | 
| 661 |     QTest::newRow(dataTag: "\"d*/c*.pem\" wildcard der" ) << (testDataDir + "d*/c*.pem" ) << int(QRegExp::Wildcard) << false << 0; | 
| 662 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" fixed pem" ) << (testDataDir + "c.*/c.*.pem" ) << int(QRegExp::FixedString) << true << 0; | 
| 663 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" fixed der" ) << (testDataDir + "c.*/c.*.pem" ) << int(QRegExp::FixedString) << false << 0; | 
| 664 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" regexp pem" ) << (testDataDir + "c.*/c.*.pem" ) << int(QRegExp::RegExp) << true << 5; | 
| 665 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" regexp der" ) << (testDataDir + "c.*/c.*.pem" ) << int(QRegExp::RegExp) << false << 0; | 
| 666 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" wildcard pem" ) << (testDataDir + "c.*/c.*.pem" ) << int(QRegExp::Wildcard) << true << 0; | 
| 667 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" wildcard der" ) << (testDataDir + "c.*/c.*.pem" ) << int(QRegExp::Wildcard) << false << 0; | 
| 668 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" fixed pem" ) << (testDataDir + "d.*/c.*.pem" ) << int(QRegExp::FixedString) << true << 0; | 
| 669 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" fixed der" ) << (testDataDir + "d.*/c.*.pem" ) << int(QRegExp::FixedString) << false << 0; | 
| 670 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" regexp pem" ) << (testDataDir + "d.*/c.*.pem" ) << int(QRegExp::RegExp) << true << 0; | 
| 671 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" regexp der" ) << (testDataDir + "d.*/c.*.pem" ) << int(QRegExp::RegExp) << false << 0; | 
| 672 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" wildcard pem" ) << (testDataDir + "d.*/c.*.pem" ) << int(QRegExp::Wildcard) << true << 0; | 
| 673 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" wildcard der" ) << (testDataDir + "d.*/c.*.pem" ) << int(QRegExp::Wildcard) << false << 0; | 
| 674 | #ifdef Q_OS_LINUX | 
| 675 |     QTest::newRow(dataTag: "absolute path wildcard pem" ) << (testDataDir + "certificates/*.pem" ) << int(QRegExp::Wildcard) << true << 7; | 
| 676 | #endif | 
| 677 |  | 
| 678 |     QTest::newRow(dataTag: "trailing-whitespace" ) << (testDataDir + "more-certificates/trailing-whitespace.pem" ) << int(QRegExp::FixedString) << true << 1; | 
| 679 |     QTest::newRow(dataTag: "no-ending-newline" ) << (testDataDir + "more-certificates/no-ending-newline.pem" ) << int(QRegExp::FixedString) << true << 1; | 
| 680 |     QTest::newRow(dataTag: "malformed-just-begin" ) << (testDataDir + "more-certificates/malformed-just-begin.pem" ) << int(QRegExp::FixedString) << true << 0; | 
| 681 |     QTest::newRow(dataTag: "malformed-just-begin-no-newline" ) << (testDataDir + "more-certificates/malformed-just-begin-no-newline.pem" ) << int(QRegExp::FixedString) << true << 0; | 
| 682 | } | 
| 683 |  | 
| 684 | void tst_QSslCertificate::fromPath() | 
| 685 | { | 
| 686 |     QFETCH(QString, path); | 
| 687 |     QFETCH(int, syntax); | 
| 688 |     QFETCH(bool, pemencoding); | 
| 689 |     QFETCH(int, numCerts); | 
| 690 |  | 
| 691 |     QCOMPARE(QSslCertificate::fromPath(path, | 
| 692 |                                        pemencoding ? QSsl::Pem : QSsl::Der, | 
| 693 |                                        QRegExp::PatternSyntax(syntax)).size(), | 
| 694 |              numCerts); | 
| 695 | } | 
| 696 |  | 
| 697 | void tst_QSslCertificate::fromPath_qregularexpression_data() | 
| 698 | { | 
| 699 |     QTest::addColumn<QString>(name: "path" ); | 
| 700 |     QTest::addColumn<int>(name: "syntax" ); | 
| 701 |     QTest::addColumn<bool>(name: "pemencoding" ); | 
| 702 |     QTest::addColumn<int>(name: "numCerts" ); | 
| 703 |  | 
| 704 |     QTest::newRow(dataTag: "empty fixed pem" ) << QString() << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 705 |     QTest::newRow(dataTag: "empty fixed der" ) << QString() << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 706 |     QTest::newRow(dataTag: "empty regexp pem" ) << QString() << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0; | 
| 707 |     QTest::newRow(dataTag: "empty regexp der" ) << QString() << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 708 |     QTest::newRow(dataTag: "empty wildcard pem" ) << QString() << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0; | 
| 709 |     QTest::newRow(dataTag: "empty wildcard der" ) << QString() << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0; | 
| 710 |     QTest::newRow(dataTag: "\"certificates\" fixed pem" ) << (testDataDir + "certificates" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 711 |     QTest::newRow(dataTag: "\"certificates\" fixed der" ) << (testDataDir + "certificates" ) << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 712 |     QTest::newRow(dataTag: "\"certificates\" regexp pem" ) << (testDataDir + "certificates" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0; | 
| 713 |     QTest::newRow(dataTag: "\"certificates\" regexp der" ) << (testDataDir + "certificates" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 714 |     QTest::newRow(dataTag: "\"certificates\" wildcard pem" ) << (testDataDir + "certificates" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0; | 
| 715 |     QTest::newRow(dataTag: "\"certificates\" wildcard der" ) << (testDataDir + "certificates" ) << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0; | 
| 716 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" fixed pem" ) << (testDataDir + "certificates/cert.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 1; | 
| 717 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" fixed der" ) << (testDataDir + "certificates/cert.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 718 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" regexp pem" ) << (testDataDir + "certificates/cert.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 1; | 
| 719 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" regexp der" ) << (testDataDir + "certificates/cert.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 720 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" wildcard pem" ) << (testDataDir + "certificates/cert.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 1; | 
| 721 |     QTest::newRow(dataTag: "\"certificates/cert.pem\" wildcard der" ) << (testDataDir + "certificates/cert.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0; | 
| 722 |     QTest::newRow(dataTag: "\"certificates/*\" fixed pem" ) << (testDataDir + "certificates/*" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 723 |     QTest::newRow(dataTag: "\"certificates/*\" fixed der" ) << (testDataDir + "certificates/*" ) << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 724 |     QTest::newRow(dataTag: "\"certificates/*\" regexp pem" ) << (testDataDir + "certificates/*" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0; | 
| 725 |     QTest::newRow(dataTag: "\"certificates/*\" regexp der" ) << (testDataDir + "certificates/*" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 726 |     QTest::newRow(dataTag: "\"certificates/*\" wildcard pem" ) << (testDataDir + "certificates/*" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 7; | 
| 727 |     QTest::newRow(dataTag: "\"certificates/ca*\" wildcard pem" ) << (testDataDir + "certificates/ca*" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 1; | 
| 728 |     QTest::newRow(dataTag: "\"certificates/cert*\" wildcard pem" ) << (testDataDir + "certificates/cert*" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 4; | 
| 729 |     QTest::newRow(dataTag: "\"certificates/cert-[sure]*\" wildcard pem" ) << (testDataDir + "certificates/cert-[sure]*" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 3; | 
| 730 |     QTest::newRow(dataTag: "\"certificates/cert-[not]*\" wildcard pem" ) << (testDataDir + "certificates/cert-[not]*" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0; | 
| 731 |     QTest::newRow(dataTag: "\"certificates/*\" wildcard der" ) << (testDataDir + "certificates/*" ) << int(QSslCertificate::PatternSyntax::Wildcard) << false << 2; | 
| 732 |     QTest::newRow(dataTag: "\"c*/c*.pem\" fixed pem" ) << (testDataDir + "c*/c*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 733 |     QTest::newRow(dataTag: "\"c*/c*.pem\" fixed der" ) << (testDataDir + "c*/c*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 734 |     QTest::newRow(dataTag: "\"c*/c*.pem\" regexp pem" ) << (testDataDir + "c*/c*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0; | 
| 735 |     QTest::newRow(dataTag: "\"c*/c*.pem\" regexp der" ) << (testDataDir + "c*/c*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 736 |     QTest::newRow(dataTag: "\"c*/c*.pem\" wildcard pem" ) << (testDataDir + "c*/c*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 5; | 
| 737 |     QTest::newRow(dataTag: "\"c*/c*.pem\" wildcard der" ) << (testDataDir + "c*/c*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0; | 
| 738 |     QTest::newRow(dataTag: "\"d*/c*.pem\" fixed pem" ) << (testDataDir + "d*/c*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 739 |     QTest::newRow(dataTag: "\"d*/c*.pem\" fixed der" ) << (testDataDir + "d*/c*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 740 |     QTest::newRow(dataTag: "\"d*/c*.pem\" regexp pem" ) << (testDataDir + "d*/c*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0; | 
| 741 |     QTest::newRow(dataTag: "\"d*/c*.pem\" regexp der" ) << (testDataDir + "d*/c*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 742 |     QTest::newRow(dataTag: "\"d*/c*.pem\" wildcard pem" ) << (testDataDir + "d*/c*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0; | 
| 743 |     QTest::newRow(dataTag: "\"d*/c*.pem\" wildcard der" ) << (testDataDir + "d*/c*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0; | 
| 744 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" fixed pem" ) << (testDataDir + "c.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 745 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" fixed der" ) << (testDataDir + "c.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 746 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" regexp pem" ) << (testDataDir + "c.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 5; | 
| 747 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" regexp der" ) << (testDataDir + "c.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 748 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" wildcard pem" ) << (testDataDir + "c.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0; | 
| 749 |     QTest::newRow(dataTag: "\"c.*/c.*.pem\" wildcard der" ) << (testDataDir + "c.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0; | 
| 750 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" fixed pem" ) << (testDataDir + "d.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 751 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" fixed der" ) << (testDataDir + "d.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << false << 0; | 
| 752 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" regexp pem" ) << (testDataDir + "d.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0; | 
| 753 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" regexp der" ) << (testDataDir + "d.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0; | 
| 754 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" wildcard pem" ) << (testDataDir + "d.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0; | 
| 755 |     QTest::newRow(dataTag: "\"d.*/c.*.pem\" wildcard der" ) << (testDataDir + "d.*/c.*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0; | 
| 756 | #ifdef Q_OS_LINUX | 
| 757 |     QTest::newRow(dataTag: "absolute path wildcard pem" ) << (testDataDir + "certificates/*.pem" ) << int(QSslCertificate::PatternSyntax::Wildcard) << true << 7; | 
| 758 | #endif | 
| 759 |  | 
| 760 |     QTest::newRow(dataTag: "trailing-whitespace" ) << (testDataDir + "more-certificates/trailing-whitespace.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 1; | 
| 761 |     QTest::newRow(dataTag: "no-ending-newline" ) << (testDataDir + "more-certificates/no-ending-newline.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 1; | 
| 762 |     QTest::newRow(dataTag: "malformed-just-begin" ) << (testDataDir + "more-certificates/malformed-just-begin.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 763 |     QTest::newRow(dataTag: "malformed-just-begin-no-newline" ) << (testDataDir + "more-certificates/malformed-just-begin-no-newline.pem" ) << int(QSslCertificate::PatternSyntax::FixedString) << true << 0; | 
| 764 | } | 
| 765 |  | 
| 766 | void tst_QSslCertificate::fromPath_qregularexpression() | 
| 767 | { | 
| 768 |     QFETCH(QString, path); | 
| 769 |     QFETCH(int, syntax); | 
| 770 |     QFETCH(bool, pemencoding); | 
| 771 |     QFETCH(int, numCerts); | 
| 772 |  | 
| 773 |     QCOMPARE(QSslCertificate::fromPath(path, | 
| 774 |                                        pemencoding ? QSsl::Pem : QSsl::Der, | 
| 775 |                                        QSslCertificate::PatternSyntax(syntax)).size(), | 
| 776 |              numCerts); | 
| 777 | } | 
| 778 |  | 
| 779 | void tst_QSslCertificate::certInfo() | 
| 780 | { | 
| 781 | // MD5 Fingerprint=B6:CF:57:34:DA:A9:73:21:82:F7:CF:4D:3D:85:31:88 | 
| 782 | // SHA1 Fingerprint=B6:D1:51:82:E0:29:CA:59:96:38:BD:B6:F9:40:05:91:6D:49:09:60 | 
| 783 | // Certificate: | 
| 784 | //     Data: | 
| 785 | //         Version: 1 (0x0) | 
| 786 | //         Serial Number: 17 (0x11) | 
| 787 | //         Signature Algorithm: sha1WithRSAEncryption | 
| 788 | //         Issuer: C=AU, ST=Queensland, O=CryptSoft Pty Ltd, CN=Test CA (1024 bit) | 
| 789 | //         Validity | 
| 790 | //             Not Before: Apr 17 07:40:26 2007 GMT | 
| 791 | //             Not After : May 17 07:40:26 2007 GMT | 
| 792 | //         Subject: CN=name/with/slashes, C=NO | 
| 793 | //         Subject Public Key Info: | 
| 794 | //             Public Key Algorithm: rsaEncryption | 
| 795 | //             RSA Public Key: (1024 bit) | 
| 796 | //                 Modulus (1024 bit): | 
| 797 | //                     00:eb:9d:e9:03:ac:30:4f:a9:58:03:44:c7:18:26: | 
| 798 | //                     2f:48:93:d5:ac:a0:fb:e8:53:c4:7b:2a:01:89:e6: | 
| 799 | //                     fc:5a:0c:c5:f5:21:f8:d7:4a:92:02:67:db:f1:9f: | 
| 800 | //                     36:9a:62:9d:f3:ce:48:8e:ba:ed:5a:a8:9d:4f:bb: | 
| 801 | //                     24:16:43:4c:b5:79:08:f6:d9:22:8f:5f:15:0a:43: | 
| 802 | //                     25:03:7a:9d:a7:af:e3:26:b1:53:55:5e:60:57:c8: | 
| 803 | //                     ed:2f:1c:f3:36:0a:78:64:91:f9:17:a7:34:d7:8b: | 
| 804 | //                     bd:f1:fc:d1:8c:4f:a5:96:75:b2:7b:fc:21:f0:c7: | 
| 805 | //                     d9:5f:0c:57:18:b2:af:b9:4b | 
| 806 | //                 Exponent: 65537 (0x10001) | 
| 807 | //     Signature Algorithm: sha1WithRSAEncryption | 
| 808 | //         95:e6:94:e2:98:33:57:a2:98:fa:af:50:b9:76:a9:51:83:2c: | 
| 809 | //         0b:61:a2:36:d0:e6:90:6d:e4:f8:c4:c7:50:ef:17:94:4e:21: | 
| 810 | //         a8:fa:c8:33:aa:d1:7f:bc:ca:41:d6:7d:e7:44:76:c0:bf:45: | 
| 811 | //         4a:76:25:42:6d:53:76:fd:fc:74:29:1a:ea:2b:cc:06:ab:d1: | 
| 812 | //         b8:eb:7d:6b:11:f7:9b:41:bb:9f:31:cb:ed:4d:f3:68:26:ed: | 
| 813 | //         13:1d:f2:56:59:fe:6f:7c:98:b6:25:69:4e:ea:b4:dc:c2:eb: | 
| 814 | //         b7:bb:50:18:05:ba:ad:af:08:49:fe:98:63:55:ba:e7:fb:95: | 
| 815 | //         5d:91 | 
| 816 |     static const char pem[] = | 
| 817 |         "-----BEGIN CERTIFICATE-----\n"  | 
| 818 |         "MIIB8zCCAVwCAREwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n"  | 
| 819 |         "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n"  | 
| 820 |         "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDcwNDE3MDc0MDI2WhcNMDcwNTE3\n"  | 
| 821 |         "MDc0MDI2WjApMRowGAYDVQQDExFuYW1lL3dpdGgvc2xhc2hlczELMAkGA1UEBhMC\n"  | 
| 822 |         "Tk8wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOud6QOsME+pWANExxgmL0iT\n"  | 
| 823 |         "1ayg++hTxHsqAYnm/FoMxfUh+NdKkgJn2/GfNppinfPOSI667VqonU+7JBZDTLV5\n"  | 
| 824 |         "CPbZIo9fFQpDJQN6naev4yaxU1VeYFfI7S8c8zYKeGSR+RenNNeLvfH80YxPpZZ1\n"  | 
| 825 |         "snv8IfDH2V8MVxiyr7lLAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAleaU4pgzV6KY\n"  | 
| 826 |         "+q9QuXapUYMsC2GiNtDmkG3k+MTHUO8XlE4hqPrIM6rRf7zKQdZ950R2wL9FSnYl\n"  | 
| 827 |         "Qm1Tdv38dCka6ivMBqvRuOt9axH3m0G7nzHL7U3zaCbtEx3yVln+b3yYtiVpTuq0\n"  | 
| 828 |         "3MLrt7tQGAW6ra8ISf6YY1W65/uVXZE=\n"  | 
| 829 |         "-----END CERTIFICATE-----\n" ; | 
| 830 |     static const char der[] =   // hex encoded | 
| 831 |         "30:82:01:f3:30:82:01:5c:02:01:11:30:0d:06:09:2a"  | 
| 832 |         "86:48:86:f7:0d:01:01:05:05:00:30:5b:31:0b:30:09"  | 
| 833 |         "06:03:55:04:06:13:02:41:55:31:13:30:11:06:03:55"  | 
| 834 |         "04:08:13:0a:51:75:65:65:6e:73:6c:61:6e:64:31:1a"  | 
| 835 |         "30:18:06:03:55:04:0a:13:11:43:72:79:70:74:53:6f"  | 
| 836 |         "66:74:20:50:74:79:20:4c:74:64:31:1b:30:19:06:03"  | 
| 837 |         "55:04:03:13:12:54:65:73:74:20:43:41:20:28:31:30"  | 
| 838 |         "32:34:20:62:69:74:29:30:1e:17:0d:30:37:30:34:31"  | 
| 839 |         "37:30:37:34:30:32:36:5a:17:0d:30:37:30:35:31:37"  | 
| 840 |         "30:37:34:30:32:36:5a:30:29:31:1a:30:18:06:03:55"  | 
| 841 |         "04:03:13:11:6e:61:6d:65:2f:77:69:74:68:2f:73:6c"  | 
| 842 |         "61:73:68:65:73:31:0b:30:09:06:03:55:04:06:13:02"  | 
| 843 |         "4e:4f:30:81:9f:30:0d:06:09:2a:86:48:86:f7:0d:01"  | 
| 844 |         "01:01:05:00:03:81:8d:00:30:81:89:02:81:81:00:eb"  | 
| 845 |         "9d:e9:03:ac:30:4f:a9:58:03:44:c7:18:26:2f:48:93"  | 
| 846 |         "d5:ac:a0:fb:e8:53:c4:7b:2a:01:89:e6:fc:5a:0c:c5"  | 
| 847 |         "f5:21:f8:d7:4a:92:02:67:db:f1:9f:36:9a:62:9d:f3"  | 
| 848 |         "ce:48:8e:ba:ed:5a:a8:9d:4f:bb:24:16:43:4c:b5:79"  | 
| 849 |         "08:f6:d9:22:8f:5f:15:0a:43:25:03:7a:9d:a7:af:e3"  | 
| 850 |         "26:b1:53:55:5e:60:57:c8:ed:2f:1c:f3:36:0a:78:64"  | 
| 851 |         "91:f9:17:a7:34:d7:8b:bd:f1:fc:d1:8c:4f:a5:96:75"  | 
| 852 |         "b2:7b:fc:21:f0:c7:d9:5f:0c:57:18:b2:af:b9:4b:02"  | 
| 853 |         "03:01:00:01:30:0d:06:09:2a:86:48:86:f7:0d:01:01"  | 
| 854 |         "05:05:00:03:81:81:00:95:e6:94:e2:98:33:57:a2:98"  | 
| 855 |         "fa:af:50:b9:76:a9:51:83:2c:0b:61:a2:36:d0:e6:90"  | 
| 856 |         "6d:e4:f8:c4:c7:50:ef:17:94:4e:21:a8:fa:c8:33:aa"  | 
| 857 |         "d1:7f:bc:ca:41:d6:7d:e7:44:76:c0:bf:45:4a:76:25"  | 
| 858 |         "42:6d:53:76:fd:fc:74:29:1a:ea:2b:cc:06:ab:d1:b8"  | 
| 859 |         "eb:7d:6b:11:f7:9b:41:bb:9f:31:cb:ed:4d:f3:68:26"  | 
| 860 |         "ed:13:1d:f2:56:59:fe:6f:7c:98:b6:25:69:4e:ea:b4"  | 
| 861 |         "dc:c2:eb:b7:bb:50:18:05:ba:ad:af:08:49:fe:98:63"  | 
| 862 |         "55:ba:e7:fb:95:5d:91" ; | 
| 863 |  | 
| 864 |     QSslCertificate cert =  QSslCertificate::fromPath(path: testDataDir + "certificates/cert.pem" , format: QSsl::Pem, | 
| 865 |                                                       syntax: QSslCertificate::PatternSyntax::FixedString).first(); | 
| 866 |     QVERIFY(!cert.isNull()); | 
| 867 |  | 
| 868 |     QCOMPARE(cert.issuerInfo(QSslCertificate::Organization)[0], QString("CryptSoft Pty Ltd" )); | 
| 869 |     QCOMPARE(cert.issuerInfo(QSslCertificate::CommonName)[0], QString("Test CA (1024 bit)" )); | 
| 870 |     QCOMPARE(cert.issuerInfo(QSslCertificate::LocalityName), QStringList()); | 
| 871 |     QCOMPARE(cert.issuerInfo(QSslCertificate::OrganizationalUnitName), QStringList()); | 
| 872 |     QCOMPARE(cert.issuerInfo(QSslCertificate::CountryName)[0], QString("AU" )); | 
| 873 |     QCOMPARE(cert.issuerInfo(QSslCertificate::StateOrProvinceName)[0], QString("Queensland" )); | 
| 874 |  | 
| 875 |     QCOMPARE(cert.issuerInfo("O" )[0], QString("CryptSoft Pty Ltd" )); | 
| 876 |     QCOMPARE(cert.issuerInfo("CN" )[0], QString("Test CA (1024 bit)" )); | 
| 877 |     QCOMPARE(cert.issuerInfo("L" ), QStringList()); | 
| 878 |     QCOMPARE(cert.issuerInfo("OU" ), QStringList()); | 
| 879 |     QCOMPARE(cert.issuerInfo("C" )[0], QString("AU" )); | 
| 880 |     QCOMPARE(cert.issuerInfo("ST" )[0], QString("Queensland" )); | 
| 881 |  | 
| 882 |     QCOMPARE(cert.subjectInfo(QSslCertificate::Organization), QStringList()); | 
| 883 |     QCOMPARE(cert.subjectInfo(QSslCertificate::CommonName)[0], QString("name/with/slashes" )); | 
| 884 |     QCOMPARE(cert.subjectInfo(QSslCertificate::LocalityName), QStringList()); | 
| 885 |     QCOMPARE(cert.subjectInfo(QSslCertificate::OrganizationalUnitName), QStringList()); | 
| 886 |     QCOMPARE(cert.subjectInfo(QSslCertificate::CountryName)[0], QString("NO" )); | 
| 887 |     QCOMPARE(cert.subjectInfo(QSslCertificate::StateOrProvinceName), QStringList()); | 
| 888 |  | 
| 889 |     QCOMPARE(cert.subjectInfo("O" ), QStringList()); | 
| 890 |     QCOMPARE(cert.subjectInfo("CN" )[0], QString("name/with/slashes" )); | 
| 891 |     QCOMPARE(cert.subjectInfo("L" ), QStringList()); | 
| 892 |     QCOMPARE(cert.subjectInfo("OU" ), QStringList()); | 
| 893 |     QCOMPARE(cert.subjectInfo("C" )[0], QString("NO" )); | 
| 894 |     QCOMPARE(cert.subjectInfo("ST" ), QStringList()); | 
| 895 |  | 
| 896 |     QCOMPARE(cert.version(), QByteArray::number(1)); | 
| 897 |     QCOMPARE(cert.serialNumber(), QByteArray("11" )); | 
| 898 |  | 
| 899 |     QCOMPARE(cert.toPem().constData(), (const char*)pem); | 
| 900 |     QCOMPARE(cert.toDer(), QByteArray::fromHex(der)); | 
| 901 |  | 
| 902 |     QCOMPARE(cert.digest(QCryptographicHash::Md5), | 
| 903 |              QByteArray::fromHex("B6:CF:57:34:DA:A9:73:21:82:F7:CF:4D:3D:85:31:88" )); | 
| 904 |     QCOMPARE(cert.digest(QCryptographicHash::Sha1), | 
| 905 |              QByteArray::fromHex("B6:D1:51:82:E0:29:CA:59:96:38:BD:B6:F9:40:05:91:6D:49:09:60" )); | 
| 906 |  | 
| 907 |     QCOMPARE(cert.effectiveDate().toUTC(), QDateTime(QDate(2007, 4, 17), QTime(7,40,26), Qt::UTC)); | 
| 908 |     QCOMPARE(cert.expiryDate().toUTC(), QDateTime(QDate(2007, 5, 17), QTime(7,40,26), Qt::UTC)); | 
| 909 |     QVERIFY(cert.expiryDate() < QDateTime::currentDateTime());   // cert has expired | 
| 910 |  | 
| 911 |     QSslCertificate copy = cert; | 
| 912 |     QCOMPARE(cert, copy); | 
| 913 |     QVERIFY(!(cert != copy)); | 
| 914 |  | 
| 915 |     QCOMPARE(cert, QSslCertificate(pem, QSsl::Pem)); | 
| 916 |     QCOMPARE(cert, QSslCertificate(QByteArray::fromHex(der), QSsl::Der)); | 
| 917 | } | 
| 918 |  | 
| 919 | void tst_QSslCertificate::certInfoQByteArray() | 
| 920 | { | 
| 921 |     QSslCertificate cert =  QSslCertificate::fromPath(path: testDataDir + "certificates/cert.pem" , format: QSsl::Pem, | 
| 922 |                                                       syntax: QSslCertificate::PatternSyntax::FixedString).first(); | 
| 923 |     QVERIFY(!cert.isNull()); | 
| 924 |  | 
| 925 |     // in this test, check the bytearray variants before the enum variants to see if | 
| 926 |     // we fixed a bug we had with lazy initialization of the values. | 
| 927 |     QCOMPARE(cert.issuerInfo("CN" )[0], QString("Test CA (1024 bit)" )); | 
| 928 |     QCOMPARE(cert.subjectInfo("CN" )[0], QString("name/with/slashes" )); | 
| 929 | } | 
| 930 |  | 
| 931 | void tst_QSslCertificate::task256066toPem() | 
| 932 | { | 
| 933 |     // a certificate whose PEM encoding's length is a multiple of 64 | 
| 934 |     const char *mycert = "-----BEGIN CERTIFICATE-----\n"  \ | 
| 935 |                          "MIIEGjCCAwKgAwIBAgIESikYSjANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJF\n"  \ | 
| 936 |                          "RTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEPMA0GA1UECxMG\n"  \ | 
| 937 |                          "RVNURUlEMRcwFQYDVQQDEw5FU1RFSUQtU0sgMjAwNzAeFw0wOTA2MDUxMzA2MTha\n"  \ | 
| 938 |                          "Fw0xNDA2MDkyMTAwMDBaMIGRMQswCQYDVQQGEwJFRTEPMA0GA1UEChMGRVNURUlE\n"  \ | 
| 939 |                          "MRcwFQYDVQQLEw5hdXRoZW50aWNhdGlvbjEhMB8GA1UEAxMYSEVJQkVSRyxTVkVO\n"  \ | 
| 940 |                          "LDM3NzA5MjcwMjg1MRAwDgYDVQQEEwdIRUlCRVJHMQ0wCwYDVQQqEwRTVkVOMRQw\n"  \ | 
| 941 |                          "EgYDVQQFEwszNzcwOTI3MDI4NTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n"  \ | 
| 942 |                          "k2Euwhm34vu1jOFp02J5fQRx9LW2C7x78CbJ7yInoAKn7QR8UdxTU7mJk90Opejo\n"  \ | 
| 943 |                          "71RUi2/aYl4jCr9gr99v2YoLufMRwAuqdmwmwqH1WAHRUtIcD0oPdKyelmmn9ig0\n"  \ | 
| 944 |                          "RV+yJLNT3dnyrwPw+uuzDe3DeKepGKE4lxexliCaAx0CAyCMW6OCATEwggEtMA4G\n"  \ | 
| 945 |                          "A1UdDwEB/wQEAwIEsDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwPAYD\n"  \ | 
| 946 |                          "VR0fBDUwMzAxoC+gLYYraHR0cDovL3d3dy5zay5lZS9jcmxzL2VzdGVpZC9lc3Rl\n"  \ | 
| 947 |                          "aWQyMDA3LmNybDAgBgNVHREEGTAXgRVzdmVuLmhlaWJlcmdAZWVzdGkuZWUwUQYD\n"  \ | 
| 948 |                          "VR0gBEowSDBGBgsrBgEEAc4fAQEBATA3MBIGCCsGAQUFBwICMAYaBG5vbmUwIQYI\n"  \ | 
| 949 |                          "KwYBBQUHAgEWFWh0dHA6Ly93d3cuc2suZWUvY3BzLzAfBgNVHSMEGDAWgBRIBt6+\n"  \ | 
| 950 |                          "jIdXlYB4Y/qcIysroDoYdTAdBgNVHQ4EFgQUKCjpDf+LcvL6AH0QOiW6rMTtB/0w\n"  \ | 
| 951 |                          "CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEABRyRuUm9zt8V27WuNeXtCDmU\n"  \ | 
| 952 |                          "MGzA6g4QXNAd2nxFzT3k+kNzzQTOcgRdmjiEPuK49On+GWnBr/5MSBNhbCJVPWr/\n"  \ | 
| 953 |                          "yym1UYTBisaqhRt/N/kwZqd0bHeLJk+ZxSePXRyqkp9H8KPWqz7H+O/FxRS4ffxo\n"  \ | 
| 954 |                          "Q9Clem+e0bcjNlL5xXiRGycBeZq8cKj+0+A/UuattznQlvHdlCEsSeu1fPOORqFV\n"  \ | 
| 955 |                          "fZur4HC31lQD7xVvETLiL83CtOQC78+29XPD6Zlrrc5OF2yibSVParY19b8Zh6yu\n"  \ | 
| 956 |                          "p1dNvN8pBgXGrsyxRonwHooV2ghGNmGILkpdvlQfnxeCUg4erfHjDdSY9vmT7w==\n"  \ | 
| 957 |                          "-----END CERTIFICATE-----\n" ; | 
| 958 |  | 
| 959 |     QByteArray pem1(mycert); | 
| 960 |     QSslCertificate cert1(pem1); | 
| 961 |     QVERIFY(!cert1.isNull()); | 
| 962 |     QByteArray pem2(cert1.toPem()); | 
| 963 |     QSslCertificate cert2(pem2); | 
| 964 |     QVERIFY(!cert2.isNull()); | 
| 965 |     QCOMPARE(pem1, pem2); | 
| 966 | } | 
| 967 |  | 
| 968 | void tst_QSslCertificate::nulInCN() | 
| 969 | { | 
| 970 | #if QT_CONFIG(securetransport) || defined(Q_OS_WINRT) || QT_CONFIG(schannel) | 
| 971 |     QSKIP("Generic QSslCertificatePrivate fails this test" ); | 
| 972 | #endif | 
| 973 |     QList<QSslCertificate> certList = | 
| 974 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/badguy-nul-cn.crt" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 975 |     QCOMPARE(certList.size(), 1); | 
| 976 |  | 
| 977 |     const QSslCertificate &cert = certList.at(i: 0); | 
| 978 |     QVERIFY(!cert.isNull()); | 
| 979 |  | 
| 980 |     QString cn = cert.subjectInfo(info: QSslCertificate::CommonName)[0]; | 
| 981 |     QVERIFY(cn != QLatin1String("www.bank.com" )); | 
| 982 |  | 
| 983 |     static const char realCN[] = "www.bank.com\0.badguy.com" ; | 
| 984 |     QCOMPARE(cn, QString::fromLatin1(realCN, sizeof realCN - 1)); | 
| 985 | } | 
| 986 |  | 
| 987 | void tst_QSslCertificate::nulInSan() | 
| 988 | { | 
| 989 | #if QT_CONFIG(securetransport) || defined(Q_OS_WINRT) || QT_CONFIG(schannel) | 
| 990 |     QSKIP("Generic QSslCertificatePrivate fails this test" ); | 
| 991 | #endif | 
| 992 |     QList<QSslCertificate> certList = | 
| 993 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/badguy-nul-san.crt" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 994 |     QCOMPARE(certList.size(), 1); | 
| 995 |  | 
| 996 |     const QSslCertificate &cert = certList.at(i: 0); | 
| 997 |     QVERIFY(!cert.isNull()); | 
| 998 |  | 
| 999 |     QMultiMap<QSsl::AlternativeNameEntryType, QString> san = cert.subjectAlternativeNames(); | 
| 1000 |     QVERIFY(!san.isEmpty()); | 
| 1001 |  | 
| 1002 |     QString dnssan = san.value(akey: QSsl::DnsEntry); | 
| 1003 |     QVERIFY(!dnssan.isEmpty()); | 
| 1004 |     QVERIFY(dnssan != "www.bank.com" ); | 
| 1005 |  | 
| 1006 |     static const char realSAN[] = "www.bank.com\0www.badguy.com" ; | 
| 1007 |     QCOMPARE(dnssan, QString::fromLatin1(realSAN, sizeof realSAN - 1)); | 
| 1008 | } | 
| 1009 |  | 
| 1010 | void tst_QSslCertificate::largeSerialNumber() | 
| 1011 | { | 
| 1012 |     QList<QSslCertificate> certList = | 
| 1013 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/cert-large-serial-number.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1014 |  | 
| 1015 |     QCOMPARE(certList.size(), 1); | 
| 1016 |  | 
| 1017 |     const QSslCertificate &cert = certList.at(i: 0); | 
| 1018 |     QVERIFY(!cert.isNull()); | 
| 1019 |     QCOMPARE(cert.serialNumber(), QByteArray("01:02:03:04:05:06:07:08:09:10:aa:bb:cc:dd:ee:ff:17:18:19:20" )); | 
| 1020 | } | 
| 1021 |  | 
| 1022 | void tst_QSslCertificate::largeExpirationDate() // QTBUG-12489 | 
| 1023 | { | 
| 1024 |     QList<QSslCertificate> certList = | 
| 1025 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/cert-large-expiration-date.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1026 |  | 
| 1027 |     QCOMPARE(certList.size(), 1); | 
| 1028 |  | 
| 1029 |     const QSslCertificate &cert = certList.at(i: 0); | 
| 1030 |     QVERIFY(!cert.isNull()); | 
| 1031 |     QCOMPARE(cert.effectiveDate().toUTC(), QDateTime(QDate(2010, 8, 4), QTime(9, 53, 41), Qt::UTC)); | 
| 1032 |     // if the date is larger than 2049, then the generalized time format is used | 
| 1033 |     QCOMPARE(cert.expiryDate().toUTC(), QDateTime(QDate(2051, 8, 29), QTime(9, 53, 41), Qt::UTC)); | 
| 1034 | } | 
| 1035 |  | 
| 1036 | void tst_QSslCertificate::blacklistedCertificates() | 
| 1037 | { | 
| 1038 |     QList<QSslCertificate> blacklistedCerts = QSslCertificate::fromPath(path: testDataDir + "more-certificates/blacklisted*.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::Wildcard); | 
| 1039 |     QVERIFY(blacklistedCerts.count() > 0); | 
| 1040 |     for (int a = 0; a < blacklistedCerts.count(); a++) { | 
| 1041 |         QVERIFY(blacklistedCerts.at(a).isBlacklisted()); | 
| 1042 |     } | 
| 1043 | } | 
| 1044 |  | 
| 1045 | void tst_QSslCertificate::selfsignedCertificates() | 
| 1046 | { | 
| 1047 |     QVERIFY(QSslCertificate::fromPath(testDataDir + "certificates/cert-ss.pem" , QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first().isSelfSigned()); | 
| 1048 |     QVERIFY(!QSslCertificate::fromPath(testDataDir + "certificates/cert.pem" , QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first().isSelfSigned()); | 
| 1049 |     QVERIFY(!QSslCertificate().isSelfSigned()); | 
| 1050 | } | 
| 1051 |  | 
| 1052 | void tst_QSslCertificate::toText() | 
| 1053 | { | 
| 1054 |     QList<QSslCertificate> certList = | 
| 1055 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/cert-large-expiration-date.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1056 |  | 
| 1057 |     QCOMPARE(certList.size(), 1); | 
| 1058 |     const QSslCertificate &cert = certList.at(i: 0); | 
| 1059 |  | 
| 1060 |     // Openssl's cert dump method changed slightly between 0.9.8, 1.0.0 and 1.01 versions, so we want it to match any output | 
| 1061 |  | 
| 1062 |     QFile f098(testDataDir + "more-certificates/cert-large-expiration-date.txt.0.9.8" ); | 
| 1063 |     QVERIFY(f098.open(QIODevice::ReadOnly | QFile::Text)); | 
| 1064 |     QByteArray txt098 = f098.readAll(); | 
| 1065 |  | 
| 1066 |     QFile f100(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.0.0" ); | 
| 1067 |     QVERIFY(f100.open(QIODevice::ReadOnly | QFile::Text)); | 
| 1068 |     QByteArray txt100 = f100.readAll(); | 
| 1069 |  | 
| 1070 |     QFile f101(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.0.1" ); | 
| 1071 |     QVERIFY(f101.open(QIODevice::ReadOnly | QFile::Text)); | 
| 1072 |     QByteArray txt101 = f101.readAll(); | 
| 1073 |  | 
| 1074 |     QFile f101c(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.0.1c" ); | 
| 1075 |     QVERIFY(f101c.open(QIODevice::ReadOnly | QFile::Text)); | 
| 1076 |     QByteArray txt101c = f101c.readAll(); | 
| 1077 |  | 
| 1078 |     QFile f111(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.1.1" ); | 
| 1079 |     QVERIFY(f111.open(QIODevice::ReadOnly | QFile::Text)); | 
| 1080 |     QByteArray txt111 = f111.readAll(); | 
| 1081 |  | 
| 1082 |     QString txtcert = cert.toText(); | 
| 1083 |  | 
| 1084 | #ifdef QT_NO_OPENSSL | 
| 1085 |     QEXPECT_FAIL("" , "QTBUG-40884: QSslCertificate::toText is not implemented on WinRT" , Continue); | 
| 1086 | #endif | 
| 1087 |     QVERIFY(QString::fromLatin1(txt098) == txtcert || | 
| 1088 |             QString::fromLatin1(txt100) == txtcert || | 
| 1089 |             QString::fromLatin1(txt101) == txtcert || | 
| 1090 |             QString::fromLatin1(txt101c) == txtcert || | 
| 1091 |             QString::fromLatin1(txt111) == txtcert ); | 
| 1092 | } | 
| 1093 |  | 
| 1094 | void tst_QSslCertificate::multipleCommonNames() | 
| 1095 | { | 
| 1096 |     QList<QSslCertificate> certList = | 
| 1097 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/test-cn-two-cns-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1098 |     QVERIFY(certList.count() > 0); | 
| 1099 |  | 
| 1100 |     QStringList commonNames = certList[0].subjectInfo(info: QSslCertificate::CommonName); | 
| 1101 |     QVERIFY(commonNames.contains(QString("www.example.com" ))); | 
| 1102 |     QVERIFY(commonNames.contains(QString("www2.example.com" ))); | 
| 1103 | } | 
| 1104 |  | 
| 1105 | void tst_QSslCertificate::subjectAndIssuerAttributes() | 
| 1106 | { | 
| 1107 |     QList<QSslCertificate> certList = | 
| 1108 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/test-cn-with-drink-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1109 |     QVERIFY(certList.count() > 0); | 
| 1110 |  | 
| 1111 |     QList<QByteArray> attributes = certList[0].subjectInfoAttributes(); | 
| 1112 |     QVERIFY(attributes.contains(QByteArray("favouriteDrink" ))); | 
| 1113 |     attributes.clear(); | 
| 1114 |  | 
| 1115 |     certList = QSslCertificate::fromPath(path: testDataDir + "more-certificates/natwest-banking.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1116 |     QVERIFY(certList.count() > 0); | 
| 1117 |  | 
| 1118 |     QByteArray shortName("1.3.6.1.4.1.311.60.2.1.3" ); | 
| 1119 | #if !defined(QT_NO_OPENSSL) && defined(SN_jurisdictionCountryName) | 
| 1120 |     shortName = SN_jurisdictionCountryName; | 
| 1121 | #endif | 
| 1122 |     attributes = certList[0].subjectInfoAttributes(); | 
| 1123 |     QVERIFY(attributes.contains(shortName)); | 
| 1124 | } | 
| 1125 |  | 
| 1126 | void tst_QSslCertificate::verify() | 
| 1127 | { | 
| 1128 | #if QT_CONFIG(securetransport) | 
| 1129 |     QSKIP("Not implemented in SecureTransport" ); | 
| 1130 | #endif | 
| 1131 |  | 
| 1132 |     QList<QSslError> errors; | 
| 1133 |     QList<QSslCertificate> toVerify; | 
| 1134 |  | 
| 1135 |     // Like QVERIFY, but be verbose about the content of `errors' when failing | 
| 1136 | #define VERIFY_VERBOSE(A)                                       \ | 
| 1137 |     QVERIFY2((A),                                               \ | 
| 1138 |         qPrintable(QString("errors: %1").arg(toString(errors))) \ | 
| 1139 |     ) | 
| 1140 |  | 
| 1141 | #ifdef QT_NO_OPENSSL | 
| 1142 |     QEXPECT_FAIL("" , "QTBUG-40884: WinRT API does not yet support verifying a chain" , Abort); | 
| 1143 | #endif | 
| 1144 |     // Empty chain is unspecified error | 
| 1145 |     errors = QSslCertificate::verify(certificateChain: toVerify); | 
| 1146 |     VERIFY_VERBOSE(errors.count() == 1); | 
| 1147 |     VERIFY_VERBOSE(errors[0] == QSslError(QSslError::UnspecifiedError)); | 
| 1148 |     errors.clear(); | 
| 1149 |  | 
| 1150 |     // Verify a valid cert signed by a CA | 
| 1151 |     QList<QSslCertificate> caCerts = QSslCertificate::fromPath(path: testDataDir + "verify-certs/cacert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1152 |  | 
| 1153 | QT_WARNING_PUSH | 
| 1154 | QT_WARNING_DISABLE_DEPRECATED | 
| 1155 |     QSslSocket::addDefaultCaCertificate(certificate: caCerts.first()); | 
| 1156 | QT_WARNING_POP | 
| 1157 |  | 
| 1158 |     toVerify = QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-ocsp-good-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1159 |  | 
| 1160 |     errors = QSslCertificate::verify(certificateChain: toVerify); | 
| 1161 |     VERIFY_VERBOSE(errors.count() == 0); | 
| 1162 |     errors.clear(); | 
| 1163 |  | 
| 1164 |     // Test a blacklisted certificate | 
| 1165 |     toVerify = QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1166 |     errors = QSslCertificate::verify(certificateChain: toVerify); | 
| 1167 |     bool foundBlack = false; | 
| 1168 |     foreach (const QSslError &error, errors) { | 
| 1169 |         if (error.error() == QSslError::CertificateBlacklisted) { | 
| 1170 |             foundBlack = true; | 
| 1171 |             break; | 
| 1172 |         } | 
| 1173 |     } | 
| 1174 |     QVERIFY(foundBlack); | 
| 1175 |     errors.clear(); | 
| 1176 |  | 
| 1177 |     // This one is expired and untrusted | 
| 1178 |     toVerify = QSslCertificate::fromPath(path: testDataDir + "more-certificates/cert-large-serial-number.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1179 |     errors = QSslCertificate::verify(certificateChain: toVerify); | 
| 1180 |     VERIFY_VERBOSE(errors.contains(QSslError(QSslError::SelfSignedCertificate, toVerify[0]))); | 
| 1181 |     VERIFY_VERBOSE(errors.contains(QSslError(QSslError::CertificateExpired, toVerify[0]))); | 
| 1182 |     errors.clear(); | 
| 1183 |     toVerify.clear(); | 
| 1184 |  | 
| 1185 |     // This one is signed by a valid cert, but the signer is not a valid CA | 
| 1186 |     toVerify << QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-intermediate-not-ca-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString).first(); | 
| 1187 |     toVerify << QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-ocsp-good-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString).first(); | 
| 1188 |     errors = QSslCertificate::verify(certificateChain: toVerify); | 
| 1189 |     VERIFY_VERBOSE(errors.contains(QSslError(QSslError::InvalidCaCertificate, toVerify[1]))); | 
| 1190 |     toVerify.clear(); | 
| 1191 |  | 
| 1192 |     // This one is signed by a valid cert, and the signer is a valid CA | 
| 1193 |     toVerify << QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-intermediate-is-ca-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString).first(); | 
| 1194 |     toVerify << QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-intermediate-ca-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString).first(); | 
| 1195 |     errors = QSslCertificate::verify(certificateChain: toVerify); | 
| 1196 |     VERIFY_VERBOSE(errors.count() == 0); | 
| 1197 |  | 
| 1198 |     // Recheck the above with hostname validation | 
| 1199 |     errors = QSslCertificate::verify(certificateChain: toVerify, hostName: QLatin1String("example.com" )); | 
| 1200 |     VERIFY_VERBOSE(errors.count() == 0); | 
| 1201 |  | 
| 1202 |     // Recheck the above with a bad hostname | 
| 1203 |     errors = QSslCertificate::verify(certificateChain: toVerify, hostName: QLatin1String("fail.example.com" )); | 
| 1204 |     VERIFY_VERBOSE(errors.contains(QSslError(QSslError::HostNameMismatch, toVerify[0]))); | 
| 1205 |     toVerify.clear(); | 
| 1206 |  | 
| 1207 | #undef VERIFY_VERBOSE | 
| 1208 | } | 
| 1209 |  | 
| 1210 | QString tst_QSslCertificate::toString(const QList<QSslError>& errors) | 
| 1211 | { | 
| 1212 |     QStringList errorStrings; | 
| 1213 |  | 
| 1214 |     foreach (const QSslError& error, errors) { | 
| 1215 |         errorStrings.append(t: QLatin1Char('"') + error.errorString() + QLatin1Char('"')); | 
| 1216 |     } | 
| 1217 |  | 
| 1218 |     return QLatin1String("[ " ) + errorStrings.join(sep: QLatin1String(", " )) + QLatin1String(" ]" ); | 
| 1219 | } | 
| 1220 |  | 
| 1221 | void tst_QSslCertificate::extensions() | 
| 1222 | { | 
| 1223 |     QList<QSslCertificate> certList = | 
| 1224 |         QSslCertificate::fromPath(path: testDataDir + "more-certificates/natwest-banking.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1225 |     QVERIFY(certList.count() > 0); | 
| 1226 |  | 
| 1227 |     QSslCertificate cert = certList[0]; | 
| 1228 |     QList<QSslCertificateExtension> extensions = cert.extensions(); | 
| 1229 |     QCOMPARE(extensions.count(), 9); | 
| 1230 |  | 
| 1231 |     int unknown_idx = -1; | 
| 1232 |     int authority_info_idx = -1; | 
| 1233 |     int basic_constraints_idx = -1; | 
| 1234 |     int subject_key_idx = -1; | 
| 1235 |     int auth_key_idx = -1; | 
| 1236 |  | 
| 1237 |     for (int i=0; i < extensions.length(); ++i) { | 
| 1238 |         QSslCertificateExtension ext = extensions[i]; | 
| 1239 |  | 
| 1240 |         //qDebug() << i << ":" << ext.name() << ext.oid(); | 
| 1241 |         if (ext.oid() == QStringLiteral("1.3.6.1.5.5.7.1.12" )) | 
| 1242 |             unknown_idx = i; | 
| 1243 |         if (ext.name() == QStringLiteral("authorityInfoAccess" )) | 
| 1244 |             authority_info_idx = i; | 
| 1245 |         if (ext.name() == QStringLiteral("basicConstraints" )) | 
| 1246 |             basic_constraints_idx = i; | 
| 1247 |         if (ext.name() == QStringLiteral("subjectKeyIdentifier" )) | 
| 1248 |             subject_key_idx = i; | 
| 1249 |         if (ext.name() == QStringLiteral("authorityKeyIdentifier" )) | 
| 1250 |             auth_key_idx = i; | 
| 1251 |     } | 
| 1252 |  | 
| 1253 |     QVERIFY(unknown_idx != -1); | 
| 1254 |     QVERIFY(authority_info_idx != -1); | 
| 1255 |     QVERIFY(basic_constraints_idx != -1); | 
| 1256 |     QVERIFY(subject_key_idx != -1); | 
| 1257 |     QVERIFY(auth_key_idx != -1); | 
| 1258 |  | 
| 1259 |     // Unknown | 
| 1260 |     QSslCertificateExtension unknown = extensions[unknown_idx]; | 
| 1261 |     QCOMPARE(unknown.oid(), QStringLiteral("1.3.6.1.5.5.7.1.12" )); | 
| 1262 |     QCOMPARE(unknown.name(), QStringLiteral("1.3.6.1.5.5.7.1.12" )); | 
| 1263 |     QVERIFY(!unknown.isCritical()); | 
| 1264 |     QVERIFY(!unknown.isSupported()); | 
| 1265 |  | 
| 1266 |     QByteArray unknownValue = QByteArray::fromHex( | 
| 1267 |                         hexEncoded: "3060A15EA05C305A305830561609696D6167652F6769663021301F300706052B0E03021A0414"  \ | 
| 1268 |                         "4B6BB92896060CBBD052389B29AC4B078B21051830261624687474703A2F2F6C6F676F2E7665"  \ | 
| 1269 |                         "72697369676E2E636F6D2F76736C6F676F312E676966" ); | 
| 1270 |     QCOMPARE(unknown.value().toByteArray(), unknownValue); | 
| 1271 |  | 
| 1272 |     // Authority Info Access | 
| 1273 |     QSslCertificateExtension aia = extensions[authority_info_idx]; | 
| 1274 |     QCOMPARE(aia.oid(), QStringLiteral("1.3.6.1.5.5.7.1.1" )); | 
| 1275 |     QCOMPARE(aia.name(), QStringLiteral("authorityInfoAccess" )); | 
| 1276 |     QVERIFY(!aia.isCritical()); | 
| 1277 |     QVERIFY(aia.isSupported()); | 
| 1278 |  | 
| 1279 |     QVariantMap aiaValue = aia.value().toMap(); | 
| 1280 |     QCOMPARE(aiaValue.keys(), QList<QString>() << QStringLiteral("OCSP" ) << QStringLiteral("caIssuers" )); | 
| 1281 |     QString ocsp = aiaValue[QStringLiteral("OCSP" )].toString(); | 
| 1282 |     QString caIssuers = aiaValue[QStringLiteral("caIssuers" )].toString(); | 
| 1283 |  | 
| 1284 |     QCOMPARE(ocsp, QStringLiteral("http://EVIntl-ocsp.verisign.com" )); | 
| 1285 |     QCOMPARE(caIssuers, QStringLiteral("http://EVIntl-aia.verisign.com/EVIntl2006.cer" )); | 
| 1286 |  | 
| 1287 |     // Basic constraints | 
| 1288 |     QSslCertificateExtension basic = extensions[basic_constraints_idx]; | 
| 1289 |     QCOMPARE(basic.oid(), QStringLiteral("2.5.29.19" )); | 
| 1290 |     QCOMPARE(basic.name(), QStringLiteral("basicConstraints" )); | 
| 1291 |     QVERIFY(!basic.isCritical()); | 
| 1292 |     QVERIFY(basic.isSupported()); | 
| 1293 |  | 
| 1294 |     QVariantMap basicValue = basic.value().toMap(); | 
| 1295 |     QCOMPARE(basicValue.keys(), QList<QString>() << QStringLiteral("ca" )); | 
| 1296 |     QVERIFY(!basicValue[QStringLiteral("ca" )].toBool()); | 
| 1297 |  | 
| 1298 |     // Subject key identifier | 
| 1299 |     QSslCertificateExtension subjectKey = extensions[subject_key_idx]; | 
| 1300 |     QCOMPARE(subjectKey.oid(), QStringLiteral("2.5.29.14" )); | 
| 1301 |     QCOMPARE(subjectKey.name(), QStringLiteral("subjectKeyIdentifier" )); | 
| 1302 |     QVERIFY(!subjectKey.isCritical()); | 
| 1303 |     QVERIFY(subjectKey.isSupported()); | 
| 1304 |     QCOMPARE(subjectKey.value().toString(), QStringLiteral("5F:90:23:CD:24:CA:52:C9:36:29:F0:7E:9D:B1:FE:08:E0:EE:69:F0" )); | 
| 1305 |  | 
| 1306 |     // Authority key identifier | 
| 1307 |     QSslCertificateExtension authKey = extensions[auth_key_idx]; | 
| 1308 |     QCOMPARE(authKey.oid(), QStringLiteral("2.5.29.35" )); | 
| 1309 |     QCOMPARE(authKey.name(), QStringLiteral("authorityKeyIdentifier" )); | 
| 1310 |     QVERIFY(!authKey.isCritical()); | 
| 1311 |     QVERIFY(authKey.isSupported()); | 
| 1312 |  | 
| 1313 |     QVariantMap authValue = authKey.value().toMap(); | 
| 1314 |     QCOMPARE(authValue.keys(), QList<QString>() << QStringLiteral("keyid" )); | 
| 1315 |     QVERIFY(authValue[QStringLiteral("keyid" )].toByteArray() == | 
| 1316 |             QByteArray("4e43c81d76ef37537a4ff2586f94f338e2d5bddf" )); | 
| 1317 | } | 
| 1318 |  | 
| 1319 | void tst_QSslCertificate::extensionsCritical() | 
| 1320 | { | 
| 1321 |     QList<QSslCertificate> certList = | 
| 1322 |         QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1323 |     QVERIFY(certList.count() > 0); | 
| 1324 |  | 
| 1325 |     QSslCertificate cert = certList[0]; | 
| 1326 |     QList<QSslCertificateExtension> extensions = cert.extensions(); | 
| 1327 |     QCOMPARE(extensions.count(), 9); | 
| 1328 |  | 
| 1329 |     int basic_constraints_idx = -1; | 
| 1330 |     int key_usage_idx = -1; | 
| 1331 |  | 
| 1332 |     for (int i=0; i < extensions.length(); ++i) { | 
| 1333 |         QSslCertificateExtension ext = extensions[i]; | 
| 1334 |  | 
| 1335 |         if (ext.name() == QStringLiteral("basicConstraints" )) | 
| 1336 |             basic_constraints_idx = i; | 
| 1337 |         if (ext.name() == QStringLiteral("keyUsage" )) | 
| 1338 |             key_usage_idx = i; | 
| 1339 |     } | 
| 1340 |  | 
| 1341 |     QVERIFY(basic_constraints_idx != -1); | 
| 1342 |     QVERIFY(key_usage_idx != -1); | 
| 1343 |  | 
| 1344 |     // Basic constraints | 
| 1345 |     QSslCertificateExtension basic = extensions[basic_constraints_idx]; | 
| 1346 |     QCOMPARE(basic.oid(), QStringLiteral("2.5.29.19" )); | 
| 1347 |     QCOMPARE(basic.name(), QStringLiteral("basicConstraints" )); | 
| 1348 |     QVERIFY(basic.isCritical()); | 
| 1349 |     QVERIFY(basic.isSupported()); | 
| 1350 |  | 
| 1351 |     QVariantMap basicValue = basic.value().toMap(); | 
| 1352 |     QCOMPARE(basicValue.keys(), QList<QString>() << QStringLiteral("ca" )); | 
| 1353 |     QVERIFY(!basicValue[QStringLiteral("ca" )].toBool()); | 
| 1354 |  | 
| 1355 |     // Key Usage | 
| 1356 |     QSslCertificateExtension keyUsage = extensions[key_usage_idx]; | 
| 1357 |     QCOMPARE(keyUsage.oid(), QStringLiteral("2.5.29.15" )); | 
| 1358 |     QCOMPARE(keyUsage.name(), QStringLiteral("keyUsage" )); | 
| 1359 |     QVERIFY(keyUsage.isCritical()); | 
| 1360 |     QVERIFY(!keyUsage.isSupported()); | 
| 1361 | } | 
| 1362 |  | 
| 1363 | class TestThread : public QThread | 
| 1364 | { | 
| 1365 | public: | 
| 1366 |     void run() | 
| 1367 |     { | 
| 1368 |         effectiveDate = cert.effectiveDate(); | 
| 1369 |         expiryDate = cert.expiryDate(); | 
| 1370 |         extensions = cert.extensions(); | 
| 1371 |         isBlacklisted = cert.isBlacklisted(); | 
| 1372 |         issuerInfo = cert.issuerInfo(info: QSslCertificate::CommonName); | 
| 1373 |         issuerInfoAttributes = cert.issuerInfoAttributes(); | 
| 1374 |         publicKey = cert.publicKey(); | 
| 1375 |         serialNumber = cert.serialNumber(); | 
| 1376 |         subjectInfo = cert.subjectInfo(info: QSslCertificate::CommonName); | 
| 1377 |         subjectInfoAttributes = cert.subjectInfoAttributes(); | 
| 1378 |         toDer = cert.toDer(); | 
| 1379 |         toPem = cert.toPem(); | 
| 1380 |         toText = cert.toText(); | 
| 1381 |         version = cert.version(); | 
| 1382 |     } | 
| 1383 |     QSslCertificate cert; | 
| 1384 |     QDateTime effectiveDate; | 
| 1385 |     QDateTime expiryDate; | 
| 1386 |     QList<QSslCertificateExtension> extensions; | 
| 1387 |     bool isBlacklisted; | 
| 1388 |     QStringList issuerInfo; | 
| 1389 |     QList<QByteArray> issuerInfoAttributes; | 
| 1390 |     QSslKey publicKey; | 
| 1391 |     QByteArray serialNumber; | 
| 1392 |     QStringList subjectInfo; | 
| 1393 |     QList<QByteArray> subjectInfoAttributes; | 
| 1394 |     QByteArray toDer; | 
| 1395 |     QByteArray toPem; | 
| 1396 |     QString toText; | 
| 1397 |     QByteArray version; | 
| 1398 | }; | 
| 1399 |  | 
| 1400 | void tst_QSslCertificate::threadSafeConstMethods() | 
| 1401 | { | 
| 1402 |     if (!QSslSocket::supportsSsl()) | 
| 1403 |         return; | 
| 1404 |  | 
| 1405 |     QByteArray encoded = readFile(absFilePath: testDataDir + "certificates/cert.pem" ); | 
| 1406 |     QSslCertificate certificate(encoded); | 
| 1407 |     QVERIFY(!certificate.isNull()); | 
| 1408 |  | 
| 1409 |     TestThread t1; | 
| 1410 |     t1.cert = certificate; //shallow copy | 
| 1411 |     TestThread t2; | 
| 1412 |     t2.cert = certificate; //shallow copy | 
| 1413 |     t1.start(); | 
| 1414 |     t2.start(); | 
| 1415 |     QVERIFY(t1.wait(5000)); | 
| 1416 |     QVERIFY(t2.wait(5000)); | 
| 1417 |     QCOMPARE(t1.cert, t2.cert); | 
| 1418 |     QCOMPARE(t1.effectiveDate, t2.effectiveDate); | 
| 1419 |     QCOMPARE(t1.expiryDate, t2.expiryDate); | 
| 1420 |     //QVERIFY(t1.extensions == t2.extensions); // no equality operator, so not tested | 
| 1421 |     QCOMPARE(t1.isBlacklisted, t2.isBlacklisted); | 
| 1422 |     QCOMPARE(t1.issuerInfo, t2.issuerInfo); | 
| 1423 |     QCOMPARE(t1.issuerInfoAttributes, t2.issuerInfoAttributes); | 
| 1424 |     QCOMPARE(t1.publicKey, t2.publicKey); | 
| 1425 |     QCOMPARE(t1.serialNumber, t2.serialNumber); | 
| 1426 |     QCOMPARE(t1.subjectInfo, t2.subjectInfo); | 
| 1427 |     QCOMPARE(t1.subjectInfoAttributes, t2.subjectInfoAttributes); | 
| 1428 |     QCOMPARE(t1.toDer, t2.toDer); | 
| 1429 |     QCOMPARE(t1.toPem, t2.toPem); | 
| 1430 |     QCOMPARE(t1.toText, t2.toText); | 
| 1431 |     QCOMPARE(t1.version, t2.version); | 
| 1432 |  | 
| 1433 | } | 
| 1434 |  | 
| 1435 | void tst_QSslCertificate::version_data() | 
| 1436 | { | 
| 1437 |     QTest::addColumn<QSslCertificate>(name: "certificate" ); | 
| 1438 |     QTest::addColumn<QByteArray>(name: "result" ); | 
| 1439 |  | 
| 1440 |     QTest::newRow(dataTag: "null certificate" ) << QSslCertificate() << QByteArray(); | 
| 1441 |  | 
| 1442 |     QList<QSslCertificate> certs; | 
| 1443 |     certs << QSslCertificate::fromPath(path: testDataDir + "verify-certs/test-ocsp-good-cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1444 |  | 
| 1445 |     QTest::newRow(dataTag: "v3 certificate" ) << certs.first() << QByteArrayLiteral("3" ); | 
| 1446 |  | 
| 1447 |     certs.clear(); | 
| 1448 |     certs << QSslCertificate::fromPath(path: testDataDir + "certificates/cert.pem" , format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1449 |     QTest::newRow(dataTag: "v1 certificate" ) << certs.first() << QByteArrayLiteral("1" ); | 
| 1450 | } | 
| 1451 |  | 
| 1452 | void tst_QSslCertificate::version() | 
| 1453 | { | 
| 1454 |     if (!QSslSocket::supportsSsl()) | 
| 1455 |         return; | 
| 1456 |  | 
| 1457 |     QFETCH(QSslCertificate, certificate); | 
| 1458 |     QFETCH(QByteArray, result); | 
| 1459 |     QCOMPARE(certificate.version(), result); | 
| 1460 | } | 
| 1461 |  | 
| 1462 | void tst_QSslCertificate::pkcs12() | 
| 1463 | { | 
| 1464 |     // See pkcs12/README for how to generate the PKCS12 files used here. | 
| 1465 |     if (!QSslSocket::supportsSsl()) { | 
| 1466 |         qWarning(msg: "SSL not supported, skipping test" ); | 
| 1467 |         return; | 
| 1468 |     } | 
| 1469 |  | 
| 1470 |     QFile f(testDataDir + QLatin1String("pkcs12/leaf.p12" )); | 
| 1471 |     bool ok = f.open(flags: QIODevice::ReadOnly); | 
| 1472 |     QVERIFY(ok); | 
| 1473 |  | 
| 1474 |     QSslKey key; | 
| 1475 |     QSslCertificate cert; | 
| 1476 |     QList<QSslCertificate> caCerts; | 
| 1477 |  | 
| 1478 | #ifdef QT_NO_OPENSSL | 
| 1479 |     QEXPECT_FAIL("" , "QTBUG-40884: WinRT API does not support pkcs12 imports" , Abort); | 
| 1480 | #endif | 
| 1481 |     ok = QSslCertificate::importPkcs12(device: &f, key: &key, cert: &cert, caCertificates: &caCerts); | 
| 1482 |     QVERIFY(ok); | 
| 1483 |     f.close(); | 
| 1484 |  | 
| 1485 |     QList<QSslCertificate> leafCert = QSslCertificate::fromPath(path: testDataDir + QLatin1String("pkcs12/leaf.crt" ), format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1486 |     QVERIFY(!leafCert.isEmpty()); | 
| 1487 |  | 
| 1488 |     QCOMPARE(cert, leafCert.first()); | 
| 1489 |  | 
| 1490 |     QFile f2(testDataDir + QLatin1String("pkcs12/leaf.key" )); | 
| 1491 |     ok = f2.open(flags: QIODevice::ReadOnly); | 
| 1492 |     QVERIFY(ok); | 
| 1493 |  | 
| 1494 |     QSslKey leafKey(&f2, QSsl::Rsa); | 
| 1495 |     f2.close(); | 
| 1496 |  | 
| 1497 |     QVERIFY(!leafKey.isNull()); | 
| 1498 |     QCOMPARE(key, leafKey); | 
| 1499 |  | 
| 1500 |     QList<QSslCertificate> caCert = QSslCertificate::fromPath(path: testDataDir + QLatin1String("pkcs12/inter.crt" ), format: QSsl::Pem, syntax: QSslCertificate::PatternSyntax::FixedString); | 
| 1501 |     QVERIFY(!caCert.isEmpty()); | 
| 1502 |  | 
| 1503 |     QVERIFY(!caCerts.isEmpty()); | 
| 1504 |     QCOMPARE(caCerts.first(), caCert.first()); | 
| 1505 |     QCOMPARE(caCerts, caCert); | 
| 1506 |  | 
| 1507 |     // QTBUG-62335 - Fail (found no private key) but don't crash: | 
| 1508 |     QFile nocert(testDataDir + QLatin1String("pkcs12/leaf-nokey.p12" )); | 
| 1509 |     ok = nocert.open(flags: QIODevice::ReadOnly); | 
| 1510 |     QVERIFY(ok); | 
| 1511 |     QTest::ignoreMessage(type: QtWarningMsg, message: "Unable to convert private key" ); | 
| 1512 |     ok = QSslCertificate::importPkcs12(device: &nocert, key: &key, cert: &cert, caCertificates: &caCerts); | 
| 1513 |     QVERIFY(!ok); | 
| 1514 |     nocert.close(); | 
| 1515 | } | 
| 1516 |  | 
| 1517 | #endif // QT_NO_SSL | 
| 1518 |  | 
| 1519 | QTEST_MAIN(tst_QSslCertificate) | 
| 1520 | #include "tst_qsslcertificate.moc" | 
| 1521 |  |