qca/unittest/cms/cms.cpp
Albert Astals Cid ecdd0538dd Fix CMSut::signverify_message_invalid failing "randomly"
Once in a blue moon it happens that signedResult1[signedResult1.size() -
2] is a 0, so setting it to 0 doesn't break the signature validation, so
   check if it's a 0 and if it is, set it to 1
2021-02-05 16:45:07 +00:00

523 lines
18 KiB
C++

/**
* Copyright (C) 2006 Brad Hards <bradh@frogmouth.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <QtCrypto>
#include <QtTest/QtTest>
#ifdef QT_STATICPLUGIN
#include "import_plugins.h"
#endif
#include <openssl/opensslv.h>
class CMSut : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void xcrypt_data();
void xcrypt();
void signverify_data();
void signverify();
void signverify_message_data();
void signverify_message();
void signverify_message_invalid_data();
void signverify_message_invalid();
private:
QCA::Initializer *m_init;
};
void CMSut::initTestCase()
{
m_init = new QCA::Initializer;
}
void CMSut::cleanupTestCase()
{
delete m_init;
}
void CMSut::xcrypt_data()
{
QTest::addColumn<QByteArray>("testText");
QTest::newRow("empty") << QByteArray("");
QTest::newRow("0") << QByteArray("0");
QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()");
}
void CMSut::xcrypt()
{
QStringList providersToTest;
providersToTest.append(QStringLiteral("qca-ossl"));
foreach (const QString provider, providersToTest) {
if (!QCA::isSupported("cert", provider))
QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
else if (!QCA::isSupported("cms", provider))
QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
else {
QCA::Certificate pubCert =
QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), nullptr, provider);
QCOMPARE(pubCert.isNull(), false);
QCA::SecureMessageKey secMsgKey;
QCA::CertificateChain chain;
chain += pubCert;
secMsgKey.setX509CertificateChain(chain);
QCA::CMS cms;
QCA::SecureMessage msg(&cms);
QCOMPARE(msg.canClearsign(), false);
QCOMPARE(msg.canSignAndEncrypt(), false);
QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
msg.setRecipient(secMsgKey);
QFETCH(QByteArray, testText);
msg.startEncrypt();
msg.update(testText);
msg.end();
msg.waitForFinished(-1);
QByteArray encryptedResult1 = msg.read();
QCOMPARE(encryptedResult1.isEmpty(), false);
msg.reset();
msg.setRecipient(secMsgKey);
msg.startEncrypt();
msg.update(testText);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.success());
QByteArray encryptedResult2 = msg.read();
QCOMPARE(encryptedResult2.isEmpty(), false);
QCA::ConvertResult res;
QCA::SecureArray passPhrase = "start";
QCA::PrivateKey privKey =
QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res);
QCOMPARE(res, QCA::ConvertGood);
secMsgKey.setX509PrivateKey(privKey);
QCA::SecureMessageKeyList privKeyList;
privKeyList += secMsgKey;
QCA::CMS cms2;
cms2.setPrivateKeys(privKeyList);
QCA::SecureMessage msg2(&cms2);
msg2.startDecrypt();
msg2.update(encryptedResult1);
msg2.end();
msg2.waitForFinished(-1);
QVERIFY(msg2.success());
QByteArray decryptedResult1 = msg2.read();
QCOMPARE(decryptedResult1, testText);
msg2.reset();
msg2.startDecrypt();
msg2.update(encryptedResult1);
msg2.end();
msg2.waitForFinished(-1);
QVERIFY(msg2.success());
QByteArray decryptedResult2 = msg2.read();
QCOMPARE(decryptedResult1, decryptedResult2);
QCOMPARE(msg2.canClearsign(), false);
QCOMPARE(msg2.canSignAndEncrypt(), false);
QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
}
}
}
void CMSut::signverify_data()
{
QTest::addColumn<QByteArray>("testText");
QTest::newRow("empty") << QByteArray("");
QTest::newRow("0") << QByteArray("0");
QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()");
}
// This one tests Detached format.
void CMSut::signverify()
{
QStringList providersToTest;
providersToTest.append(QStringLiteral("qca-ossl"));
foreach (const QString provider, providersToTest) {
if (!QCA::isSupported("cert", provider))
QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
else if (!QCA::isSupported("cms", provider))
QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
else {
QCA::ConvertResult res;
QCA::SecureArray passPhrase = "start";
QCA::PrivateKey privKey =
QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCA::Certificate pubCert =
QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCOMPARE(pubCert.isNull(), false);
QCA::CertificateChain chain;
chain += pubCert;
QCA::SecureMessageKey secMsgKey;
secMsgKey.setX509CertificateChain(chain);
secMsgKey.setX509PrivateKey(privKey);
QCA::SecureMessageKeyList privKeyList;
privKeyList += secMsgKey;
QCA::CMS cms2;
cms2.setPrivateKeys(privKeyList);
QCA::SecureMessage msg2(&cms2);
msg2.setSigners(privKeyList);
QCOMPARE(msg2.canClearsign(), false);
QCOMPARE(msg2.canSignAndEncrypt(), false);
QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
QFETCH(QByteArray, testText);
msg2.startSign(QCA::SecureMessage::Detached);
msg2.update(testText);
msg2.end();
msg2.waitForFinished(-1);
QVERIFY(msg2.success());
QByteArray signedResult1 = msg2.signature();
QCOMPARE(signedResult1.isEmpty(), false);
msg2.reset();
msg2.setSigners(privKeyList);
msg2.startSign(QCA::SecureMessage::Detached);
msg2.update(testText);
msg2.end();
msg2.waitForFinished(-1);
QVERIFY(msg2.success());
QByteArray signedResult2 = msg2.signature();
QCOMPARE(signedResult2.isEmpty(), false);
QCA::CMS cms;
QCA::Certificate caCert =
QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCA::CertificateCollection caCertCollection;
caCertCollection.addCertificate(caCert);
cms.setTrustedCertificates(caCertCollection);
QCA::SecureMessage msg(&cms);
QCOMPARE(msg.canClearsign(), false);
QCOMPARE(msg.canSignAndEncrypt(), false);
QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
msg.startVerify(signedResult1);
msg.update(testText);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
#if OPENSSL_VERSION_NUMBER < 0x1010109fL
QEXPECT_FAIL("empty", "We don't seem to be able to verify signature of a zero length message", Continue);
#endif
QVERIFY(msg.verifySuccess());
msg.reset();
msg.startVerify(signedResult2);
msg.update(testText);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
#if OPENSSL_VERSION_NUMBER < 0x1010109fL
QEXPECT_FAIL("empty", "We don't seem to be able to verify signature of a zero length message", Continue);
#endif
QVERIFY(msg.verifySuccess());
msg.reset();
// This tests junk on the end of the signature - should fail
msg.startVerify(signedResult2 + "junk");
msg.update(testText);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
#if OPENSSL_VERSION_NUMBER >= 0x1010109fL
QEXPECT_FAIL("empty", "On newer openssl verifaction of zero length message always succeeds", Continue);
#endif
QCOMPARE(msg.verifySuccess(), false);
msg.reset();
// This tests junk on the end of the message - should fail
msg.startVerify(signedResult2);
msg.update(testText + "junk");
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
QCOMPARE(msg.verifySuccess(), false);
}
}
}
void CMSut::signverify_message_data()
{
QTest::addColumn<QByteArray>("testText");
QTest::newRow("empty") << QByteArray("");
QTest::newRow("0") << QByteArray("0");
QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()");
}
// This one tests Message format
void CMSut::signverify_message()
{
QStringList providersToTest;
providersToTest.append(QStringLiteral("qca-ossl"));
foreach (const QString provider, providersToTest) {
if (!QCA::isSupported("cert", provider))
QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
else if (!QCA::isSupported("cms", provider))
QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
else {
QCA::ConvertResult res;
QCA::SecureArray passPhrase = "start";
QCA::PrivateKey privKey =
QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCA::Certificate pubCert =
QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCOMPARE(pubCert.isNull(), false);
QCA::CertificateChain chain;
chain += pubCert;
QCA::SecureMessageKey secMsgKey;
secMsgKey.setX509CertificateChain(chain);
secMsgKey.setX509PrivateKey(privKey);
QCA::SecureMessageKeyList privKeyList;
privKeyList += secMsgKey;
QCA::CMS cms2;
cms2.setPrivateKeys(privKeyList);
QCA::SecureMessage msg2(&cms2);
msg2.setSigners(privKeyList);
QCOMPARE(msg2.canClearsign(), false);
QCOMPARE(msg2.canSignAndEncrypt(), false);
QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
QFETCH(QByteArray, testText);
msg2.startSign(QCA::SecureMessage::Message);
msg2.update(testText);
msg2.end();
msg2.waitForFinished(-1);
QVERIFY(msg2.success());
QByteArray signedResult1 = msg2.read();
QCOMPARE(signedResult1.isEmpty(), false);
msg2.reset();
msg2.setSigners(privKeyList);
msg2.startSign(QCA::SecureMessage::Message);
msg2.update(testText);
msg2.end();
msg2.waitForFinished(-1);
QVERIFY(msg2.success());
QByteArray signedResult2 = msg2.read();
QCOMPARE(signedResult2.isEmpty(), false);
QCA::CMS cms;
QCA::Certificate caCert =
QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCA::CertificateCollection caCertCollection;
caCertCollection.addCertificate(caCert);
cms.setTrustedCertificates(caCertCollection);
QCA::SecureMessage msg(&cms);
QCOMPARE(msg.canClearsign(), false);
QCOMPARE(msg.canSignAndEncrypt(), false);
QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
msg.startVerify();
msg.update(signedResult1);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
QVERIFY(msg.verifySuccess());
msg.reset();
msg.startVerify();
msg.update(signedResult2);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
QVERIFY(msg.verifySuccess());
msg.reset();
msg.startVerify();
msg.update(signedResult2);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
QCOMPARE(msg.verifySuccess(), true);
}
}
}
void CMSut::signverify_message_invalid_data()
{
QTest::addColumn<QByteArray>("testText");
QTest::newRow("empty") << QByteArray("");
QTest::newRow("0") << QByteArray("0");
QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()");
}
// This one tests Message format
void CMSut::signverify_message_invalid()
{
QStringList providersToTest;
providersToTest.append(QStringLiteral("qca-ossl"));
foreach (const QString provider, providersToTest) {
if (!QCA::isSupported("cert", provider))
QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
else if (!QCA::isSupported("cms", provider))
QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
else {
QCA::ConvertResult res;
QCA::SecureArray passPhrase = "start";
QCA::PrivateKey privKey =
QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCA::Certificate pubCert =
QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCOMPARE(pubCert.isNull(), false);
QCA::CertificateChain chain;
chain += pubCert;
QCA::SecureMessageKey secMsgKey;
secMsgKey.setX509CertificateChain(chain);
secMsgKey.setX509PrivateKey(privKey);
QCA::SecureMessageKeyList privKeyList;
privKeyList += secMsgKey;
QCA::CMS cms2;
cms2.setPrivateKeys(privKeyList);
QCA::SecureMessage msg2(&cms2);
msg2.setSigners(privKeyList);
QCOMPARE(msg2.canClearsign(), false);
QCOMPARE(msg2.canSignAndEncrypt(), false);
QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
QFETCH(QByteArray, testText);
msg2.startSign(QCA::SecureMessage::Message);
msg2.update(testText);
msg2.end();
msg2.waitForFinished(-1);
QVERIFY(msg2.success());
QByteArray signedResult1 = msg2.read();
QCOMPARE(signedResult1.isEmpty(), false);
QCA::CMS cms;
QCA::Certificate caCert =
QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), &res, provider);
QCOMPARE(res, QCA::ConvertGood);
QCA::CertificateCollection caCertCollection;
caCertCollection.addCertificate(caCert);
cms.setTrustedCertificates(caCertCollection);
QCA::SecureMessage msg(&cms);
QCOMPARE(msg.canClearsign(), false);
QCOMPARE(msg.canSignAndEncrypt(), false);
QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
// This is just to break things
// signedResult1[30] = signedResult1[30] + 1;
if (signedResult1.at(signedResult1.size() - 2) != 0) {
signedResult1[signedResult1.size() - 2] = 0x00;
} else {
signedResult1[signedResult1.size() - 2] = 0x01;
}
msg.startVerify();
msg.update(signedResult1);
msg.end();
msg.waitForFinished(-1);
QVERIFY(msg.wasSigned());
QVERIFY(msg.success());
QCOMPARE(msg.verifySuccess(), false);
}
}
}
QTEST_MAIN(CMSut)
#include "cms.moc"