summaryrefslogtreecommitdiff
path: root/xmlsecurity/qa/unit
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2024-09-12 15:29:33 +0200
committerMiklos Vajna <vmiklos@collabora.com>2024-09-12 16:53:06 +0200
commite5a0209d4b1e1f09191a442e04d626b21c49b9df (patch)
treecac121f5c796aed978ddeb9513519c97b5acb816 /xmlsecurity/qa/unit
parent4b399dbfc4c3081174be1703a0c98fec1afd761f (diff)
cool#9992 lok doc sign: allow sign of macros & the document itself in one step
Sign a document with macros (via file -> digital signatures -> digital signatures), realize that you still get a warning on file open, sign the macros in the document (via tools -> macros -> digital signature), realize that you did this in the wrong order, so now you have to re-sign the doc content. The reason for this is that the macro signature only signs the macro parts of the document (so you can still edit the document and the signature is valid, as long as you don't touch macros), while the doc content signature signs everything, including the macro signature, so the order of the two matters. Solve this trouble by adding a new setting that allows doing the two signatures in one step. Do this by extending the doc content signing code with an optional pre-step that first signs the document macros. This is a bit tricky to do, since xmlsecurity/ gets an RW signature stream and a RO document storage from sfx2/, but transferring one more signature stream can solve this trouble. Other tricky parts of the change: 1) The crypto signing is always done by libxmlsec, so DigitalSignaturesDialog::SetScriptingSignatureStream() has to update the storage of the sign manager's sign helper, otherwise, the hashes in the macro signature will be empty. 2) Signing reads the RO storage, so normally the macro signature would not be part of the doc signature when creating both signatures inside a single dialog. (The storage is only committed after the dialog ends.) Fix this problem by extending DocumentSignatureManager::add() and UriBindingHelper::OpenInputStream() to provide kind of an overlay when xmlsecurity/ gets a script signature stream: this way the macro signature will be part of the doc signature while the dialog is in progress. No overlay is needed later, once both streams are committed to the storage on dialog end. Change-Id: Ic2728689997165595991d5ec59c7a2683286e22d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173263 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'xmlsecurity/qa/unit')
-rw-r--r--xmlsecurity/qa/unit/signing/data/macro.odtbin0 -> 11023 bytes
-rw-r--r--xmlsecurity/qa/unit/signing/signing.cxx62
2 files changed, 62 insertions, 0 deletions
diff --git a/xmlsecurity/qa/unit/signing/data/macro.odt b/xmlsecurity/qa/unit/signing/data/macro.odt
new file mode 100644
index 000000000000..b6e470076bef
--- /dev/null
+++ b/xmlsecurity/qa/unit/signing/data/macro.odt
Binary files differ
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx
index 038bf78ce193..5646a2afa6b6 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -1149,6 +1149,68 @@ CPPUNIT_TEST_FIXTURE(SigningTest, testSignatureLineODF)
CPPUNIT_ASSERT(xSignatureInfo[0].InvalidSignatureLineImage.is());
}
+CPPUNIT_TEST_FIXTURE(SigningTest, testImplicitScriptSign)
+{
+ // Given an ODT file with macros, and two signature managers to create macro + doc signatures:
+ OUString aFileURL = createFileURL(u"macro.odt");
+ uno::Reference<embed::XStorage> xWriteableZipStor
+ = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aFileURL,
+ embed::ElementModes::READWRITE);
+ uno::Reference<embed::XStorage> xMetaInf
+ = xWriteableZipStor->openStorageElement(u"META-INF"_ustr, embed::ElementModes::READWRITE);
+ uno::Reference<io::XStream> xStream = xMetaInf->openStreamElement(
+ u"documentsignatures.xml"_ustr, embed::ElementModes::READWRITE);
+ uno::Reference<io::XStream> xScriptingStream
+ = xMetaInf->openStreamElement(u"macrosignatures.xml"_ustr, embed::ElementModes::READWRITE);
+ uno::Reference<embed::XStorage> xZipStor
+ = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aFileURL,
+ embed::ElementModes::READ);
+ DocumentSignatureManager aManager(m_xContext, DocumentSignatureMode::Content);
+ CPPUNIT_ASSERT(aManager.init());
+ aManager.setStore(xZipStor);
+ aManager.setSignatureStream(xStream);
+ aManager.getSignatureHelper().SetStorage(xZipStor, u"1.2", xScriptingStream);
+ DocumentSignatureManager aScriptManager(m_xContext, DocumentSignatureMode::Macros);
+ CPPUNIT_ASSERT(aScriptManager.init());
+ aScriptManager.setStore(xZipStor);
+ aScriptManager.getSignatureHelper().SetStorage(xZipStor, u"1.2");
+ aScriptManager.setSignatureStream(xScriptingStream);
+ uno::Reference<security::XCertificate> xCertificate
+ = getCertificate(aManager, svl::crypto::SignatureMethodAlgorithm::RSA);
+ if (!xCertificate.is())
+ return;
+
+ // When adding those signatures and writing them to the streams from the read-write storage:
+ OUString aDescription;
+ sal_Int32 nSecurityId;
+ bool bAdESCompliant = true;
+ aScriptManager.add(xCertificate, mxSecurityContext, aDescription, nSecurityId, bAdESCompliant);
+ aScriptManager.read(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
+ aScriptManager.write(bAdESCompliant);
+ aManager.setScriptingSignatureStream(xScriptingStream);
+ aManager.add(xCertificate, mxSecurityContext, aDescription, nSecurityId, bAdESCompliant);
+ aManager.read(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
+ aManager.write(bAdESCompliant);
+
+ // Then make sure both signatures are created correctly:
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xScriptingStream, true));
+ xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+ OUString aScriptDigest = getXPathContent(
+ pXmlDoc, "/odfds:document-signatures/dsig:Signature[1]/dsig:SignedInfo/"
+ "dsig:Reference[@URI='Basic/script-lc.xml']/dsig:DigestValue"_ostr);
+ // Without the accompanying fix in place, this test would have failed, the digest value was just a
+ // " " placeholder.
+ CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(1), aScriptDigest.getLength());
+ pStream = utl::UcbStreamHelper::CreateStream(xStream, true);
+ pXmlDoc = parseXmlStream(pStream.get());
+ // Without the accompanying fix in place, this test would have failed, the macro signature was
+ // not part of the signed data of the document signature.
+ assertXPath(pXmlDoc,
+ "/odfds:document-signatures/dsig:Signature[1]/dsig:SignedInfo/"
+ "dsig:Reference[@URI='META-INF/macrosignatures.xml']"_ostr,
+ 1);
+}
+
#if HAVE_FEATURE_GPGVERIFY
/// Test a typical ODF where all streams are GPG-signed.
CPPUNIT_TEST_FIXTURE(SigningTest, testODFGoodGPG)