1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
12 #include <string_view>
14 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
15 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
17 #include <osl/file.hxx>
18 #include <sal/log.hxx>
19 #include <test/bootstrapfixture.hxx>
20 #include <unotest/macros_test.hxx>
21 #include <tools/datetime.hxx>
22 #include <unotools/streamwrap.hxx>
23 #include <unotools/ucbstreamhelper.hxx>
24 #include <vcl/filter/pdfdocument.hxx>
25 #include <vcl/filter/PDFiumLibrary.hxx>
27 #include <documentsignaturemanager.hxx>
28 #include <pdfsignaturehelper.hxx>
31 #define WIN32_LEAN_AND_MEAN
35 using namespace com::sun::star
;
39 constexpr OUStringLiteral DATA_DIRECTORY
= u
"/xmlsecurity/qa/unit/pdfsigning/data/";
42 /// Testsuite for the PDF signing feature.
43 class PDFSigningTest
: public test::BootstrapFixture
, public unotest::MacrosTest
47 * Sign rInURL once and save the result as rOutURL, asserting that rInURL
48 * had nOriginalSignatureCount signatures.
50 bool sign(const OUString
& rInURL
, const OUString
& rOutURL
, size_t nOriginalSignatureCount
);
52 * Read a pdf and make sure that it has the expected number of valid
55 std::vector
<SignatureInformation
> verify(const OUString
& rURL
, size_t nCount
);
59 void setUp() override
;
60 void tearDown() override
;
63 PDFSigningTest::PDFSigningTest() {}
65 void PDFSigningTest::setUp()
67 test::BootstrapFixture::setUp();
68 MacrosTest::setUpNssGpg(m_directories
, "xmlsecurity_pdfsigning");
71 void PDFSigningTest::tearDown()
73 MacrosTest::tearDownNssGpg();
74 test::BootstrapFixture::tearDown();
77 std::vector
<SignatureInformation
> PDFSigningTest::verify(const OUString
& rURL
, size_t nCount
)
79 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
80 = xml::crypto::SEInitializer::create(mxComponentContext
);
81 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
82 = xSEInitializer
->createSecurityContext(OUString());
83 std::vector
<SignatureInformation
> aRet
;
85 SvFileStream
aStream(rURL
, StreamMode::READ
);
86 PDFSignatureHelper aHelper
;
87 CPPUNIT_ASSERT(aHelper
.ReadAndVerifySignatureSvStream(aStream
));
89 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
92 CPPUNIT_ASSERT_EQUAL(nCount
, aHelper
.GetSignatureInformations().size());
94 for (size_t i
= 0; i
< aHelper
.GetSignatureInformations().size(); ++i
)
96 const SignatureInformation
& rInfo
= aHelper
.GetSignatureInformations()[i
];
97 aRet
.push_back(rInfo
);
103 bool PDFSigningTest::sign(const OUString
& rInURL
, const OUString
& rOutURL
,
104 size_t nOriginalSignatureCount
)
106 // Make sure that input has nOriginalSignatureCount signatures.
107 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
108 = xml::crypto::SEInitializer::create(mxComponentContext
);
109 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
110 = xSEInitializer
->createSecurityContext(OUString());
111 vcl::filter::PDFDocument aDocument
;
113 SvFileStream
aStream(rInURL
, StreamMode::READ
);
114 CPPUNIT_ASSERT(aDocument
.Read(aStream
));
115 std::vector
<vcl::filter::PDFObjectElement
*> aSignatures
= aDocument
.GetSignatureWidgets();
116 CPPUNIT_ASSERT_EQUAL(nOriginalSignatureCount
, aSignatures
.size());
119 bool bSignSuccessful
= false;
120 // Sign it and write out the result.
122 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
123 = xSecurityContext
->getSecurityEnvironment();
124 uno::Sequence
<uno::Reference
<security::XCertificate
>> aCertificates
125 = xSecurityEnvironment
->getPersonalCertificates();
126 DateTime
now(DateTime::SYSTEM
);
127 for (auto& cert
: asNonConstRange(aCertificates
))
129 css::util::DateTime aNotValidAfter
= cert
->getNotValidAfter();
130 css::util::DateTime aNotValidBefore
= cert
->getNotValidBefore();
132 // Only try certificates that are already active and not expired
133 if ((now
> aNotValidAfter
) || (now
< aNotValidBefore
))
135 SAL_WARN("xmlsecurity.qa",
136 "Skipping a certificate that is not yet valid or already not valid");
140 bool bSignResult
= aDocument
.Sign(cert
, "test", /*bAdES=*/true);
144 DWORD dwErr
= GetLastError();
145 if (HRESULT_FROM_WIN32(dwErr
) == CRYPT_E_NO_KEY_PROPERTY
)
147 SAL_WARN("xmlsecurity.qa", "Skipping a certificate without a private key");
148 continue; // The certificate does not have a private key - not a valid certificate
152 CPPUNIT_ASSERT(bSignResult
);
153 SvFileStream
aOutStream(rOutURL
, StreamMode::WRITE
| StreamMode::TRUNC
);
154 CPPUNIT_ASSERT(aDocument
.Write(aOutStream
));
155 bSignSuccessful
= true;
161 // This was nOriginalSignatureCount when PDFDocument::Sign() silently returned success, without doing anything.
163 verify(rOutURL
, nOriginalSignatureCount
+ 1);
165 // May return false if NSS failed to parse its own profile or Windows has no valid certificates installed.
166 return bSignSuccessful
;
169 /// Test adding a new signature to a previously unsigned file.
170 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDFAdd
)
172 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
178 OUString aSourceDir
= m_directories
.getURLFromSrc(DATA_DIRECTORY
);
179 OUString aInURL
= aSourceDir
+ "no.pdf";
181 = m_directories
.getURLFromWorkdir(u
"/CppunitTest/xmlsecurity_pdfsigning.test.user/");
182 OUString aOutURL
= aTargetDir
+ "add.pdf";
183 bool bHadCertificates
= sign(aInURL
, aOutURL
, 0);
185 if (bHadCertificates
)
187 // Assert that the SubFilter is not adbe.pkcs7.detached in the bAdES case.
188 std::vector
<SignatureInformation
> aInfos
= verify(aOutURL
, 1);
189 CPPUNIT_ASSERT(aInfos
[0].bHasSigningCertificate
);
190 // Make sure the timestamp is correct.
191 DateTime
aDateTime(DateTime::SYSTEM
);
192 // This was 0 (on Windows), as neither the /M key nor the PKCS#7 blob contained a timestamp.
193 CPPUNIT_ASSERT_EQUAL(aDateTime
.GetYear(), aInfos
[0].stDateTime
.Year
);
194 // Assert that the digest algorithm is not SHA-1 in the bAdES case.
195 CPPUNIT_ASSERT_EQUAL(xml::crypto::DigestID::SHA256
, aInfos
[0].nDigestID
);
199 /// Test signing a previously unsigned file twice.
200 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDFAdd2
)
203 OUString aSourceDir
= m_directories
.getURLFromSrc(DATA_DIRECTORY
);
204 OUString aInURL
= aSourceDir
+ "no.pdf";
206 = m_directories
.getURLFromWorkdir(u
"/CppunitTest/xmlsecurity_pdfsigning.test.user/");
207 OUString aOutURL
= aTargetDir
+ "add.pdf";
208 bool bHadCertificates
= sign(aInURL
, aOutURL
, 0);
211 aInURL
= aTargetDir
+ "add.pdf";
212 aOutURL
= aTargetDir
+ "add2.pdf";
213 // This failed with "second range end is not the end of the file" for the
215 if (bHadCertificates
)
216 sign(aInURL
, aOutURL
, 1);
219 /// Test removing a signature from a previously signed file.
220 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDFRemove
)
222 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
228 // Make sure that good.pdf has 1 valid signature.
229 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
230 = xml::crypto::SEInitializer::create(mxComponentContext
);
231 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
232 = xSEInitializer
->createSecurityContext(OUString());
233 vcl::filter::PDFDocument aDocument
;
234 OUString aSourceDir
= m_directories
.getURLFromSrc(DATA_DIRECTORY
);
235 OUString aInURL
= aSourceDir
+ "good.pdf";
237 SvFileStream
aStream(aInURL
, StreamMode::READ
);
238 PDFSignatureHelper aHelper
;
239 aHelper
.ReadAndVerifySignatureSvStream(aStream
);
240 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aHelper
.GetSignatureInformations().size());
243 // Remove the signature and write out the result as remove.pdf.
245 = m_directories
.getURLFromWorkdir(u
"/CppunitTest/xmlsecurity_pdfsigning.test.user/");
246 OUString aOutURL
= aTargetDir
+ "remove.pdf";
247 osl::File::copy(aInURL
, aOutURL
);
249 uno::Reference
<io::XInputStream
> xInputStream
;
250 std::unique_ptr
<SvStream
> pStream
251 = utl::UcbStreamHelper::CreateStream(aOutURL
, StreamMode::READWRITE
);
252 uno::Reference
<io::XStream
> xStream(new utl::OStreamWrapper(std::move(pStream
)));
253 xInputStream
.set(xStream
, uno::UNO_QUERY
);
254 PDFSignatureHelper::RemoveSignature(xInputStream
, 0);
257 // Read back the pdf and make sure that it no longer has signatures.
258 // This failed when PDFDocument::RemoveSignature() silently returned
259 // success, without doing anything.
263 /// Test removing all signatures from a previously multi-signed file.
264 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDFRemoveAll
)
266 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
272 // Make sure that good2.pdf has 2 valid signatures. Unlike in
273 // testPDFRemove(), here intentionally test DocumentSignatureManager and
274 // PDFSignatureHelper code as well.
275 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
276 = xml::crypto::SEInitializer::create(mxComponentContext
);
277 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
278 = xSEInitializer
->createSecurityContext(OUString());
280 // Copy the test document to a temporary file, as it'll be modified.
282 = m_directories
.getURLFromWorkdir(u
"/CppunitTest/xmlsecurity_pdfsigning.test.user/");
283 OUString aOutURL
= aTargetDir
+ "remove-all.pdf";
284 CPPUNIT_ASSERT_EQUAL(
285 osl::File::RC::E_None
,
286 osl::File::copy(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "2good.pdf", aOutURL
));
287 // Load the test document as a storage and read its two signatures.
288 DocumentSignatureManager
aManager(mxComponentContext
, DocumentSignatureMode::Content
);
289 std::unique_ptr
<SvStream
> pStream
290 = utl::UcbStreamHelper::CreateStream(aOutURL
, StreamMode::READ
| StreamMode::WRITE
);
291 uno::Reference
<io::XStream
> xStream(new utl::OStreamWrapper(std::move(pStream
)));
292 aManager
.setSignatureStream(xStream
);
293 aManager
.read(/*bUseTempStream=*/false);
294 std::vector
<SignatureInformation
>& rInformations
= aManager
.getCurrentSignatureInformations();
295 // This was 1 when NSS_CMSSignerInfo_GetSigningCertificate() failed, which
296 // means that we only used the locally imported certificates for
297 // verification, not the ones provided in the PDF signature data.
298 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations
.size());
300 // Request removal of the first signature, should imply removal of the
301 // second chained signature as well.
303 // This was 2, Manager didn't write anything to disk when removal succeeded
304 // (instead of doing that when removal failed).
305 // Then this was 1, when the chained signature wasn't removed.
306 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), rInformations
.size());
309 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testTdf107782
)
311 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
312 = xml::crypto::SEInitializer::create(mxComponentContext
);
313 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
314 = xSEInitializer
->createSecurityContext(OUString());
316 // Load the test document as a storage and read its signatures.
317 DocumentSignatureManager
aManager(mxComponentContext
, DocumentSignatureMode::Content
);
318 OUString aURL
= m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "tdf107782.pdf";
319 std::unique_ptr
<SvStream
> pStream
320 = utl::UcbStreamHelper::CreateStream(aURL
, StreamMode::READ
| StreamMode::WRITE
);
321 uno::Reference
<io::XStream
> xStream(new utl::OStreamWrapper(std::move(pStream
)));
322 aManager
.setSignatureStream(xStream
);
323 aManager
.read(/*bUseTempStream=*/false);
324 CPPUNIT_ASSERT(aManager
.hasPDFSignatureHelper());
326 // This failed with an std::bad_alloc exception on Windows.
327 aManager
.getPDFSignatureHelper().GetDocumentSignatureInformations(
328 aManager
.getSecurityEnvironment());
331 /// Test a PDF 1.4 document, signed by Adobe.
332 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDF14Adobe
)
334 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
340 // Two signatures, first is SHA1, the second is SHA256.
341 // This was 0, as we failed to find the Annots key's value when it was a
342 // reference-to-array, not an array.
343 std::vector
<SignatureInformation
> aInfos
344 = verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "pdf14adobe.pdf", 2);
345 // This was 0, out-of-PKCS#7 signature date wasn't read.
346 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16
>(2016), aInfos
[1].stDateTime
.Year
);
349 /// Test a PDF 1.6 document, signed by Adobe.
350 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDF16Adobe
)
352 // Contains a cross-reference stream, object streams and a compressed
353 // stream with a predictor. And a valid signature.
354 // Found signatures was 0, as parsing failed due to lack of support for
356 verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "pdf16adobe.pdf", 1);
359 /// Test adding a signature to a PDF 1.6 document.
360 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDF16Add
)
362 // Contains PDF 1.6 features, make sure we can add a signature using that
364 OUString aSourceDir
= m_directories
.getURLFromSrc(DATA_DIRECTORY
);
365 OUString aInURL
= aSourceDir
+ "pdf16adobe.pdf";
367 = m_directories
.getURLFromWorkdir(u
"/CppunitTest/xmlsecurity_pdfsigning.test.user/");
368 OUString aOutURL
= aTargetDir
+ "add.pdf";
369 // This failed: verification broke as incorrect xref stream was written as
370 // part of the new signature.
371 bool bHadCertificates
= sign(aInURL
, aOutURL
, 1);
374 aInURL
= aTargetDir
+ "add.pdf";
375 aOutURL
= aTargetDir
+ "add2.pdf";
376 // This failed as non-compressed AcroForm wasn't handled.
377 if (bHadCertificates
)
378 sign(aInURL
, aOutURL
, 2);
381 /// Test a PDF 1.4 document, signed by LO on Windows.
382 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDF14LOWin
)
384 // mscrypto used SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION as a digest
385 // algorithm when it meant SEC_OID_SHA1, make sure we tolerate that on all
387 // This failed, as NSS HASH_Create() didn't handle the sign algorithm.
388 verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "pdf14lowin.pdf", 1);
391 /// Test a PAdES document, signed by LO on Linux.
392 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPDFPAdESGood
)
394 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
400 std::vector
<SignatureInformation
> aInfos
401 = verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "good-pades.pdf", 1);
402 CPPUNIT_ASSERT(aInfos
[0].bHasSigningCertificate
);
405 /// Test a valid signature that does not cover the whole file.
406 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPartial
)
408 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
414 std::vector
<SignatureInformation
> aInfos
415 = verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "partial.pdf", 1);
416 CPPUNIT_ASSERT(!aInfos
.empty());
417 SignatureInformation
& rInformation
= aInfos
[0];
418 CPPUNIT_ASSERT(rInformation
.bPartialDocumentSignature
);
421 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testPartialInBetween
)
423 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
429 std::vector
<SignatureInformation
> aInfos
430 = verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "partial-in-between.pdf", 2);
431 CPPUNIT_ASSERT(!aInfos
.empty());
432 SignatureInformation
& rInformation
= aInfos
[0];
433 // Without the accompanying fix in place, this test would have failed, as unsigned incremental
434 // update between two signatures were not detected.
435 CPPUNIT_ASSERT(rInformation
.bPartialDocumentSignature
);
438 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testBadCertP1
)
440 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
446 std::vector
<SignatureInformation
> aInfos
447 = verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "bad-cert-p1.pdf", 1);
448 CPPUNIT_ASSERT(!aInfos
.empty());
449 SignatureInformation
& rInformation
= aInfos
[0];
450 // Without the accompanying fix in place, this test would have failed with:
451 // - Expected: 0 (SecurityOperationStatus_UNKNOWN)
452 // - Actual : 1 (SecurityOperationStatus_OPERATION_SUCCEEDED)
453 // i.e. annotation after a P1 signature was not considered as a bad modification.
454 CPPUNIT_ASSERT_EQUAL(xml::crypto::SecurityOperationStatus::SecurityOperationStatus_UNKNOWN
,
455 rInformation
.nStatus
);
458 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testBadCertP3Stamp
)
460 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
466 std::vector
<SignatureInformation
> aInfos
467 = verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "bad-cert-p3-stamp.pdf", 1);
468 CPPUNIT_ASSERT(!aInfos
.empty());
469 SignatureInformation
& rInformation
= aInfos
[0];
471 // Without the accompanying fix in place, this test would have failed with:
472 // - Expected: 0 (SecurityOperationStatus_UNKNOWN)
473 // - Actual : 1 (SecurityOperationStatus_OPERATION_SUCCEEDED)
474 // i.e. adding a stamp annotation was not considered as a bad modification.
475 CPPUNIT_ASSERT_EQUAL(xml::crypto::SecurityOperationStatus::SecurityOperationStatus_UNKNOWN
,
476 rInformation
.nStatus
);
479 /// Test writing a PAdES signature.
480 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testSigningCertificateAttribute
)
482 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
488 // Create a new signature.
489 OUString aSourceDir
= m_directories
.getURLFromSrc(DATA_DIRECTORY
);
490 OUString aInURL
= aSourceDir
+ "no.pdf";
492 = m_directories
.getURLFromWorkdir(u
"/CppunitTest/xmlsecurity_pdfsigning.test.user/");
493 OUString aOutURL
= aTargetDir
+ "signing-certificate-attribute.pdf";
494 bool bHadCertificates
= sign(aInURL
, aOutURL
, 0);
495 if (!bHadCertificates
)
499 std::vector
<SignatureInformation
> aInfos
= verify(aOutURL
, 1);
500 CPPUNIT_ASSERT(!aInfos
.empty());
501 SignatureInformation
& rInformation
= aInfos
[0];
502 // Assert that it has a signed signingCertificateV2 attribute.
503 CPPUNIT_ASSERT(rInformation
.bHasSigningCertificate
);
506 /// Test that we accept files which are supposed to be good.
507 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testGood
)
509 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
515 const std::initializer_list
<std::u16string_view
> aNames
= {
516 // We failed to determine if this is good or bad.
517 u
"good-non-detached.pdf",
518 // Boolean value for dictionary key caused read error.
522 for (const auto& rName
: aNames
)
524 std::vector
<SignatureInformation
> aInfos
525 = verify(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + rName
, 1);
526 CPPUNIT_ASSERT(!aInfos
.empty());
527 SignatureInformation
& rInformation
= aInfos
[0];
528 CPPUNIT_ASSERT_EQUAL(int(xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
),
529 static_cast<int>(rInformation
.nStatus
));
533 /// Test that we don't crash / loop while tokenizing these files.
534 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testTokenize
)
536 const std::initializer_list
<std::u16string_view
> aNames
= {
537 // We looped on this broken input.
539 // ']' in a name token was mishandled.
541 // %%EOF at the end wasn't followed by a newline.
543 // File that's intentionally smaller than 1024 bytes.
546 // Nested parentheses were not handled.
548 // Valgrind was unhappy about this.
552 for (const auto& rName
: aNames
)
554 SvFileStream
aStream(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + rName
, StreamMode::READ
);
555 vcl::filter::PDFDocument aDocument
;
556 // Just make sure the tokenizer finishes without an error, don't look at the signature.
557 CPPUNIT_ASSERT(aDocument
.Read(aStream
));
559 if (rName
== u
"tdf107149.pdf")
560 // This failed, page list was empty.
561 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aDocument
.GetPages().size());
565 /// Test handling of unknown SubFilter values.
566 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testUnknownSubFilter
)
568 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
574 // Tokenize the bugdoc.
575 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
576 = xml::crypto::SEInitializer::create(mxComponentContext
);
577 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
578 = xSEInitializer
->createSecurityContext(OUString());
579 std::unique_ptr
<SvStream
> pStream
= utl::UcbStreamHelper::CreateStream(
580 m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "cr-comment.pdf", StreamMode::STD_READ
);
581 uno::Reference
<io::XStream
> xStream(new utl::OStreamWrapper(std::move(pStream
)));
582 DocumentSignatureManager
aManager(mxComponentContext
, DocumentSignatureMode::Content
);
583 aManager
.setSignatureStream(xStream
);
584 aManager
.read(/*bUseTempStream=*/false);
586 // Make sure we find both signatures, even if the second has unknown SubFilter.
587 std::vector
<SignatureInformation
>& rInformations
= aManager
.getCurrentSignatureInformations();
588 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations
.size());
591 CPPUNIT_TEST_FIXTURE(PDFSigningTest
, testGoodCustomMagic
)
593 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
599 // Tokenize the bugdoc.
600 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
601 = xml::crypto::SEInitializer::create(mxComponentContext
);
602 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
603 = xSEInitializer
->createSecurityContext(OUString());
604 std::unique_ptr
<SvStream
> pStream
= utl::UcbStreamHelper::CreateStream(
605 m_directories
.getURLFromSrc(DATA_DIRECTORY
) + "good-custom-magic.pdf",
606 StreamMode::STD_READ
);
607 uno::Reference
<io::XStream
> xStream(new utl::OStreamWrapper(std::move(pStream
)));
608 DocumentSignatureManager
aManager(mxComponentContext
, DocumentSignatureMode::Content
);
609 aManager
.setSignatureStream(xStream
);
610 aManager
.read(/*bUseTempStream=*/false);
612 // Without the accompanying fix in place, this test would have failed with:
613 // - Expected: 1 (SecurityOperationStatus_OPERATION_SUCCEEDED)
614 // - Actual : 0 (SecurityOperationStatus_UNKNOWN)
615 // i.e. no signatures were found due to a custom non-comment magic after the header.
616 std::vector
<SignatureInformation
>& rInformations
= aManager
.getCurrentSignatureInformations();
617 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations
.size());
620 CPPUNIT_PLUGIN_IMPLEMENT();
622 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */