aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
aheinecke@404:  * Software engineering by Intevation GmbH
aheinecke@404:  *
aheinecke@404:  * This file is Free Software under the GNU GPL (v>=2)
aheinecke@404:  * and comes with ABSOLUTELY NO WARRANTY!
aheinecke@404:  * See LICENSE.txt for details.
aheinecke@404:  */
aheinecke@7: #include "certlistparsertest.h"
aheinecke@7: #include "certificatelist.h"
aheinecke@87: #include "certificate.h"
aheinecke@240: #include "common.h"
aheinecke@7: 
aheinecke@7: #include <QDebug>
aheinecke@7: 
aheinecke@31: void CertListTest::testValidList()
aheinecke@31: {
andre@359: #ifdef RELEASE_BUILD
andre@359:     const char *fname = "list-valid-signed-release.txt";
andre@359: #else
aheinecke@31:     const char *fname = "list-valid-signed.txt";
andre@359: #endif
aheinecke@88: 
aheinecke@88:     QDir dataDir = QDir(SOURCE_DIR"/data/");
aheinecke@88:     QString fileName = dataDir.absoluteFilePath(fname);
aheinecke@88:     QFile validList(fileName);
aheinecke@87:     validList.open(QIODevice::ReadOnly);
aheinecke@87:     QString validData = QString::fromLatin1(validList.readAll());
aheinecke@87:     QStringList instLines;
aheinecke@87:     QStringList remoLines;
aheinecke@87: 
aheinecke@31:     CertificateList *certList = testWithFile(fname);
aheinecke@87:     QCOMPARE(certList->getStatus(), Valid);
aheinecke@87:     QVERIFY(certList->isValid());
aheinecke@87: 
aheinecke@87:     QVERIFY(certList->rawData() == validData.toLatin1());
aheinecke@87: 
aheinecke@249:     const QList<Certificate> cList = certList->getCertificates();
aheinecke@87: 
aheinecke@87:     foreach (QString act, validData.split("\r\n")) {
aheinecke@87:         if (act.startsWith("I:")) {
aheinecke@87:             instLines << act;
aheinecke@87:             continue;
aheinecke@87:         }
aheinecke@87:         if (act.startsWith("R:")) {
aheinecke@87:             remoLines << act;
aheinecke@87:             continue;
aheinecke@87:         }
aheinecke@87:     }
aheinecke@87: 
aheinecke@249:     int instCnt = 0,
aheinecke@249:         remoCnt = 0;
aheinecke@249:     foreach (const Certificate& cert, cList) {
aheinecke@87:         QVERIFY(cert.isValid());
aheinecke@249:         if (cert.isInstallCert()) {
aheinecke@249:             QVERIFY(instLines.contains(cert.base64Line()));
aheinecke@249:             instCnt++;
aheinecke@249:         } else {
aheinecke@249:             QVERIFY(remoLines.contains(cert.base64Line()));
aheinecke@249:             remoCnt++;
aheinecke@249:         }
aheinecke@87:     }
aheinecke@87: 
aheinecke@87:     /* Be variable if test data changes later */
aheinecke@249:     QVERIFY(instCnt >= 1);
aheinecke@249:     QVERIFY(remoCnt >= 1);
aheinecke@249:     QVERIFY(instLines.size() == instCnt);
aheinecke@249:     QVERIFY(remoLines.size() == remoCnt);
aheinecke@87: 
andre@204:     /* Check that a default certificate is invalid */
aheinecke@95:     Certificate cert;
aheinecke@95:     QVERIFY(!cert.isValid());
aheinecke@95: 
andre@203:     certList->readList(fileName.toLocal8Bit().data());
andre@203: 
aheinecke@249:     const QList<Certificate> cList2 = certList->getCertificates();
aheinecke@249:     QVERIFY(instLines.size() + remoLines.size() == cList2.size());
aheinecke@87: 
aheinecke@31:     delete certList;
aheinecke@31: }
aheinecke@7: 
aheinecke@7: void CertListTest::testInvalidSig()
aheinecke@7: {
aheinecke@42:     const char *fnames[] = {"list-invalid-signed.txt",
aheinecke@42:         "list-valid-other-signature.txt",
aheinecke@42:         "list-valid-sha1-signature.txt",
aheinecke@42:         NULL};
aheinecke@42:     for (int i=0; fnames[i] != NULL; i++) {
aheinecke@42:         CertificateList *certList = testWithFile(fnames[i]);
aheinecke@42:         QCOMPARE (certList->getStatus(), InvalidSignature);
aheinecke@42:         delete certList;
aheinecke@42:     }
aheinecke@7: }
aheinecke@7: 
aheinecke@7: void verifyInvalidFile(const char *fName) {
aheinecke@7:     CertificateList *certList = new CertificateList(fName);
aheinecke@7:     QVERIFY (certList->getStatus() != Valid);
aheinecke@7:     delete certList;
aheinecke@7: }
aheinecke@7: 
aheinecke@7: void CertListTest::testInvalidFileNames()
aheinecke@7: {
aheinecke@7:     verifyInvalidFile("/dev/random");
aheinecke@7:     verifyInvalidFile("/tmp/");
aheinecke@7:     verifyInvalidFile(NULL);
aheinecke@7:     verifyInvalidFile("ä");
aheinecke@7:     verifyInvalidFile("💩 ");
aheinecke@7: }
aheinecke@7: 
aheinecke@42: void CertListTest::testEmptyFile()
aheinecke@42: {
aheinecke@42:     const char *fname = "empty_file";
aheinecke@42:     CertificateList *certList = testWithFile(fname);
aheinecke@95:     QCOMPARE (certList->getStatus(), SeekFailed);
aheinecke@42:     delete certList;
aheinecke@42: }
aheinecke@42: 
aheinecke@7: void CertListTest::testGarbage()
aheinecke@7: {
andre@202:     const char *fname = "list-with-null.txt";
andre@202:     QString fname2 = getRandomDataFile(200);
andre@202:     CertificateList *certList = testWithFile(fname);
andre@202:     QCOMPARE (certList->getStatus(), InvalidFormat);
andre@202:     delete certList;
andre@202:     certList = testWithFile(fname2.toLocal8Bit().constData());
andre@202:     QVERIFY(QFile::remove(fname2));
andre@202:     QCOMPARE (certList->getStatus(), InvalidFormat);
andre@202:     delete certList;
andre@202: }
andre@202: 
aheinecke@7: void CertListTest::testTooLarge()
aheinecke@7: {
andre@202:     QString fname = getRandomDataFile(MAX_LINE_LENGTH * MAX_LINES + 1);
andre@202:     CertificateList *certList = testWithFile(fname.toLocal8Bit().constData());
andre@202:     QVERIFY(QFile::remove(fname));
andre@202:     QCOMPARE(certList->getStatus(), TooLarge);
andre@202:     QVERIFY(!certList->isValid());
aheinecke@7:     delete certList;
aheinecke@7: }
aheinecke@7: 
aheinecke@7: void CertListTest::benchmarkValid()
aheinecke@7: {
aheinecke@7:     const char *fname = "list-valid-signed.txt";
aheinecke@7: 
aheinecke@88:     QBENCHMARK{
aheinecke@7:         CertificateList *certList = testWithFile(fname);
aheinecke@7:         delete certList;
aheinecke@7:     }
aheinecke@7: }
aheinecke@7: 
aheinecke@7: CertificateList* CertListTest::testWithFile(const char *filename)
aheinecke@7: {
aheinecke@7:     QDir dataDir = QDir(SOURCE_DIR"/data/");
aheinecke@7:     QString fileName = dataDir.absoluteFilePath(filename);
aheinecke@7:     return new CertificateList(fileName.toLocal8Bit().data());
aheinecke@7: }
aheinecke@7: 
andre@351: void CertListTest::testCertificateFromFile()
andre@351: {
andre@351:     QList<Certificate> result;
andre@351: 
andre@351:     /* Real certificates in the wild */
andre@351:     result = Certificate::fromFileName(":/Intevation-Root-CA-2010.crt");
andre@351:     QVERIFY(result.size() == 1);
andre@351:     QVERIFY(result[0].isValid());
andre@351:     result = Certificate::fromFileName(":/Intevation-Root-CA-2010.der");
andre@351:     QVERIFY(result.size() == 1);
andre@351:     QVERIFY(result[0].isValid());
andre@351: 
andre@351:     /* We can handle ECC keys */
andre@351:     result = Certificate::fromFileName(":/valid_ssl_bp.pem");
andre@351:     QVERIFY(result.size() == 1);
andre@351:     QVERIFY(result[0].isValid());
andre@351: 
andre@351:     /* Basic stuff */
andre@351:     result = Certificate::fromFileName(":/valid_ssl_rsa.pem");
andre@351:     QVERIFY(result.size() == 1);
andre@351:     QVERIFY(result[0].isValid());
andre@351: 
andre@351:     /* Multiple certs */
andre@351:     result = Certificate::fromFileName(":/import_test.pem");
andre@351:     QVERIFY(result.size() == 15);
andre@351: 
andre@351:     QString lastCertB64;
andre@351:     foreach (const Certificate& cert, result) {
andre@351:         QVERIFY(cert.isValid());
andre@351:         /* Just to verify that it's not all the same */
andre@351:         QVERIFY(cert.base64Line() != lastCertB64);
andre@351:         lastCertB64 = cert.base64Line();
andre@351:     }
andre@351: 
andre@351:     /* Some robustness */
andre@351:     QString fname = getRandomDataFile(MAX_LINE_LENGTH * MAX_LINES - 100);
andre@351:     result = Certificate::fromFileName(fname);
andre@351:     QVERIFY(QFile::remove(fname));
andre@351:     QVERIFY(result.isEmpty());
andre@351: }
andre@351: 
aheinecke@7: int main( int argc, char **argv )
aheinecke@7: {
aheinecke@7:   CertListTest tc;
aheinecke@7:   return QTest::qExec( &tc, argc, argv );
aheinecke@7: }
aheinecke@7: 
aheinecke@7: