xmlsecurity/inc/pdfio/pdfdocument.hxx | 10 + xmlsecurity/qa/unit/pdfsigning/data/2good.pdf |binary xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx | 113 ++++++++++++++--- xmlsecurity/source/helper/documentsignaturemanager.cxx | 7 - xmlsecurity/source/helper/pdfsignaturehelper.cxx | 3 xmlsecurity/source/pdfio/pdfdocument.cxx | 54 ++++++-- xmlsecurity/source/pdfio/pdfverify.cxx | 3 7 files changed, 155 insertions(+), 35 deletions(-)
New commits: commit b6f98b71155d3c7af70bfc623cfaa7da0fbb905f Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Wed Oct 26 17:55:02 2016 +0200 xmlsecurity PDF verify: support SHA-256 And various other minor fixes. Change-Id: Ifcccebf48aac8ad526406f2d7a402a840d3c91cd diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx index f42350a..8ef7afd 100644 --- a/xmlsecurity/inc/pdfio/pdfdocument.hxx +++ b/xmlsecurity/inc/pdfio/pdfdocument.hxx @@ -75,6 +75,8 @@ public: static size_t FindStartXRef(SvStream& rStream); void ReadXRef(SvStream& rStream); static void SkipWhitespace(SvStream& rStream); + /// Instead of all whitespace, just skip CR and NL characters. + static void SkipLineBreaks(SvStream& rStream); size_t GetObjectOffset(size_t nIndex) const; const std::vector< std::unique_ptr<PDFElement> >& GetElements(); std::vector<PDFObjectElement*> GetPages(); diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx index a1ac63c..df7a809 100644 --- a/xmlsecurity/source/pdfio/pdfdocument.cxx +++ b/xmlsecurity/source/pdfio/pdfdocument.cxx @@ -18,6 +18,7 @@ #include <comphelper/processfactory.hxx> #include <comphelper/scopeguard.hxx> #include <comphelper/string.hxx> +#include <filter/msfilter/mscodec.hxx> #include <rtl/strbuf.hxx> #include <rtl/string.hxx> #include <sal/log.hxx> @@ -784,7 +785,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, bool bPartial) return false; } - PDFDocument::SkipWhitespace(rStream); + PDFDocument::SkipLineBreaks(rStream); m_aElements.push_back(std::unique_ptr<PDFElement>(new PDFStreamElement(nLength))); if (!m_aElements.back()->Read(rStream)) return false; @@ -822,7 +823,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, bool bPartial) } else { - SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Tokenize: unexpected '" << aKeyword << "' keyword"); + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Tokenize: unexpected '" << aKeyword << "' keyword at byte position " << rStream.Tell()); return false; } } @@ -830,7 +831,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, bool bPartial) { if (!isspace(ch)) { - SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Tokenize: unexpected character: " << ch); + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Tokenize: unexpected character: " << ch << " at byte position " << rStream.Tell()); return false; } } @@ -1034,6 +1035,24 @@ void PDFDocument::SkipWhitespace(SvStream& rStream) } } +void PDFDocument::SkipLineBreaks(SvStream& rStream) +{ + char ch = 0; + + while (true) + { + rStream.ReadChar(ch); + if (rStream.IsEof()) + break; + + if (ch != '\n' && ch != '\r') + { + rStream.SeekRel(-1); + return; + } + } +} + size_t PDFDocument::GetObjectOffset(size_t nIndex) const { auto it = m_aXRef.find(nIndex); @@ -1388,7 +1407,10 @@ bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignat switch (SECOID_FindOIDTag(&aAlgorithm)) { case SEC_OID_SHA1: - nMaxResultLen = 20; + nMaxResultLen = msfilter::SHA1_HASH_LENGTH; + break; + case SEC_OID_SHA256: + nMaxResultLen = msfilter::SHA256_HASH_LENGTH; break; default: SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ValidateSignature: unrecognized algorithm"); @@ -1519,14 +1541,14 @@ bool PDFNumberElement::Read(SvStream& rStream) m_nOffset = rStream.Tell(); char ch; rStream.ReadChar(ch); - if (!isdigit(ch) && ch != '-') + if (!isdigit(ch) && ch != '-' && ch != '.') { rStream.SeekRel(-1); return false; } while (!rStream.IsEof()) { - if (!isdigit(ch) && ch != '-') + if (!isdigit(ch) && ch != '-' && ch != '.') { rStream.SeekRel(-1); m_nLength = rStream.Tell() - m_nOffset; @@ -1599,25 +1621,28 @@ const OString& PDFHexStringElement::GetValue() const bool PDFLiteralStringElement::Read(SvStream& rStream) { - char ch; + char nPrevCh = 0; + char ch = 0; rStream.ReadChar(ch); if (ch != '(') { SAL_INFO("xmlsecurity.pdfio", "PDFHexStringElement::Read: expected '(' as first character"); return false; } + nPrevCh = ch; rStream.ReadChar(ch); OStringBuffer aBuf; while (!rStream.IsEof()) { - if (ch == ')') + if (ch == ')' && nPrevCh != '\\') { m_aValue = aBuf.makeStringAndClear(); SAL_INFO("xmlsecurity.pdfio", "PDFLiteralStringElement::Read: m_aValue is '" << m_aValue << "'"); return true; } aBuf.append(ch); + nPrevCh = ch; rStream.ReadChar(ch); } commit fc56d31c094f1e01adc5eca69b414e984c7e4baf Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Wed Oct 26 17:54:26 2016 +0200 xmlsecurity PDF verify: fix handling of non-imported certs Previously we only managed to verify a signature in case the certificate was already imported in the local NSS db. Don't depend on that by (temporarily) importing certificates from the PDF signature. Also adjust a test file that failed previously (the test DB has only an "Alice" cert imported, intentionally sign the file as "Bob" as well). Change-Id: Id8440acc31915f5a1718ea48129b950bb67e7486 diff --git a/xmlsecurity/qa/unit/pdfsigning/data/2good.pdf b/xmlsecurity/qa/unit/pdfsigning/data/2good.pdf index af668fc..10528c5 100644 Binary files a/xmlsecurity/qa/unit/pdfsigning/data/2good.pdf and b/xmlsecurity/qa/unit/pdfsigning/data/2good.pdf differ diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index 4442ac5..1f9ef83 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -214,6 +214,9 @@ void PDFSigningTest::testPDFRemoveAll() aManager.mxSignatureStream = xStream; aManager.read(/*bUseTempStream=*/false); std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations; + // This was 1 when NSS_CMSSignerInfo_GetSigningCertificate() failed, which + // means that we only used the locally imported certificates for + // verification, not the ones provided in the PDF signature data. CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations.size()); // Request removal of the first signature, should imply removal of the diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx index 20bbbbf..a1ac63c 100644 --- a/xmlsecurity/source/pdfio/pdfdocument.cxx +++ b/xmlsecurity/source/pdfio/pdfdocument.cxx @@ -1334,6 +1334,13 @@ bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignat return false; } + // Import certificates from the signed data temporarily, so it'll be + // possible to verify the signature, even if we didn't have the certificate + // perviously. + std::vector<CERTCertificate*> aDocumentCertificates; + for (size_t i = 0; pCMSSignedData->rawCerts[i]; ++i) + aDocumentCertificates.push_back(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), pCMSSignedData->rawCerts[i], nullptr, 0, 0)); + NSSCMSSignerInfo* pCMSSignerInfo = NSS_CMSSignedData_GetSignerInfo(pCMSSignedData, 0); if (!pCMSSignerInfo) { @@ -1456,6 +1463,8 @@ bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignat PORT_Free(pActualResultBuffer); HASH_Destroy(pHASHContext); NSS_CMSSignerInfo_Destroy(pCMSSignerInfo); + for (auto pDocumentCertificate : aDocumentCertificates) + CERT_DestroyCertificate(pDocumentCertificate); return true; #else commit 23ca39a7c2cd5b33ac6361282432c6f34c458366 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Wed Oct 26 17:53:04 2016 +0200 xmlsecurity PDF sign: fix removing non-last signatures PDF signatures are always chained, so when removing a signature not only the item at a given position should be removed on the UI, but the whole position-last range. Change-Id: I76b14308885267cdac994fa957218a8b7df6b3cf diff --git a/xmlsecurity/qa/unit/pdfsigning/data/2good.pdf b/xmlsecurity/qa/unit/pdfsigning/data/2good.pdf new file mode 100644 index 0000000..af668fc Binary files /dev/null and b/xmlsecurity/qa/unit/pdfsigning/data/2good.pdf differ diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index a2980db..4442ac5 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -12,7 +12,10 @@ #include <comphelper/processfactory.hxx> #include <osl/file.hxx> #include <test/bootstrapfixture.hxx> +#include <unotools/streamwrap.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <documentsignaturemanager.hxx> #include <pdfio/pdfdocument.hxx> using namespace com::sun::star; @@ -42,13 +45,16 @@ public: void testPDFAdd(); /// Test signing a previously unsigned file twice. void testPDFAdd2(); - /// Test remove a signature from a previously signed file. + /// Test removing a signature from a previously signed file. void testPDFRemove(); + /// Test removing all signatures from a previously multi-signed file. + void testPDFRemoveAll(); CPPUNIT_TEST_SUITE(PDFSigningTest); CPPUNIT_TEST(testPDFAdd); CPPUNIT_TEST(testPDFAdd2); CPPUNIT_TEST(testPDFRemove); + CPPUNIT_TEST(testPDFRemoveAll); CPPUNIT_TEST_SUITE_END(); }; @@ -187,6 +193,38 @@ void PDFSigningTest::testPDFRemove() } #endif } + +void PDFSigningTest::testPDFRemoveAll() +{ +#ifndef _WIN32 + // Make sure that good2.pdf has 2 valid signatures. Unlike in + // testPDFRemove(), here intentionally test DocumentSignatureManager and + // PDFSignatureHelper code as well. + uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext); + uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString()); + + // Copy the test document to a temporary file, as it'll be modified. + OUString aTargetDir = m_directories.getURLFromWorkdir("/CppunitTest/xmlsecurity_signing.test.user/"); + OUString aOutURL = aTargetDir + "remove-all.pdf"; + CPPUNIT_ASSERT_EQUAL(osl::File::RC::E_None, osl::File::copy(m_directories.getURLFromSrc(DATA_DIRECTORY) + "2good.pdf", aOutURL)); + // Load the test document as a storage and read its two signatures. + DocumentSignatureManager aManager(mxComponentContext, SignatureModeDocumentContent); + SvStream* pStream = utl::UcbStreamHelper::CreateStream(aOutURL, StreamMode::READ | StreamMode::WRITE); + uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream)); + aManager.mxSignatureStream = xStream; + aManager.read(/*bUseTempStream=*/false); + std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations; + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations.size()); + + // Request removal of the first signature, should imply removal of the + // second chained signature as well. + aManager.remove(0); + // This was 2, Manager didn't write anything to disk when removal succeeded + // (instead of doing that when removal failed). + // Then this was 1, when the chained signature wasn't removed. + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), rInformations.size()); +#endif +} CPPUNIT_TEST_SUITE_REGISTRATION(PDFSigningTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx index 0a5568f..dee86c8 100644 --- a/xmlsecurity/source/helper/documentsignaturemanager.cxx +++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx @@ -317,14 +317,15 @@ void DocumentSignatureManager::remove(sal_uInt16 nPosition) { // Something not ZIP based, try PDF. uno::Reference<io::XInputStream> xInputStream(mxSignatureStream, uno::UNO_QUERY); - if (PDFSignatureHelper::RemoveSignature(xInputStream, nPosition)) + if (!PDFSignatureHelper::RemoveSignature(xInputStream, nPosition)) { SAL_WARN("xmlsecurity.helper", "PDFSignatureHelper::RemoveSignature() failed"); return; } - // Only erase when the removal was successfull, it may fail for PDF. - maCurrentSignatureInformations.erase(maCurrentSignatureInformations.begin() + nPosition); + // Only erase when the removal was successful, it may fail for PDF. + // Also, erase the requested and all following signatures, as PDF signatures are always chained. + maCurrentSignatureInformations.erase(maCurrentSignatureInformations.begin() + nPosition, maCurrentSignatureInformations.end()); return; } commit f45ace2897dca1dd8f3553e46415df4fe7ad62d8 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Wed Oct 26 17:52:28 2016 +0200 xmlsecurity PDF signing: fix byte range check for multiple signatures We can mandate that the byte range end is the end of the file for the last signature only. With this, signing a previously unsigned file multiple times works, so add a matching testcase for that as well. Change-Id: I8fe5482890fca4dab8da6305aa7fc7f60df612d8 diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx index 59c7f5d..f42350a 100644 --- a/xmlsecurity/inc/pdfio/pdfdocument.hxx +++ b/xmlsecurity/inc/pdfio/pdfdocument.hxx @@ -88,8 +88,12 @@ public: /// Serializes the contents of the edit buffer. bool Write(SvStream& rStream); std::vector<PDFObjectElement*> GetSignatureWidgets(); - /// Return value is about if we can determine a result, rInformation is about the actual result. - static bool ValidateSignature(SvStream& rStream, PDFObjectElement* pSignature, SignatureInformation& rInformation); + /** + * @param rInformation The actual result. + * @param bLast If this is the last signature in the file, so it covers the whole file physically. + * @return If we can determinate a result. + */ + static bool ValidateSignature(SvStream& rStream, PDFObjectElement* pSignature, SignatureInformation& rInformation, bool bLast); /// Remove the nth signature from read document in the edit buffer. bool RemoveSignature(size_t nPosition); }; diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index 6a3800f..a2980db 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -29,17 +29,25 @@ class PDFSigningTest : public test::BootstrapFixture { uno::Reference<uno::XComponentContext> mxComponentContext; + /** + * Sign rInURL once and save the result as rOutURL, asserting that rInURL + * had nOriginalSignatureCount signatures. + */ + void sign(const OUString& rInURL, const OUString& rOutURL, size_t nOriginalSignatureCount); public: PDFSigningTest(); void setUp() override; /// Test adding a new signature to a previously unsigned file. void testPDFAdd(); + /// Test signing a previously unsigned file twice. + void testPDFAdd2(); /// Test remove a signature from a previously signed file. void testPDFRemove(); CPPUNIT_TEST_SUITE(PDFSigningTest); CPPUNIT_TEST(testPDFAdd); + CPPUNIT_TEST(testPDFAdd2); CPPUNIT_TEST(testPDFRemove); CPPUNIT_TEST_SUITE_END(); }; @@ -67,25 +75,20 @@ void PDFSigningTest::setUp() #endif } -void PDFSigningTest::testPDFAdd() +void PDFSigningTest::sign(const OUString& rInURL, const OUString& rOutURL, size_t nOriginalSignatureCount) { -#ifndef _WIN32 - // Make sure that no.pdf has no signatures. + // Make sure that input has nOriginalSignatureCount signatures. uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext); uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString()); xmlsecurity::pdfio::PDFDocument aDocument; { - OUString aSourceDir = m_directories.getURLFromSrc(DATA_DIRECTORY); - OUString aInURL = aSourceDir + "no.pdf"; - SvFileStream aStream(aInURL, StreamMode::READ); + SvFileStream aStream(rInURL, StreamMode::READ); CPPUNIT_ASSERT(aDocument.Read(aStream)); std::vector<xmlsecurity::pdfio::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets(); - CPPUNIT_ASSERT(aSignatures.empty()); + CPPUNIT_ASSERT_EQUAL(nOriginalSignatureCount, aSignatures.size()); } - // Sign it and write out the result as add.pdf. - OUString aTargetDir = m_directories.getURLFromWorkdir("/CppunitTest/xmlsecurity_signing.test.user/"); - OUString aOutURL = aTargetDir + "add.pdf"; + // Sign it and write out the result. { uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment(); uno::Sequence<uno::Reference<security::XCertificate>> aCertificates = xSecurityEnvironment->getPersonalCertificates(); @@ -95,21 +98,54 @@ void PDFSigningTest::testPDFAdd() return; } CPPUNIT_ASSERT(aDocument.Sign(aCertificates[0], "test")); - SvFileStream aOutStream(aOutURL, StreamMode::WRITE | StreamMode::TRUNC); + SvFileStream aOutStream(rOutURL, StreamMode::WRITE | StreamMode::TRUNC); CPPUNIT_ASSERT(aDocument.Write(aOutStream)); } // Read back the signed pdf and make sure that it has one valid signature. { - SvFileStream aStream(aOutURL, StreamMode::READ); + SvFileStream aStream(rOutURL, StreamMode::READ); xmlsecurity::pdfio::PDFDocument aVerifyDocument; CPPUNIT_ASSERT(aVerifyDocument.Read(aStream)); std::vector<xmlsecurity::pdfio::PDFObjectElement*> aSignatures = aVerifyDocument.GetSignatureWidgets(); - // This was 0 when PDFDocument::Sign() silently returned success, without doing anything. - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aSignatures.size()); - SignatureInformation aInfo(0); - CPPUNIT_ASSERT(xmlsecurity::pdfio::PDFDocument::ValidateSignature(aStream, aSignatures[0], aInfo)); + // This was nOriginalSignatureCount when PDFDocument::Sign() silently returned success, without doing anything. + CPPUNIT_ASSERT_EQUAL(nOriginalSignatureCount + 1, aSignatures.size()); + for (size_t i = 0; i < aSignatures.size(); ++i) + { + SignatureInformation aInfo(i); + bool bLast = i == aSignatures.size() - 1; + CPPUNIT_ASSERT(xmlsecurity::pdfio::PDFDocument::ValidateSignature(aStream, aSignatures[i], aInfo, bLast)); + } } +} + +void PDFSigningTest::testPDFAdd() +{ +#ifndef _WIN32 + OUString aSourceDir = m_directories.getURLFromSrc(DATA_DIRECTORY); + OUString aInURL = aSourceDir + "no.pdf"; + OUString aTargetDir = m_directories.getURLFromWorkdir("/CppunitTest/xmlsecurity_signing.test.user/"); + OUString aOutURL = aTargetDir + "add.pdf"; + sign(aInURL, aOutURL, 0); +#endif +} + +void PDFSigningTest::testPDFAdd2() +{ +#ifndef _WIN32 + // Sign. + OUString aSourceDir = m_directories.getURLFromSrc(DATA_DIRECTORY); + OUString aInURL = aSourceDir + "no.pdf"; + OUString aTargetDir = m_directories.getURLFromWorkdir("/CppunitTest/xmlsecurity_signing.test.user/"); + OUString aOutURL = aTargetDir + "add.pdf"; + sign(aInURL, aOutURL, 0); + + // Sign again. + aInURL = aTargetDir + "add.pdf"; + aOutURL = aTargetDir + "add2.pdf"; + // This failed with "second range end is not the end of the file" for the + // first signature. + sign(aInURL, aOutURL, 1); #endif } @@ -128,7 +164,7 @@ void PDFSigningTest::testPDFRemove() std::vector<xmlsecurity::pdfio::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets(); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aSignatures.size()); SignatureInformation aInfo(0); - CPPUNIT_ASSERT(xmlsecurity::pdfio::PDFDocument::ValidateSignature(aStream, aSignatures[0], aInfo)); + CPPUNIT_ASSERT(xmlsecurity::pdfio::PDFDocument::ValidateSignature(aStream, aSignatures[0], aInfo, /*bLast=*/true)); } // Remove the signature and write out the result as remove.pdf. diff --git a/xmlsecurity/source/helper/pdfsignaturehelper.cxx b/xmlsecurity/source/helper/pdfsignaturehelper.cxx index a1b1d20..859a479 100644 --- a/xmlsecurity/source/helper/pdfsignaturehelper.cxx +++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx @@ -58,7 +58,8 @@ bool PDFSignatureHelper::ReadAndVerifySignature(const uno::Reference<io::XInputS { SignatureInformation aInfo(i); - if (!xmlsecurity::pdfio::PDFDocument::ValidateSignature(*pStream, aSignatures[i], aInfo)) + bool bLast = i == aSignatures.size() - 1; + if (!xmlsecurity::pdfio::PDFDocument::ValidateSignature(*pStream, aSignatures[i], aInfo, bLast)) { SAL_WARN("xmlsecurity.helper", "failed to determine digest match"); continue; diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx index 7b8cea0..20bbbbf 100644 --- a/xmlsecurity/source/pdfio/pdfdocument.cxx +++ b/xmlsecurity/source/pdfio/pdfdocument.cxx @@ -1188,7 +1188,7 @@ std::vector<unsigned char> PDFDocument::DecodeHexString(PDFHexStringElement* pEl return aRet; } -bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignature, SignatureInformation& rInformation) +bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignature, SignatureInformation& rInformation, bool bLast) { PDFObjectElement* pValue = pSignature->LookupObject("V"); if (!pValue) @@ -1285,7 +1285,7 @@ bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignat } rStream.Seek(STREAM_SEEK_TO_END); size_t nFileEnd = rStream.Tell(); - if ((aByteRanges[1].first + aByteRanges[1].second) != nFileEnd) + if (bLast && (aByteRanges[1].first + aByteRanges[1].second) != nFileEnd) { SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ValidateSignature: second range end is not the end of the file"); return false; diff --git a/xmlsecurity/source/pdfio/pdfverify.cxx b/xmlsecurity/source/pdfio/pdfverify.cxx index f980db8..8e4ba42 100644 --- a/xmlsecurity/source/pdfio/pdfverify.cxx +++ b/xmlsecurity/source/pdfio/pdfverify.cxx @@ -113,7 +113,8 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(nArgc, pArgv) for (size_t i = 0; i < aSignatures.size(); ++i) { SignatureInformation aInfo(i); - if (!xmlsecurity::pdfio::PDFDocument::ValidateSignature(aStream, aSignatures[i], aInfo)) + bool bLast = i == aSignatures.size() - 1; + if (!xmlsecurity::pdfio::PDFDocument::ValidateSignature(aStream, aSignatures[i], aInfo, bLast)) { SAL_WARN("xmlsecurity.pdfio", "failed to determine digest match"); return 1; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits