tests/auto/qsslcertificate/tst_qsslcertificate.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtTest/QtTest>
       
    44 #include <qsslcertificate.h>
       
    45 #include <qsslkey.h>
       
    46 #include <qsslsocket.h>
       
    47 
       
    48 #ifdef Q_OS_SYMBIAN
       
    49 // In Symbian OS test data is located in applications private dir
       
    50 // Current path (C:\private\<UID>) contains only ascii chars
       
    51 #define SRCDIR "./"
       
    52 #endif
       
    53 
       
    54 class tst_QSslCertificate : public QObject
       
    55 {
       
    56     Q_OBJECT
       
    57 
       
    58     struct CertInfo {
       
    59         QFileInfo fileInfo;
       
    60         QFileInfo fileInfo_digest_md5;
       
    61         QFileInfo fileInfo_digest_sha1;
       
    62         QSsl::EncodingFormat format;
       
    63         CertInfo(const QFileInfo &fileInfo, QSsl::EncodingFormat format)
       
    64             : fileInfo(fileInfo), format(format) {}
       
    65     };
       
    66 
       
    67     QList<CertInfo> certInfoList;
       
    68     QMap<QString, QString> subjAltNameMap;
       
    69     QMap<QString, QString> pubkeyMap;
       
    70     QMap<QString, QString> md5Map;
       
    71     QMap<QString, QString> sha1Map;
       
    72 
       
    73     void createTestRows();
       
    74 #ifndef QT_NO_OPENSSL
       
    75     void compareCertificates(const QSslCertificate & cert1, const QSslCertificate & cert2);
       
    76 #endif
       
    77 
       
    78     QString oldCurrentDir;
       
    79 public:
       
    80     tst_QSslCertificate();
       
    81     virtual ~tst_QSslCertificate();
       
    82 
       
    83 public slots:
       
    84     void initTestCase_data();
       
    85     void init();
       
    86     void cleanup();
       
    87 
       
    88 #ifndef QT_NO_OPENSSL
       
    89 private slots:
       
    90     void emptyConstructor();
       
    91     void constructor_data();
       
    92     void constructor();
       
    93     void constructingGarbage();
       
    94     void copyAndAssign_data();
       
    95     void copyAndAssign();
       
    96     void digest_data();
       
    97     void digest();
       
    98     void alternateSubjectNames_data();
       
    99     void alternateSubjectNames();
       
   100     void publicKey_data();
       
   101     void publicKey();
       
   102     void toPemOrDer_data();
       
   103     void toPemOrDer();
       
   104     void fromDevice();
       
   105     void fromPath_data();
       
   106     void fromPath();
       
   107     void certInfo();
       
   108     void task256066toPem();
       
   109     void nulInCN();
       
   110     void nulInSan();
       
   111 // ### add tests for certificate bundles (multiple certificates concatenated into a single
       
   112 //     structure); both PEM and DER formatted
       
   113 #endif
       
   114 };
       
   115 
       
   116 tst_QSslCertificate::tst_QSslCertificate()
       
   117 {
       
   118     QDir dir(SRCDIR + QLatin1String("/certificates"));
       
   119     QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable);
       
   120     QRegExp rxCert(QLatin1String("^.+\\.(pem|der)$"));
       
   121     QRegExp rxSan(QLatin1String("^(.+\\.(?:pem|der))\\.san$"));
       
   122     QRegExp rxPubKey(QLatin1String("^(.+\\.(?:pem|der))\\.pubkey$"));
       
   123     QRegExp rxDigest(QLatin1String("^(.+\\.(?:pem|der))\\.digest-(md5|sha1)$"));
       
   124     foreach (QFileInfo fileInfo, fileInfoList) {
       
   125         if (rxCert.indexIn(fileInfo.fileName()) >= 0)
       
   126             certInfoList <<
       
   127                 CertInfo(fileInfo,
       
   128                          rxCert.cap(1) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
       
   129         if (rxSan.indexIn(fileInfo.fileName()) >= 0)
       
   130             subjAltNameMap.insert(rxSan.cap(1), fileInfo.absoluteFilePath());
       
   131         if (rxPubKey.indexIn(fileInfo.fileName()) >= 0)
       
   132             pubkeyMap.insert(rxPubKey.cap(1), fileInfo.absoluteFilePath());
       
   133         if (rxDigest.indexIn(fileInfo.fileName()) >= 0) {
       
   134             if (rxDigest.cap(2) == QLatin1String("md5"))
       
   135                 md5Map.insert(rxDigest.cap(1), fileInfo.absoluteFilePath());
       
   136             else
       
   137                 sha1Map.insert(rxDigest.cap(1), fileInfo.absoluteFilePath());
       
   138         }
       
   139     }
       
   140 }
       
   141 
       
   142 tst_QSslCertificate::~tst_QSslCertificate()
       
   143 {
       
   144 }
       
   145 
       
   146 void tst_QSslCertificate::initTestCase_data()
       
   147 {
       
   148 }
       
   149 
       
   150 void tst_QSslCertificate::init()
       
   151 {
       
   152     QString srcdir(QLatin1String(SRCDIR));
       
   153     if (!srcdir.isEmpty()) {
       
   154         oldCurrentDir = QDir::current().absolutePath();
       
   155         QDir::setCurrent(srcdir);
       
   156     }
       
   157 }
       
   158 
       
   159 void tst_QSslCertificate::cleanup()
       
   160 {
       
   161     if (!oldCurrentDir.isEmpty()) {
       
   162         QDir::setCurrent(oldCurrentDir);
       
   163     }
       
   164 
       
   165 }
       
   166 
       
   167 static QByteArray readFile(const QString &absFilePath)
       
   168 {
       
   169     QFile file(absFilePath);
       
   170     if (!file.open(QIODevice::ReadOnly)) {
       
   171         QWARN("failed to open file");
       
   172         return QByteArray();
       
   173     }
       
   174     return file.readAll();
       
   175 }
       
   176 
       
   177 #ifndef QT_NO_OPENSSL
       
   178 
       
   179 void tst_QSslCertificate::emptyConstructor()
       
   180 {
       
   181     if (!QSslSocket::supportsSsl())
       
   182         return;
       
   183 
       
   184     QSslCertificate certificate;
       
   185     QVERIFY(certificate.isNull());
       
   186     //make sure none of the functions crash  (task 203035)
       
   187     QVERIFY(!certificate.isValid());
       
   188     QCOMPARE(certificate.version() , QByteArray());
       
   189     QCOMPARE(certificate.serialNumber(), QByteArray());
       
   190     QCOMPARE(certificate.digest(), QCryptographicHash::hash(QByteArray(), QCryptographicHash::Md5));
       
   191     QCOMPARE(certificate.issuerInfo(QSslCertificate::Organization), QString());
       
   192     QCOMPARE(certificate.subjectInfo(QSslCertificate::Organization), QString());
       
   193     QCOMPARE(certificate.alternateSubjectNames(),(QMultiMap<QSsl::AlternateNameEntryType, QString>()));
       
   194 #ifndef QT_NO_TEXTSTREAM
       
   195     QCOMPARE(certificate.effectiveDate(), QDateTime());
       
   196     QCOMPARE(certificate.expiryDate(), QDateTime());
       
   197 #endif
       
   198 }
       
   199 
       
   200 Q_DECLARE_METATYPE(QSsl::EncodingFormat);
       
   201 
       
   202 void tst_QSslCertificate::createTestRows()
       
   203 {
       
   204     QTest::addColumn<QString>("absFilePath");
       
   205     QTest::addColumn<QSsl::EncodingFormat>("format");
       
   206     foreach (CertInfo certInfo, certInfoList) {
       
   207         QTest::newRow(certInfo.fileInfo.fileName().toLatin1())
       
   208             << certInfo.fileInfo.absoluteFilePath() << certInfo.format;
       
   209     }
       
   210 }
       
   211 
       
   212 void tst_QSslCertificate::constructor_data()
       
   213 {
       
   214     createTestRows();
       
   215 }
       
   216 
       
   217 void tst_QSslCertificate::constructor()
       
   218 {
       
   219     if (!QSslSocket::supportsSsl())
       
   220         return;
       
   221 
       
   222     QFETCH(QString, absFilePath);
       
   223     QFETCH(QSsl::EncodingFormat, format);
       
   224 
       
   225     QByteArray encoded = readFile(absFilePath);
       
   226     QSslCertificate certificate(encoded, format);
       
   227     QVERIFY(!certificate.isNull());
       
   228 }
       
   229 
       
   230 void tst_QSslCertificate::constructingGarbage()
       
   231 {
       
   232     if (!QSslSocket::supportsSsl())
       
   233         return;
       
   234 
       
   235     QByteArray garbage("garbage");
       
   236     QSslCertificate certificate(garbage);
       
   237     QVERIFY(certificate.isNull());
       
   238 }
       
   239 
       
   240 void tst_QSslCertificate::copyAndAssign_data()
       
   241 {
       
   242     createTestRows();
       
   243 }
       
   244 
       
   245 void tst_QSslCertificate::compareCertificates(
       
   246     const QSslCertificate & cert1, const QSslCertificate & cert2)
       
   247 {
       
   248     QCOMPARE(cert1.isNull(), cert2.isNull());
       
   249     // Note: in theory, the next line could fail even if the certificates are identical!
       
   250     QCOMPARE(cert1.isValid(), cert2.isValid());
       
   251     QCOMPARE(cert1.version(), cert2.version());
       
   252     QCOMPARE(cert1.serialNumber(), cert2.serialNumber());
       
   253     QCOMPARE(cert1.digest(), cert2.digest());
       
   254     QCOMPARE(cert1.toPem(), cert2.toPem());
       
   255     QCOMPARE(cert1.toDer(), cert2.toDer());
       
   256     for (int info = QSslCertificate::Organization;
       
   257          info <= QSslCertificate::StateOrProvinceName; info++) {
       
   258         const QSslCertificate::SubjectInfo subjectInfo = (QSslCertificate::SubjectInfo)info;
       
   259         QCOMPARE(cert1.issuerInfo(subjectInfo), cert2.issuerInfo(subjectInfo));
       
   260         QCOMPARE(cert1.subjectInfo(subjectInfo), cert2.subjectInfo(subjectInfo));
       
   261     }
       
   262     QCOMPARE(cert1.alternateSubjectNames(), cert2.alternateSubjectNames());
       
   263     QCOMPARE(cert1.effectiveDate(), cert2.effectiveDate());
       
   264     QCOMPARE(cert1.expiryDate(), cert2.expiryDate());
       
   265     QCOMPARE(cert1.version(), cert2.version());
       
   266     QCOMPARE(cert1.serialNumber(), cert2.serialNumber());
       
   267     // ### add more functions here ...
       
   268 }
       
   269 
       
   270 void tst_QSslCertificate::copyAndAssign()
       
   271 {
       
   272     if (!QSslSocket::supportsSsl())
       
   273         return;
       
   274 
       
   275     QFETCH(QString, absFilePath);
       
   276     QFETCH(QSsl::EncodingFormat, format);
       
   277 
       
   278     QByteArray encoded = readFile(absFilePath);
       
   279     QSslCertificate certificate(encoded, format);
       
   280 
       
   281     QVERIFY(!certificate.isNull());
       
   282 
       
   283     QSslCertificate copied(certificate);
       
   284     compareCertificates(certificate, copied);
       
   285 
       
   286     QSslCertificate assigned = certificate;
       
   287     compareCertificates(certificate, assigned);
       
   288 }
       
   289 
       
   290 void tst_QSslCertificate::digest_data()
       
   291 {
       
   292     QTest::addColumn<QString>("absFilePath");
       
   293     QTest::addColumn<QSsl::EncodingFormat>("format");
       
   294     QTest::addColumn<QString>("absFilePath_digest_md5");
       
   295     QTest::addColumn<QString>("absFilePath_digest_sha1");
       
   296     foreach (CertInfo certInfo, certInfoList) {
       
   297         QString certName = certInfo.fileInfo.fileName();
       
   298         QTest::newRow(certName.toLatin1())
       
   299             << certInfo.fileInfo.absoluteFilePath()
       
   300             << certInfo.format
       
   301             << md5Map.value(certName)
       
   302             << sha1Map.value(certName);
       
   303     }
       
   304 }
       
   305 
       
   306 // Converts a digest of the form '{MD5|SHA1} Fingerprint=AB:B8:32...' to binary format.
       
   307 static QByteArray convertDigest(const QByteArray &input)
       
   308 {
       
   309     QByteArray result;
       
   310     QRegExp rx(QLatin1String("(?:=|:)([0-9A-Fa-f]{2})"));
       
   311     int pos = 0;
       
   312     while ((pos = rx.indexIn(input, pos)) != -1) {
       
   313         result.append(rx.cap(1).toLatin1());
       
   314         pos += rx.matchedLength();
       
   315     }
       
   316     return QByteArray::fromHex(result);
       
   317 }
       
   318 
       
   319 void tst_QSslCertificate::digest()
       
   320 {
       
   321     if (!QSslSocket::supportsSsl())
       
   322         return;
       
   323 
       
   324     QFETCH(QString, absFilePath);
       
   325     QFETCH(QSsl::EncodingFormat, format);
       
   326     QFETCH(QString, absFilePath_digest_md5);
       
   327     QFETCH(QString, absFilePath_digest_sha1);
       
   328 
       
   329     QByteArray encoded = readFile(absFilePath);
       
   330     QSslCertificate certificate(encoded, format);
       
   331     QVERIFY(!certificate.isNull());
       
   332 
       
   333     if (!absFilePath_digest_md5.isEmpty())
       
   334         QCOMPARE(convertDigest(readFile(absFilePath_digest_md5)),
       
   335                  certificate.digest(QCryptographicHash::Md5));
       
   336 
       
   337     if (!absFilePath_digest_sha1.isEmpty())
       
   338         QCOMPARE(convertDigest(readFile(absFilePath_digest_sha1)),
       
   339                  certificate.digest(QCryptographicHash::Sha1));
       
   340 }
       
   341 
       
   342 void tst_QSslCertificate::alternateSubjectNames_data()
       
   343 {
       
   344     QTest::addColumn<QString>("certFilePath");
       
   345     QTest::addColumn<QSsl::EncodingFormat>("format");
       
   346     QTest::addColumn<QString>("subjAltNameFilePath");
       
   347 
       
   348     foreach (CertInfo certInfo, certInfoList) {
       
   349         QString certName = certInfo.fileInfo.fileName();
       
   350         if (subjAltNameMap.contains(certName))
       
   351             QTest::newRow(certName.toLatin1())
       
   352                 << certInfo.fileInfo.absoluteFilePath()
       
   353                 << certInfo.format
       
   354                 << subjAltNameMap.value(certName);
       
   355     }
       
   356 }
       
   357 
       
   358 void tst_QSslCertificate::alternateSubjectNames()
       
   359 {
       
   360     if (!QSslSocket::supportsSsl())
       
   361         return;
       
   362 
       
   363     QFETCH(QString, certFilePath);
       
   364     QFETCH(QSsl::EncodingFormat, format);
       
   365     QFETCH(QString, subjAltNameFilePath);
       
   366 
       
   367     QByteArray encodedCert = readFile(certFilePath);
       
   368     QSslCertificate certificate(encodedCert, format);
       
   369     QVERIFY(!certificate.isNull());
       
   370 
       
   371     QByteArray fileContents = readFile(subjAltNameFilePath);
       
   372 
       
   373     const QMultiMap<QSsl::AlternateNameEntryType, QString> altSubjectNames =
       
   374         certificate.alternateSubjectNames();
       
   375 
       
   376     // verify that each entry in subjAltNames is present in fileContents
       
   377     QMapIterator<QSsl::AlternateNameEntryType, QString> it(altSubjectNames);
       
   378     while (it.hasNext()) {
       
   379         it.next();
       
   380         QString type;
       
   381         if (it.key() == QSsl::EmailEntry)
       
   382             type = QLatin1String("email");
       
   383         else if (it.key() == QSsl::DnsEntry)
       
   384             type = QLatin1String("DNS");
       
   385         else
       
   386             QFAIL("unsupported alternative name type");
       
   387         QString entry = QString("%1:%2").arg(type).arg(it.value());
       
   388         QVERIFY(fileContents.contains(entry.toAscii()));
       
   389     }
       
   390 
       
   391     // verify that each entry in fileContents is present in subjAltNames
       
   392     QRegExp rx(QLatin1String("(email|DNS):([^,\\r\\n]+)"));
       
   393     for (int pos = 0; (pos = rx.indexIn(fileContents, pos)) != -1; pos += rx.matchedLength()) {
       
   394         QSsl::AlternateNameEntryType key;
       
   395         if (rx.cap(1) == QLatin1String("email"))
       
   396             key = QSsl::EmailEntry;
       
   397         else if (rx.cap(1) == QLatin1String("DNS"))
       
   398             key = QSsl::DnsEntry;
       
   399         else
       
   400             QFAIL("unsupported alternative name type");
       
   401         QVERIFY(altSubjectNames.contains(key, rx.cap(2)));
       
   402     }
       
   403 }
       
   404 
       
   405 void tst_QSslCertificate::publicKey_data()
       
   406 {
       
   407     QTest::addColumn<QString>("certFilePath");
       
   408     QTest::addColumn<QSsl::EncodingFormat>("format");
       
   409     QTest::addColumn<QString>("pubkeyFilePath");
       
   410 
       
   411     foreach (CertInfo certInfo, certInfoList) {
       
   412         QString certName = certInfo.fileInfo.fileName();
       
   413         if (pubkeyMap.contains(certName))
       
   414             QTest::newRow(certName.toLatin1())
       
   415                 << certInfo.fileInfo.absoluteFilePath()
       
   416                 << certInfo.format
       
   417                 << pubkeyMap.value(certName);
       
   418     }
       
   419 }
       
   420 
       
   421 void tst_QSslCertificate::publicKey()
       
   422 {
       
   423     if (!QSslSocket::supportsSsl())
       
   424         return;
       
   425 
       
   426     QFETCH(QString, certFilePath);
       
   427     QFETCH(QSsl::EncodingFormat, format);
       
   428     QFETCH(QString, pubkeyFilePath);
       
   429 
       
   430     QByteArray encodedCert = readFile(certFilePath);
       
   431     QSslCertificate certificate(encodedCert, format);
       
   432     QVERIFY(!certificate.isNull());
       
   433 
       
   434     QByteArray encodedPubkey = readFile(pubkeyFilePath);
       
   435     QSslKey pubkey(encodedPubkey, QSsl::Rsa, format, QSsl::PublicKey); // ### support DSA as well!
       
   436     QVERIFY(!pubkey.isNull());
       
   437 
       
   438     QCOMPARE(certificate.publicKey(), pubkey);
       
   439 }
       
   440 
       
   441 void tst_QSslCertificate::toPemOrDer_data()
       
   442 {
       
   443     createTestRows();
       
   444 }
       
   445 
       
   446 static const char BeginCertString[] = "-----BEGIN CERTIFICATE-----";
       
   447 static const char EndCertString[] = "-----END CERTIFICATE-----";
       
   448 
       
   449 // Returns, in Pem-format, the first certificate found in a Pem-formatted block
       
   450 // (Note that such a block may contain e.g. a private key at the end).
       
   451 static QByteArray firstPemCertificateFromPem(const QByteArray &pem)
       
   452 {
       
   453     int startPos = pem.indexOf(BeginCertString);
       
   454     int endPos = pem.indexOf(EndCertString);
       
   455     if (startPos == -1 || endPos == -1)
       
   456         return QByteArray();
       
   457     return pem.mid(startPos, endPos + sizeof(EndCertString) - startPos);
       
   458 }
       
   459 
       
   460 void tst_QSslCertificate::toPemOrDer()
       
   461 {
       
   462     if (!QSslSocket::supportsSsl())
       
   463         return;
       
   464 
       
   465     QFETCH(QString, absFilePath);
       
   466     QFETCH(QSsl::EncodingFormat, format);
       
   467 
       
   468     QByteArray encoded = readFile(absFilePath);
       
   469     QSslCertificate certificate(encoded, format);
       
   470     QVERIFY(!certificate.isNull());
       
   471     if (format == QSsl::Pem) {
       
   472         encoded.replace('\r',"");
       
   473         QByteArray firstPem = firstPemCertificateFromPem(encoded);
       
   474         QCOMPARE(certificate.toPem(), firstPem);
       
   475     } else {
       
   476         // ### for now, we assume that DER-encoded certificates don't contain bundled stuff
       
   477         QCOMPARE(certificate.toDer(), encoded);
       
   478     }
       
   479 }
       
   480 
       
   481 void tst_QSslCertificate::fromDevice()
       
   482 {
       
   483     QTest::ignoreMessage(QtWarningMsg, "QSslCertificate::fromDevice: cannot read from a null device");
       
   484     QList<QSslCertificate> certs = QSslCertificate::fromDevice(0); // don't crash
       
   485     QVERIFY(certs.isEmpty());
       
   486 }
       
   487 
       
   488 void tst_QSslCertificate::fromPath_data()
       
   489 {
       
   490     QTest::addColumn<QString>("path");
       
   491     QTest::addColumn<int>("syntax");
       
   492     QTest::addColumn<bool>("pemencoding");
       
   493     QTest::addColumn<int>("numCerts");
       
   494 
       
   495     QTest::newRow("empty fixed pem") << QString() << int(QRegExp::FixedString) << true << 0;
       
   496     QTest::newRow("empty fixed der") << QString() << int(QRegExp::FixedString) << false << 0;
       
   497     QTest::newRow("empty regexp pem") << QString() << int(QRegExp::RegExp) << true << 0;
       
   498     QTest::newRow("empty regexp der") << QString() << int(QRegExp::RegExp) << false << 0;
       
   499     QTest::newRow("empty wildcard pem") << QString() << int(QRegExp::Wildcard) << true << 0;
       
   500     QTest::newRow("empty wildcard der") << QString() << int(QRegExp::Wildcard) << false << 0;
       
   501     QTest::newRow("\"certificates\" fixed pem") << QString("certificates") << int(QRegExp::FixedString) << true << 0;
       
   502     QTest::newRow("\"certificates\" fixed der") << QString("certificates") << int(QRegExp::FixedString) << false << 0;
       
   503     QTest::newRow("\"certificates\" regexp pem") << QString("certificates") << int(QRegExp::RegExp) << true << 0;
       
   504     QTest::newRow("\"certificates\" regexp der") << QString("certificates") << int(QRegExp::RegExp) << false << 0;
       
   505     QTest::newRow("\"certificates\" wildcard pem") << QString("certificates") << int(QRegExp::Wildcard) << true << 0;
       
   506     QTest::newRow("\"certificates\" wildcard der") << QString("certificates") << int(QRegExp::Wildcard) << false << 0;
       
   507     QTest::newRow("\"certificates/cert.pem\" fixed pem") << QString("certificates/cert.pem") << int(QRegExp::FixedString) << true << 1;
       
   508     QTest::newRow("\"certificates/cert.pem\" fixed der") << QString("certificates/cert.pem") << int(QRegExp::FixedString) << false << 0;
       
   509     QTest::newRow("\"certificates/cert.pem\" regexp pem") << QString("certificates/cert.pem") << int(QRegExp::RegExp) << true << 1;
       
   510     QTest::newRow("\"certificates/cert.pem\" regexp der") << QString("certificates/cert.pem") << int(QRegExp::RegExp) << false << 0;
       
   511     QTest::newRow("\"certificates/cert.pem\" wildcard pem") << QString("certificates/cert.pem") << int(QRegExp::Wildcard) << true << 1;
       
   512     QTest::newRow("\"certificates/cert.pem\" wildcard der") << QString("certificates/cert.pem") << int(QRegExp::Wildcard) << false << 0;
       
   513     QTest::newRow("\"certificates/*\" fixed pem") << QString("certificates/*") << int(QRegExp::FixedString) << true << 0;
       
   514     QTest::newRow("\"certificates/*\" fixed der") << QString("certificates/*") << int(QRegExp::FixedString) << false << 0;
       
   515     QTest::newRow("\"certificates/*\" regexp pem") << QString("certificates/*") << int(QRegExp::RegExp) << true << 0;
       
   516     QTest::newRow("\"certificates/*\" regexp der") << QString("certificates/*") << int(QRegExp::RegExp) << false << 0;
       
   517     QTest::newRow("\"certificates/*\" wildcard pem") << QString("certificates/*") << int(QRegExp::Wildcard) << true << 4;
       
   518     QTest::newRow("\"certificates/*\" wildcard der") << QString("certificates/*") << int(QRegExp::Wildcard) << false << 0;
       
   519     QTest::newRow("\"c*/c*.pem\" fixed pem") << QString("c*/c*.pem") << int(QRegExp::FixedString) << true << 0;
       
   520     QTest::newRow("\"c*/c*.pem\" fixed der") << QString("c*/c*.pem") << int(QRegExp::FixedString) << false << 0;
       
   521     QTest::newRow("\"c*/c*.pem\" regexp pem") << QString("c*/c*.pem") << int(QRegExp::RegExp) << true << 0;
       
   522     QTest::newRow("\"c*/c*.pem\" regexp der") << QString("c*/c*.pem") << int(QRegExp::RegExp) << false << 0;
       
   523     QTest::newRow("\"c*/c*.pem\" wildcard pem") << QString("c*/c*.pem") << int(QRegExp::Wildcard) << true << 4;
       
   524     QTest::newRow("\"c*/c*.pem\" wildcard der") << QString("c*/c*.pem") << int(QRegExp::Wildcard) << false << 0;
       
   525     QTest::newRow("\"d*/c*.pem\" fixed pem") << QString("d*/c*.pem") << int(QRegExp::FixedString) << true << 0;
       
   526     QTest::newRow("\"d*/c*.pem\" fixed der") << QString("d*/c*.pem") << int(QRegExp::FixedString) << false << 0;
       
   527     QTest::newRow("\"d*/c*.pem\" regexp pem") << QString("d*/c*.pem") << int(QRegExp::RegExp) << true << 0;
       
   528     QTest::newRow("\"d*/c*.pem\" regexp der") << QString("d*/c*.pem") << int(QRegExp::RegExp) << false << 0;
       
   529     QTest::newRow("\"d*/c*.pem\" wildcard pem") << QString("d*/c*.pem") << int(QRegExp::Wildcard) << true << 0;
       
   530     QTest::newRow("\"d*/c*.pem\" wildcard der") << QString("d*/c*.pem") << int(QRegExp::Wildcard) << false << 0;
       
   531     QTest::newRow("\"c.*/c.*.pem\" fixed pem") << QString("c.*/c.*.pem") << int(QRegExp::FixedString) << true << 0;
       
   532     QTest::newRow("\"c.*/c.*.pem\" fixed der") << QString("c.*/c.*.pem") << int(QRegExp::FixedString) << false << 0;
       
   533     QTest::newRow("\"c.*/c.*.pem\" regexp pem") << QString("c.*/c.*.pem") << int(QRegExp::RegExp) << true << 4;
       
   534     QTest::newRow("\"c.*/c.*.pem\" regexp der") << QString("c.*/c.*.pem") << int(QRegExp::RegExp) << false << 0;
       
   535     QTest::newRow("\"c.*/c.*.pem\" wildcard pem") << QString("c.*/c.*.pem") << int(QRegExp::Wildcard) << true << 0;
       
   536     QTest::newRow("\"c.*/c.*.pem\" wildcard der") << QString("c.*/c.*.pem") << int(QRegExp::Wildcard) << false << 0;
       
   537     QTest::newRow("\"d.*/c.*.pem\" fixed pem") << QString("d.*/c.*.pem") << int(QRegExp::FixedString) << true << 0;
       
   538     QTest::newRow("\"d.*/c.*.pem\" fixed der") << QString("d.*/c.*.pem") << int(QRegExp::FixedString) << false << 0;
       
   539     QTest::newRow("\"d.*/c.*.pem\" regexp pem") << QString("d.*/c.*.pem") << int(QRegExp::RegExp) << true << 0;
       
   540     QTest::newRow("\"d.*/c.*.pem\" regexp der") << QString("d.*/c.*.pem") << int(QRegExp::RegExp) << false << 0;
       
   541     QTest::newRow("\"d.*/c.*.pem\" wildcard pem") << QString("d.*/c.*.pem") << int(QRegExp::Wildcard) << true << 0;
       
   542     QTest::newRow("\"d.*/c.*.pem\" wildcard der") << QString("d.*/c.*.pem") << int(QRegExp::Wildcard) << false << 0;
       
   543 
       
   544     QTest::newRow("trailing-whitespace") << QString("more-certificates/trailing-whitespace.pem") << int(QRegExp::FixedString) << true << 1;
       
   545 }
       
   546 
       
   547 void tst_QSslCertificate::fromPath()
       
   548 {
       
   549     QFETCH(QString, path);
       
   550     QFETCH(int, syntax);
       
   551     QFETCH(bool, pemencoding);
       
   552     QFETCH(int, numCerts);
       
   553 
       
   554     QCOMPARE(QSslCertificate::fromPath(path,
       
   555                                        pemencoding ? QSsl::Pem : QSsl::Der,
       
   556                                        QRegExp::PatternSyntax(syntax)).size(),
       
   557              numCerts);
       
   558 }
       
   559 
       
   560 void tst_QSslCertificate::certInfo()
       
   561 {
       
   562 // MD5 Fingerprint=B6:CF:57:34:DA:A9:73:21:82:F7:CF:4D:3D:85:31:88
       
   563 // SHA1 Fingerprint=B6:D1:51:82:E0:29:CA:59:96:38:BD:B6:F9:40:05:91:6D:49:09:60
       
   564 // Certificate:
       
   565 //     Data:
       
   566 //         Version: 1 (0x0)
       
   567 //         Serial Number: 17 (0x11)
       
   568 //         Signature Algorithm: sha1WithRSAEncryption
       
   569 //         Issuer: C=AU, ST=Queensland, O=CryptSoft Pty Ltd, CN=Test CA (1024 bit)
       
   570 //         Validity
       
   571 //             Not Before: Apr 17 07:40:26 2007 GMT
       
   572 //             Not After : May 17 07:40:26 2007 GMT
       
   573 //         Subject: CN=name/with/slashes, C=NO
       
   574 //         Subject Public Key Info:
       
   575 //             Public Key Algorithm: rsaEncryption
       
   576 //             RSA Public Key: (1024 bit)
       
   577 //                 Modulus (1024 bit):
       
   578 //                     00:eb:9d:e9:03:ac:30:4f:a9:58:03:44:c7:18:26:
       
   579 //                     2f:48:93:d5:ac:a0:fb:e8:53:c4:7b:2a:01:89:e6:
       
   580 //                     fc:5a:0c:c5:f5:21:f8:d7:4a:92:02:67:db:f1:9f:
       
   581 //                     36:9a:62:9d:f3:ce:48:8e:ba:ed:5a:a8:9d:4f:bb:
       
   582 //                     24:16:43:4c:b5:79:08:f6:d9:22:8f:5f:15:0a:43:
       
   583 //                     25:03:7a:9d:a7:af:e3:26:b1:53:55:5e:60:57:c8:
       
   584 //                     ed:2f:1c:f3:36:0a:78:64:91:f9:17:a7:34:d7:8b:
       
   585 //                     bd:f1:fc:d1:8c:4f:a5:96:75:b2:7b:fc:21:f0:c7:
       
   586 //                     d9:5f:0c:57:18:b2:af:b9:4b
       
   587 //                 Exponent: 65537 (0x10001)
       
   588 //     Signature Algorithm: sha1WithRSAEncryption
       
   589 //         95:e6:94:e2:98:33:57:a2:98:fa:af:50:b9:76:a9:51:83:2c:
       
   590 //         0b:61:a2:36:d0:e6:90:6d:e4:f8:c4:c7:50:ef:17:94:4e:21:
       
   591 //         a8:fa:c8:33:aa:d1:7f:bc:ca:41:d6:7d:e7:44:76:c0:bf:45:
       
   592 //         4a:76:25:42:6d:53:76:fd:fc:74:29:1a:ea:2b:cc:06:ab:d1:
       
   593 //         b8:eb:7d:6b:11:f7:9b:41:bb:9f:31:cb:ed:4d:f3:68:26:ed:
       
   594 //         13:1d:f2:56:59:fe:6f:7c:98:b6:25:69:4e:ea:b4:dc:c2:eb:
       
   595 //         b7:bb:50:18:05:ba:ad:af:08:49:fe:98:63:55:ba:e7:fb:95:
       
   596 //         5d:91
       
   597     static const char pem[] =
       
   598         "-----BEGIN CERTIFICATE-----\n"
       
   599         "MIIB8zCCAVwCAREwDQYJKoZIhvcNAQEFBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n"
       
   600         "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n"
       
   601         "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDcwNDE3MDc0MDI2WhcNMDcwNTE3\n"
       
   602         "MDc0MDI2WjApMRowGAYDVQQDExFuYW1lL3dpdGgvc2xhc2hlczELMAkGA1UEBhMC\n"
       
   603         "Tk8wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOud6QOsME+pWANExxgmL0iT\n"
       
   604         "1ayg++hTxHsqAYnm/FoMxfUh+NdKkgJn2/GfNppinfPOSI667VqonU+7JBZDTLV5\n"
       
   605         "CPbZIo9fFQpDJQN6naev4yaxU1VeYFfI7S8c8zYKeGSR+RenNNeLvfH80YxPpZZ1\n"
       
   606         "snv8IfDH2V8MVxiyr7lLAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAleaU4pgzV6KY\n"
       
   607         "+q9QuXapUYMsC2GiNtDmkG3k+MTHUO8XlE4hqPrIM6rRf7zKQdZ950R2wL9FSnYl\n"
       
   608         "Qm1Tdv38dCka6ivMBqvRuOt9axH3m0G7nzHL7U3zaCbtEx3yVln+b3yYtiVpTuq0\n"
       
   609         "3MLrt7tQGAW6ra8ISf6YY1W65/uVXZE=\n"
       
   610         "-----END CERTIFICATE-----\n";
       
   611     static const char der[] =   // hex encoded
       
   612         "30:82:01:f3:30:82:01:5c:02:01:11:30:0d:06:09:2a"
       
   613         "86:48:86:f7:0d:01:01:05:05:00:30:5b:31:0b:30:09"
       
   614         "06:03:55:04:06:13:02:41:55:31:13:30:11:06:03:55"
       
   615         "04:08:13:0a:51:75:65:65:6e:73:6c:61:6e:64:31:1a"
       
   616         "30:18:06:03:55:04:0a:13:11:43:72:79:70:74:53:6f"
       
   617         "66:74:20:50:74:79:20:4c:74:64:31:1b:30:19:06:03"
       
   618         "55:04:03:13:12:54:65:73:74:20:43:41:20:28:31:30"
       
   619         "32:34:20:62:69:74:29:30:1e:17:0d:30:37:30:34:31"
       
   620         "37:30:37:34:30:32:36:5a:17:0d:30:37:30:35:31:37"
       
   621         "30:37:34:30:32:36:5a:30:29:31:1a:30:18:06:03:55"
       
   622         "04:03:13:11:6e:61:6d:65:2f:77:69:74:68:2f:73:6c"
       
   623         "61:73:68:65:73:31:0b:30:09:06:03:55:04:06:13:02"
       
   624         "4e:4f:30:81:9f:30:0d:06:09:2a:86:48:86:f7:0d:01"
       
   625         "01:01:05:00:03:81:8d:00:30:81:89:02:81:81:00:eb"
       
   626         "9d:e9:03:ac:30:4f:a9:58:03:44:c7:18:26:2f:48:93"
       
   627         "d5:ac:a0:fb:e8:53:c4:7b:2a:01:89:e6:fc:5a:0c:c5"
       
   628         "f5:21:f8:d7:4a:92:02:67:db:f1:9f:36:9a:62:9d:f3"
       
   629         "ce:48:8e:ba:ed:5a:a8:9d:4f:bb:24:16:43:4c:b5:79"
       
   630         "08:f6:d9:22:8f:5f:15:0a:43:25:03:7a:9d:a7:af:e3"
       
   631         "26:b1:53:55:5e:60:57:c8:ed:2f:1c:f3:36:0a:78:64"
       
   632         "91:f9:17:a7:34:d7:8b:bd:f1:fc:d1:8c:4f:a5:96:75"
       
   633         "b2:7b:fc:21:f0:c7:d9:5f:0c:57:18:b2:af:b9:4b:02"
       
   634         "03:01:00:01:30:0d:06:09:2a:86:48:86:f7:0d:01:01"
       
   635         "05:05:00:03:81:81:00:95:e6:94:e2:98:33:57:a2:98"
       
   636         "fa:af:50:b9:76:a9:51:83:2c:0b:61:a2:36:d0:e6:90"
       
   637         "6d:e4:f8:c4:c7:50:ef:17:94:4e:21:a8:fa:c8:33:aa"
       
   638         "d1:7f:bc:ca:41:d6:7d:e7:44:76:c0:bf:45:4a:76:25"
       
   639         "42:6d:53:76:fd:fc:74:29:1a:ea:2b:cc:06:ab:d1:b8"
       
   640         "eb:7d:6b:11:f7:9b:41:bb:9f:31:cb:ed:4d:f3:68:26"
       
   641         "ed:13:1d:f2:56:59:fe:6f:7c:98:b6:25:69:4e:ea:b4"
       
   642         "dc:c2:eb:b7:bb:50:18:05:ba:ad:af:08:49:fe:98:63"
       
   643         "55:ba:e7:fb:95:5d:91";
       
   644 
       
   645     QSslCertificate cert =  QSslCertificate::fromPath("certificates/cert.pem", QSsl::Pem,
       
   646                                                       QRegExp::FixedString).first();
       
   647     QVERIFY(!cert.isNull());
       
   648 
       
   649     QCOMPARE(cert.issuerInfo(QSslCertificate::Organization), QString("CryptSoft Pty Ltd"));
       
   650     QCOMPARE(cert.issuerInfo(QSslCertificate::CommonName), QString("Test CA (1024 bit)"));
       
   651     QCOMPARE(cert.issuerInfo(QSslCertificate::LocalityName), QString());
       
   652     QCOMPARE(cert.issuerInfo(QSslCertificate::OrganizationalUnitName), QString());
       
   653     QCOMPARE(cert.issuerInfo(QSslCertificate::CountryName), QString("AU"));
       
   654     QCOMPARE(cert.issuerInfo(QSslCertificate::StateOrProvinceName), QString("Queensland"));
       
   655 
       
   656     QCOMPARE(cert.issuerInfo("O"), QString("CryptSoft Pty Ltd"));
       
   657     QCOMPARE(cert.issuerInfo("CN"), QString("Test CA (1024 bit)"));
       
   658     QCOMPARE(cert.issuerInfo("L"), QString());
       
   659     QCOMPARE(cert.issuerInfo("OU"), QString());
       
   660     QCOMPARE(cert.issuerInfo("C"), QString("AU"));
       
   661     QCOMPARE(cert.issuerInfo("ST"), QString("Queensland"));
       
   662 
       
   663     QCOMPARE(cert.subjectInfo(QSslCertificate::Organization), QString());
       
   664     QCOMPARE(cert.subjectInfo(QSslCertificate::CommonName), QString("name/with/slashes"));
       
   665     QCOMPARE(cert.subjectInfo(QSslCertificate::LocalityName), QString());
       
   666     QCOMPARE(cert.subjectInfo(QSslCertificate::OrganizationalUnitName), QString());
       
   667     QCOMPARE(cert.subjectInfo(QSslCertificate::CountryName), QString("NO"));
       
   668     QCOMPARE(cert.subjectInfo(QSslCertificate::StateOrProvinceName), QString());
       
   669 
       
   670     QCOMPARE(cert.subjectInfo("O"), QString());
       
   671     QCOMPARE(cert.subjectInfo("CN"), QString("name/with/slashes"));
       
   672     QCOMPARE(cert.subjectInfo("L"), QString());
       
   673     QCOMPARE(cert.subjectInfo("OU"), QString());
       
   674     QCOMPARE(cert.subjectInfo("C"), QString("NO"));
       
   675     QCOMPARE(cert.subjectInfo("ST"), QString());
       
   676 
       
   677     QCOMPARE(cert.version(), QByteArray::number(1));
       
   678     QCOMPARE(cert.serialNumber(), QByteArray::number(17));
       
   679 
       
   680     QCOMPARE(cert.toPem().constData(), (const char*)pem);
       
   681     QCOMPARE(cert.toDer(), QByteArray::fromHex(der));
       
   682 
       
   683     QCOMPARE(cert.digest(QCryptographicHash::Md5),
       
   684              QByteArray::fromHex("B6:CF:57:34:DA:A9:73:21:82:F7:CF:4D:3D:85:31:88"));
       
   685     QCOMPARE(cert.digest(QCryptographicHash::Sha1),
       
   686              QByteArray::fromHex("B6:D1:51:82:E0:29:CA:59:96:38:BD:B6:F9:40:05:91:6D:49:09:60"));
       
   687 
       
   688     QCOMPARE(cert.effectiveDate().toUTC(), QDateTime(QDate(2007, 4, 17), QTime(7,40,26), Qt::UTC));
       
   689     QCOMPARE(cert.expiryDate().toUTC(), QDateTime(QDate(2007, 5, 17), QTime(7,40,26), Qt::UTC));
       
   690     QVERIFY(!cert.isValid());   // cert has expired
       
   691 
       
   692     QSslCertificate copy = cert;
       
   693     QVERIFY(cert == copy);
       
   694     QVERIFY(!(cert != copy));
       
   695 
       
   696     QCOMPARE(cert, QSslCertificate(pem, QSsl::Pem));
       
   697     QCOMPARE(cert, QSslCertificate(QByteArray::fromHex(der), QSsl::Der));
       
   698 }
       
   699 
       
   700 void tst_QSslCertificate::task256066toPem()
       
   701 {
       
   702     // a certificate whose PEM encoding's length is a multiple of 64
       
   703     const char *mycert = "-----BEGIN CERTIFICATE-----\n" \
       
   704                          "MIIEGjCCAwKgAwIBAgIESikYSjANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJF\n" \
       
   705                          "RTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEPMA0GA1UECxMG\n" \
       
   706                          "RVNURUlEMRcwFQYDVQQDEw5FU1RFSUQtU0sgMjAwNzAeFw0wOTA2MDUxMzA2MTha\n" \
       
   707                          "Fw0xNDA2MDkyMTAwMDBaMIGRMQswCQYDVQQGEwJFRTEPMA0GA1UEChMGRVNURUlE\n" \
       
   708                          "MRcwFQYDVQQLEw5hdXRoZW50aWNhdGlvbjEhMB8GA1UEAxMYSEVJQkVSRyxTVkVO\n" \
       
   709                          "LDM3NzA5MjcwMjg1MRAwDgYDVQQEEwdIRUlCRVJHMQ0wCwYDVQQqEwRTVkVOMRQw\n" \
       
   710                          "EgYDVQQFEwszNzcwOTI3MDI4NTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" \
       
   711                          "k2Euwhm34vu1jOFp02J5fQRx9LW2C7x78CbJ7yInoAKn7QR8UdxTU7mJk90Opejo\n" \
       
   712                          "71RUi2/aYl4jCr9gr99v2YoLufMRwAuqdmwmwqH1WAHRUtIcD0oPdKyelmmn9ig0\n" \
       
   713                          "RV+yJLNT3dnyrwPw+uuzDe3DeKepGKE4lxexliCaAx0CAyCMW6OCATEwggEtMA4G\n" \
       
   714                          "A1UdDwEB/wQEAwIEsDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwPAYD\n" \
       
   715                          "VR0fBDUwMzAxoC+gLYYraHR0cDovL3d3dy5zay5lZS9jcmxzL2VzdGVpZC9lc3Rl\n" \
       
   716                          "aWQyMDA3LmNybDAgBgNVHREEGTAXgRVzdmVuLmhlaWJlcmdAZWVzdGkuZWUwUQYD\n" \
       
   717                          "VR0gBEowSDBGBgsrBgEEAc4fAQEBATA3MBIGCCsGAQUFBwICMAYaBG5vbmUwIQYI\n" \
       
   718                          "KwYBBQUHAgEWFWh0dHA6Ly93d3cuc2suZWUvY3BzLzAfBgNVHSMEGDAWgBRIBt6+\n" \
       
   719                          "jIdXlYB4Y/qcIysroDoYdTAdBgNVHQ4EFgQUKCjpDf+LcvL6AH0QOiW6rMTtB/0w\n" \
       
   720                          "CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEABRyRuUm9zt8V27WuNeXtCDmU\n" \
       
   721                          "MGzA6g4QXNAd2nxFzT3k+kNzzQTOcgRdmjiEPuK49On+GWnBr/5MSBNhbCJVPWr/\n" \
       
   722                          "yym1UYTBisaqhRt/N/kwZqd0bHeLJk+ZxSePXRyqkp9H8KPWqz7H+O/FxRS4ffxo\n" \
       
   723                          "Q9Clem+e0bcjNlL5xXiRGycBeZq8cKj+0+A/UuattznQlvHdlCEsSeu1fPOORqFV\n" \
       
   724                          "fZur4HC31lQD7xVvETLiL83CtOQC78+29XPD6Zlrrc5OF2yibSVParY19b8Zh6yu\n" \
       
   725                          "p1dNvN8pBgXGrsyxRonwHooV2ghGNmGILkpdvlQfnxeCUg4erfHjDdSY9vmT7w==\n" \
       
   726                          "-----END CERTIFICATE-----\n";
       
   727 
       
   728     QByteArray pem1(mycert);
       
   729     QSslCertificate cert1(pem1);
       
   730     QVERIFY(!cert1.isNull());
       
   731     QByteArray pem2(cert1.toPem());
       
   732     QSslCertificate cert2(pem2);
       
   733     QVERIFY(!cert2.isNull());
       
   734     QCOMPARE(pem1, pem2);
       
   735 }
       
   736 
       
   737 void tst_QSslCertificate::nulInCN()
       
   738 {
       
   739     QList<QSslCertificate> certList =
       
   740         QSslCertificate::fromPath(SRCDIR "more-certificates/badguy-nul-cn.crt");
       
   741     QCOMPARE(certList.size(), 1);
       
   742 
       
   743     const QSslCertificate &cert = certList.at(0);
       
   744     QVERIFY(!cert.isNull());
       
   745 
       
   746     QString cn = cert.subjectInfo(QSslCertificate::CommonName);
       
   747     QVERIFY(cn != "www.bank.com");
       
   748 
       
   749     static const char realCN[] = "www.bank.com\\x00.badguy.com";
       
   750     QCOMPARE(cn, QString::fromLatin1(realCN, sizeof realCN - 1));
       
   751 }
       
   752 
       
   753 void tst_QSslCertificate::nulInSan()
       
   754 {
       
   755     QList<QSslCertificate> certList =
       
   756         QSslCertificate::fromPath(SRCDIR "more-certificates/badguy-nul-san.crt");
       
   757     QCOMPARE(certList.size(), 1);
       
   758 
       
   759     const QSslCertificate &cert = certList.at(0);
       
   760     QVERIFY(!cert.isNull());
       
   761 
       
   762     QMultiMap<QSsl::AlternateNameEntryType, QString> san = cert.alternateSubjectNames();
       
   763     QVERIFY(!san.isEmpty());
       
   764 
       
   765     QString dnssan = san.value(QSsl::DnsEntry);
       
   766     QVERIFY(!dnssan.isEmpty());
       
   767     QVERIFY(dnssan != "www.bank.com");
       
   768 
       
   769     static const char realSAN[] = "www.bank.com\0www.badguy.com";
       
   770     QCOMPARE(dnssan, QString::fromLatin1(realSAN, sizeof realSAN - 1));
       
   771 }
       
   772 
       
   773 #endif // QT_NO_OPENSSL
       
   774 
       
   775 QTEST_MAIN(tst_QSslCertificate)
       
   776 #include "tst_qsslcertificate.moc"