From e4f80d6461cc26e2dd1494ab2bf548e3382a5153 Mon Sep 17 00:00:00 2001 From: Sune Vuorela Date: Wed, 15 Mar 2023 12:22:00 +0100 Subject: Simple signature tests Document some of the fields we can extract. --- qt5/tests/CMakeLists.txt | 1 + qt5/tests/check_signature_basics.cpp | 133 +++++++++++++++++++++++++++++++++++ qt6/tests/CMakeLists.txt | 1 + qt6/tests/check_signature_basics.cpp | 133 +++++++++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+) create mode 100644 qt5/tests/check_signature_basics.cpp create mode 100644 qt6/tests/check_signature_basics.cpp diff --git a/qt5/tests/CMakeLists.txt b/qt5/tests/CMakeLists.txt index baadd428..3e3be3e0 100644 --- a/qt5/tests/CMakeLists.txt +++ b/qt5/tests/CMakeLists.txt @@ -70,6 +70,7 @@ qt5_add_qtest(check_qt5_object check_object.cpp) qt5_add_qtest(check_qt5_stroke_opacity check_stroke_opacity.cpp) qt5_add_qtest(check_qt5_utf_conversion check_utf_conversion.cpp) qt5_add_qtest(check_qt5_outline check_outline.cpp) +qt5_add_qtest(check_qt5_signature_basics check_signature_basics.cpp) if (NOT WIN32) qt5_add_qtest(check_qt5_pagelabelinfo check_pagelabelinfo.cpp) qt5_add_qtest(check_qt5_strings check_strings.cpp) diff --git a/qt5/tests/check_signature_basics.cpp b/qt5/tests/check_signature_basics.cpp new file mode 100644 index 00000000..7cdb1c37 --- /dev/null +++ b/qt5/tests/check_signature_basics.cpp @@ -0,0 +1,133 @@ +//======================================================================== +// +// check_signature_basics.cpp +// +// This file is licensed under the GPLv2 or later +// +// Copyright 2023 g10 Code GmbH, Author: Sune Stolborg Vuorela +//======================================================================== + +// Simple tests of reading signatures +// +// Note that this does not check the actual validity because +// that will have an expiry date, and adding time bombs to unit tests is +// probably not a good idea. +#include +#include "PDFDoc.h" +#include "GlobalParams.h" +#include "SignatureInfo.h" +#include "config.h" + +class TestSignatureBasics : public QObject +{ + Q_OBJECT +public: + explicit TestSignatureBasics(QObject *parent = nullptr) : QObject(parent) { } + +private: + std::unique_ptr doc; +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testSignatureCount(); + void testSignatureSizes(); + void testSignerInfo(); // names and stuff + void testSignedRanges(); +}; + +void TestSignatureBasics::initTestCase() +{ + globalParams = std::make_unique(); + doc = std::make_unique(std::make_unique(TESTDATADIR "/unittestcases/pdf-signature-sample-2sigs.pdf")); + QVERIFY(doc); + QVERIFY(doc->isOk()); +} +void TestSignatureBasics::cleanupTestCase() +{ + globalParams.reset(); +} + +void TestSignatureBasics::testSignatureCount() +{ + QVERIFY(doc); + auto signatureFields = doc->getSignatureFields(); + QCOMPARE(signatureFields.size(), 4); + // count active signatures + QVERIFY(signatureFields[0]->getSignature()); + QVERIFY(signatureFields[1]->getSignature()); + QVERIFY(!signatureFields[2]->getSignature()); + QVERIFY(!signatureFields[3]->getSignature()); +} + +void TestSignatureBasics::testSignatureSizes() +{ + auto signatureFields = doc->getSignatureFields(); + // Note for later. Unpadding a signature on a command line with openssl can + // be done just by rewriting after using e.g. pdfsig -dump to extract them + // openssl pkcs7 -inform der -in pdf-signature-sample-2sigs.pdf.sig0 -outform der -out pdf-signature-sample-2sigs.pdf.sig0.unpadded + QCOMPARE(signatureFields[0]->getSignature()->getLength(), 10230); // This is technically wrong, because the signatures in this document has been padded. The correct size is 2340 + QCOMPARE(signatureFields[1]->getSignature()->getLength(), 10196); // This is technically wrong, because the signatures in this document has been padded. The correct size is 2340 +} + +void TestSignatureBasics::testSignerInfo() +{ + auto signatureFields = doc->getSignatureFields(); + QCOMPARE(signatureFields[0]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature0_B_" }); + QCOMPARE(signatureFields[0]->getSignatureType(), ETSI_CAdES_detached); + auto siginfo0 = signatureFields[0]->validateSignature(false, false, -1 /* now */, false, false); +#ifdef ENABLE_NSS3 + QCOMPARE(siginfo0->getSignerName(), std::string { "Koch, Werner" }); + QCOMPARE(siginfo0->getHashAlgorithm(), HashAlgorithm::Sha256); +#else + QCOMPARE(siginfo0->getSignerName(), std::string {}); + QCOMPARE(siginfo0->getHashAlgorithm(), HashAlgorithm::Unknown); +#endif + QCOMPARE(siginfo0->getSigningTime(), time_t(1677570911)); + + QCOMPARE(signatureFields[1]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature1_B_" }); + QCOMPARE(signatureFields[1]->getSignatureType(), ETSI_CAdES_detached); + auto siginfo1 = signatureFields[1]->validateSignature(false, false, -1 /* now */, false, false); +#ifdef ENABLE_NSS3 + QCOMPARE(siginfo1->getSignerName(), std::string { "Koch, Werner" }); + QCOMPARE(siginfo1->getHashAlgorithm(), HashAlgorithm::Sha256); +#else + QCOMPARE(siginfo1->getSignerName(), std::string {}); + QCOMPARE(siginfo1->getHashAlgorithm(), HashAlgorithm::Unknown); +#endif + QCOMPARE(siginfo1->getSigningTime(), time_t(1677840601)); + + QCOMPARE(signatureFields[2]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature2_B_" }); + QCOMPARE(signatureFields[2]->getSignatureType(), unsigned_signature_field); + QCOMPARE(signatureFields[3]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature3_B_" }); + QCOMPARE(signatureFields[3]->getSignatureType(), unsigned_signature_field); +} + +void TestSignatureBasics::testSignedRanges() +{ + auto signatureFields = doc->getSignatureFields(); + + Goffset size0; + auto sig0 = signatureFields[0]->getCheckedSignature(&size0); + QVERIFY(sig0); + auto ranges0 = signatureFields[0]->getSignedRangeBounds(); + QCOMPARE(ranges0.size(), 4); + QCOMPARE(ranges0[0], 0); + QCOMPARE(ranges0[1], 24890); + QCOMPARE(ranges0[2], 45352); + QCOMPARE(ranges0[3], 58529); + QVERIFY(ranges0[3] != size0); // signature does not cover all of it + + Goffset size1; + auto sig1 = signatureFields[1]->getCheckedSignature(&size1); + QVERIFY(sig1); + auto ranges1 = signatureFields[1]->getSignedRangeBounds(); + QCOMPARE(ranges1.size(), 4); + QCOMPARE(ranges1[0], 0); + QCOMPARE(ranges1[1], 59257); + QCOMPARE(ranges1[2], 79651); + QCOMPARE(ranges1[3], 92773); + QCOMPARE(ranges1[3], size1); // signature does cover all of it +} + +QTEST_GUILESS_MAIN(TestSignatureBasics) +#include "check_signature_basics.moc" diff --git a/qt6/tests/CMakeLists.txt b/qt6/tests/CMakeLists.txt index 90ec00cc..36da5b9f 100644 --- a/qt6/tests/CMakeLists.txt +++ b/qt6/tests/CMakeLists.txt @@ -62,6 +62,7 @@ qt6_add_qtest(check_qt6_object check_object.cpp) qt6_add_qtest(check_qt6_stroke_opacity check_stroke_opacity.cpp) qt6_add_qtest(check_qt6_utf_conversion check_utf_conversion.cpp) qt6_add_qtest(check_qt6_outline check_outline.cpp) +qt6_add_qtest(check_qt6_signature_basics check_signature_basics.cpp) if (NOT WIN32) qt6_add_qtest(check_qt6_pagelabelinfo check_pagelabelinfo.cpp) qt6_add_qtest(check_qt6_strings check_strings.cpp) diff --git a/qt6/tests/check_signature_basics.cpp b/qt6/tests/check_signature_basics.cpp new file mode 100644 index 00000000..7cdb1c37 --- /dev/null +++ b/qt6/tests/check_signature_basics.cpp @@ -0,0 +1,133 @@ +//======================================================================== +// +// check_signature_basics.cpp +// +// This file is licensed under the GPLv2 or later +// +// Copyright 2023 g10 Code GmbH, Author: Sune Stolborg Vuorela +//======================================================================== + +// Simple tests of reading signatures +// +// Note that this does not check the actual validity because +// that will have an expiry date, and adding time bombs to unit tests is +// probably not a good idea. +#include +#include "PDFDoc.h" +#include "GlobalParams.h" +#include "SignatureInfo.h" +#include "config.h" + +class TestSignatureBasics : public QObject +{ + Q_OBJECT +public: + explicit TestSignatureBasics(QObject *parent = nullptr) : QObject(parent) { } + +private: + std::unique_ptr doc; +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testSignatureCount(); + void testSignatureSizes(); + void testSignerInfo(); // names and stuff + void testSignedRanges(); +}; + +void TestSignatureBasics::initTestCase() +{ + globalParams = std::make_unique(); + doc = std::make_unique(std::make_unique(TESTDATADIR "/unittestcases/pdf-signature-sample-2sigs.pdf")); + QVERIFY(doc); + QVERIFY(doc->isOk()); +} +void TestSignatureBasics::cleanupTestCase() +{ + globalParams.reset(); +} + +void TestSignatureBasics::testSignatureCount() +{ + QVERIFY(doc); + auto signatureFields = doc->getSignatureFields(); + QCOMPARE(signatureFields.size(), 4); + // count active signatures + QVERIFY(signatureFields[0]->getSignature()); + QVERIFY(signatureFields[1]->getSignature()); + QVERIFY(!signatureFields[2]->getSignature()); + QVERIFY(!signatureFields[3]->getSignature()); +} + +void TestSignatureBasics::testSignatureSizes() +{ + auto signatureFields = doc->getSignatureFields(); + // Note for later. Unpadding a signature on a command line with openssl can + // be done just by rewriting after using e.g. pdfsig -dump to extract them + // openssl pkcs7 -inform der -in pdf-signature-sample-2sigs.pdf.sig0 -outform der -out pdf-signature-sample-2sigs.pdf.sig0.unpadded + QCOMPARE(signatureFields[0]->getSignature()->getLength(), 10230); // This is technically wrong, because the signatures in this document has been padded. The correct size is 2340 + QCOMPARE(signatureFields[1]->getSignature()->getLength(), 10196); // This is technically wrong, because the signatures in this document has been padded. The correct size is 2340 +} + +void TestSignatureBasics::testSignerInfo() +{ + auto signatureFields = doc->getSignatureFields(); + QCOMPARE(signatureFields[0]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature0_B_" }); + QCOMPARE(signatureFields[0]->getSignatureType(), ETSI_CAdES_detached); + auto siginfo0 = signatureFields[0]->validateSignature(false, false, -1 /* now */, false, false); +#ifdef ENABLE_NSS3 + QCOMPARE(siginfo0->getSignerName(), std::string { "Koch, Werner" }); + QCOMPARE(siginfo0->getHashAlgorithm(), HashAlgorithm::Sha256); +#else + QCOMPARE(siginfo0->getSignerName(), std::string {}); + QCOMPARE(siginfo0->getHashAlgorithm(), HashAlgorithm::Unknown); +#endif + QCOMPARE(siginfo0->getSigningTime(), time_t(1677570911)); + + QCOMPARE(signatureFields[1]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature1_B_" }); + QCOMPARE(signatureFields[1]->getSignatureType(), ETSI_CAdES_detached); + auto siginfo1 = signatureFields[1]->validateSignature(false, false, -1 /* now */, false, false); +#ifdef ENABLE_NSS3 + QCOMPARE(siginfo1->getSignerName(), std::string { "Koch, Werner" }); + QCOMPARE(siginfo1->getHashAlgorithm(), HashAlgorithm::Sha256); +#else + QCOMPARE(siginfo1->getSignerName(), std::string {}); + QCOMPARE(siginfo1->getHashAlgorithm(), HashAlgorithm::Unknown); +#endif + QCOMPARE(siginfo1->getSigningTime(), time_t(1677840601)); + + QCOMPARE(signatureFields[2]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature2_B_" }); + QCOMPARE(signatureFields[2]->getSignatureType(), unsigned_signature_field); + QCOMPARE(signatureFields[3]->getCreateWidget()->getField()->getFullyQualifiedName()->toStr(), std::string { "P2.AnA_Signature3_B_" }); + QCOMPARE(signatureFields[3]->getSignatureType(), unsigned_signature_field); +} + +void TestSignatureBasics::testSignedRanges() +{ + auto signatureFields = doc->getSignatureFields(); + + Goffset size0; + auto sig0 = signatureFields[0]->getCheckedSignature(&size0); + QVERIFY(sig0); + auto ranges0 = signatureFields[0]->getSignedRangeBounds(); + QCOMPARE(ranges0.size(), 4); + QCOMPARE(ranges0[0], 0); + QCOMPARE(ranges0[1], 24890); + QCOMPARE(ranges0[2], 45352); + QCOMPARE(ranges0[3], 58529); + QVERIFY(ranges0[3] != size0); // signature does not cover all of it + + Goffset size1; + auto sig1 = signatureFields[1]->getCheckedSignature(&size1); + QVERIFY(sig1); + auto ranges1 = signatureFields[1]->getSignedRangeBounds(); + QCOMPARE(ranges1.size(), 4); + QCOMPARE(ranges1[0], 0); + QCOMPARE(ranges1[1], 59257); + QCOMPARE(ranges1[2], 79651); + QCOMPARE(ranges1[3], 92773); + QCOMPARE(ranges1[3], size1); // signature does cover all of it +} + +QTEST_GUILESS_MAIN(TestSignatureBasics) +#include "check_signature_basics.moc" -- cgit v1.2.3