include/sfx2/digitalsignatures.hxx | 5 + officecfg/registry/schema/org/openoffice/Office/Common.xcs | 7 + sfx2/source/doc/docfile.cxx | 32 ++++++ xmlsecurity/inc/UriBindingHelper.hxx | 10 +- xmlsecurity/inc/digitalsignaturesdialog.hxx | 2 xmlsecurity/inc/documentsignaturemanager.hxx | 7 + xmlsecurity/inc/xmlsignaturehelper.hxx | 3 xmlsecurity/qa/unit/signing/data/macro.odt |binary xmlsecurity/qa/unit/signing/signing.cxx | 62 +++++++++++++ xmlsecurity/source/component/documentdigitalsignatures.cxx | 12 ++ xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx | 39 +++++++- xmlsecurity/source/helper/UriBindingHelper.cxx | 29 +++++- xmlsecurity/source/helper/documentsignaturemanager.cxx | 9 + xmlsecurity/source/helper/xmlsignaturehelper.cxx | 5 - 14 files changed, 210 insertions(+), 12 deletions(-)
New commits: commit a0b779adad4055cfe4f0fa765bb45d6f7d46ef9b Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Sep 12 15:29:33 2024 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Fri Sep 13 10:50:51 2024 +0200 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. (cherry picked from commit e5a0209d4b1e1f09191a442e04d626b21c49b9df) Conflicts: xmlsecurity/inc/xmlsignaturehelper.hxx Change-Id: Ic2728689997165595991d5ec59c7a2683286e22d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173314 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/include/sfx2/digitalsignatures.hxx b/include/sfx2/digitalsignatures.hxx index b364c9518931..856e1c5bf61a 100644 --- a/include/sfx2/digitalsignatures.hxx +++ b/include/sfx2/digitalsignatures.hxx @@ -45,6 +45,11 @@ public: const std::function<void(bool)>& rCallback) = 0; + /// Create a scripting signature before creating a document signature. + virtual void + SetSignScriptingContent(const css::uno::Reference<css::io::XStream>& xScriptingSignStream) + = 0; + protected: ~DigitalSignatures() noexcept = default; }; diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs index 4c4826e97904..aa8bca5cee00 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs @@ -2370,6 +2370,13 @@ </info> <value>true</value> </prop> + <prop oor:name="ImplicitScriptSign" oor:type="xs:boolean" oor:nillable="false"> + <info> + <desc>Specifies whether to implicitly sign macros when adding the first signature + to an ODF document with macros.</desc> + </info> + <value>false</value> + </prop> <prop oor:name="CertDir" oor:type="xs:string"> <info> <desc>Contains the path to the users NSS certificate directory.</desc> diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index 44edea053a8c..8002645a015a 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -4433,12 +4433,39 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, } else { + // Signing the entire document. if (xMetaInf.is()) { // ODF. uno::Reference< io::XStream > xStream; + uno::Reference< io::XStream > xScriptingStream; if (GetFilter() && GetFilter()->IsOwnFormat()) + { + bool bImplicitScriptSign = officecfg::Office::Common::Security::Scripting::ImplicitScriptSign::get(); + if (comphelper::LibreOfficeKit::isActive()) + { + bImplicitScriptSign = true; + } + + OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName(); + bool bHasSignatures = xMetaInf->hasByName(aDocSigName); + + // C.f. DocumentSignatureHelper::CreateElementList() for the + // DocumentSignatureMode::Macros case. + bool bHasMacros = xWriteableZipStor->hasByName(u"Basic"_ustr) + || xWriteableZipStor->hasByName(u"Dialogs"_ustr) + || xWriteableZipStor->hasByName(u"Scripts"_ustr); + xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW); + if (bImplicitScriptSign && bHasMacros && !bHasSignatures) + { + xScriptingStream.set( + xMetaInf->openStreamElement( + xSigner->getScriptingContentSignatureDefaultStreamName(), + embed::ElementModes::READWRITE), + uno::UNO_SET_THROW); + } + } bool bSuccess = false; auto onODFSignDocumentContentFinished = [this, xMetaInf, xWriteableZipStor]() { @@ -4456,6 +4483,11 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, xValidGraphic, xInvalidGraphic, aComment); else { + if (xScriptingStream.is()) + { + xModelSigner->SetSignScriptingContent(xScriptingStream); + } + // Async, all code before return has to go into the callback. xModelSigner->SignDocumentContentAsync(GetZipStorageToSign_Impl(), xStream, [onODFSignDocumentContentFinished, onSignDocumentContentFinished](bool bRet) { diff --git a/xmlsecurity/inc/UriBindingHelper.hxx b/xmlsecurity/inc/UriBindingHelper.hxx index 67c9ae69f8ba..f8a07d4d4264 100644 --- a/xmlsecurity/inc/UriBindingHelper.hxx +++ b/xmlsecurity/inc/UriBindingHelper.hxx @@ -26,7 +26,10 @@ #include <com/sun/star/xml/crypto/XUriBinding.hpp> namespace com::sun::star { - namespace io { class XInputStream; } + namespace io { + class XStream; + class XInputStream; + } namespace embed { class XStorage; } } @@ -36,16 +39,17 @@ class UriBindingHelper final : public cppu::WeakImplHelper< css::xml::crypto::XU { private: css::uno::Reference < css::embed::XStorage > mxStorage; + css::uno::Reference<css::io::XStream> mxScriptingSignatureStream; public: UriBindingHelper(); - explicit UriBindingHelper( const css::uno::Reference < css::embed::XStorage >& rxStorage ); + explicit UriBindingHelper( const css::uno::Reference < css::embed::XStorage >& rxStorage, const css::uno::Reference<css::io::XStream>& xScriptingSignatureStream ); void SAL_CALL setUriBinding( const OUString& uri, const css::uno::Reference< css::io::XInputStream >& aInputStream ) override; css::uno::Reference< css::io::XInputStream > SAL_CALL getUriBinding( const OUString& uri ) override; - static css::uno::Reference < css::io::XInputStream > OpenInputStream( const css::uno::Reference < css::embed::XStorage >& rxStore, const OUString& rURI ); + static css::uno::Reference < css::io::XInputStream > OpenInputStream( const css::uno::Reference < css::embed::XStorage >& rxStore, const OUString& rURI, const css::uno::Reference<css::io::XStream>& xScriptingSignatureStream ); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/inc/digitalsignaturesdialog.hxx b/xmlsecurity/inc/digitalsignaturesdialog.hxx index 08db226fb8a8..375328d91a88 100644 --- a/xmlsecurity/inc/digitalsignaturesdialog.hxx +++ b/xmlsecurity/inc/digitalsignaturesdialog.hxx @@ -43,6 +43,7 @@ class DigitalSignaturesDialog final : public weld::GenericDialogController { private: DocumentSignatureManager maSignatureManager; + std::optional<DocumentSignatureManager> moScriptSignatureManager; bool mbVerifySignatures; bool mbSignaturesChanged; @@ -112,6 +113,7 @@ public: // Set the storage which should be signed or verified void SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStore ); void SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream ); + void SetScriptingSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream ); // Execute the dialog... void beforeRun(); diff --git a/xmlsecurity/inc/documentsignaturemanager.hxx b/xmlsecurity/inc/documentsignaturemanager.hxx index 9f0c5d61f9e2..a66d97e3c7dd 100644 --- a/xmlsecurity/inc/documentsignaturemanager.hxx +++ b/xmlsecurity/inc/documentsignaturemanager.hxx @@ -68,6 +68,7 @@ private: DocumentSignatureMode const meSignatureMode; css::uno::Sequence<css::uno::Sequence<css::beans::PropertyValue>> m_manifest; css::uno::Reference<css::io::XStream> mxSignatureStream; + css::uno::Reference<css::io::XStream> mxScriptingSignatureStream; css::uno::Reference<css::frame::XModel> mxModel; rtl::Reference<utl::TempFileFastService> mxTempSignatureStream; /// Storage containing all OOXML signatures, unused for ODF. @@ -126,6 +127,12 @@ public: { mxSignatureStream = xSignatureStream; } + css::uno::Reference<css::io::XStream> getSignatureStream() const { return mxSignatureStream; } + void setScriptingSignatureStream( + const css::uno::Reference<css::io::XStream>& xScriptingSignatureStream) + { + mxScriptingSignatureStream = xScriptingSignatureStream; + } void setModel(const css::uno::Reference<css::frame::XModel>& xModel); const css::uno::Reference<css::embed::XStorage>& getStore() const { return mxStore; } DocumentSignatureMode getSignatureMode() const { return meSignatureMode; } diff --git a/xmlsecurity/inc/xmlsignaturehelper.hxx b/xmlsecurity/inc/xmlsignaturehelper.hxx index d6e2b90eebac..94bc309c5436 100644 --- a/xmlsecurity/inc/xmlsignaturehelper.hxx +++ b/xmlsecurity/inc/xmlsignaturehelper.hxx @@ -37,6 +37,7 @@ namespace com::sun::star { namespace io { class XOutputStream; class XInputStream; + class XStream; } namespace embed { class XStorage; } } @@ -83,7 +84,7 @@ public: // Set the storage which should be used by the default UriBinding // Must be set before StartMission(). //sODFVersion indicates the ODF version - void SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStorage, std::u16string_view sODFVersion ); + void SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStorage, std::u16string_view sODFVersion, const css::uno::Reference<css::io::XStream>& xScriptStream = css::uno::Reference<css::io::XStream>() ); // Argument for the Link is a uno::Reference< xml::sax::XAttributeList >* // Return 1 to verify, 0 to skip. 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 Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/macro.odt differ diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx index 316eaf22f5b7..a853de5e9367 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -1145,6 +1145,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) diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index 5b491f20a550..d7f2121442d8 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -78,6 +78,7 @@ class DocumentDigitalSignatures private: css::uno::Reference<css::uno::XComponentContext> mxCtx; css::uno::Reference<css::awt::XWindow> mxParentWindow; + uno::Reference<io::XStream> mxScriptingSignStream; /// will be set by XInitialization. If not we assume true. false means an earlier version (whatever that means, /// this is a string, not a boolean). @@ -226,6 +227,10 @@ public: void SignScriptingContentAsync(const css::uno::Reference<css::embed::XStorage>& xStorage, const css::uno::Reference<css::io::XStream>& xSignStream, const std::function<void(bool)>& rCallback) override; + + /// See sfx2::DigitalSignatures::SetSignScriptingContent(). + void SetSignScriptingContent( + const css::uno::Reference<css::io::XStream>& xScriptingSignStream) override; }; } @@ -449,6 +454,7 @@ void DocumentDigitalSignatures::ImplViewSignatures( xSignaturesDialog->SetStorage(rxStorage); xSignaturesDialog->SetSignatureStream( xSignStream ); + xSignaturesDialog->SetScriptingSignatureStream( mxScriptingSignStream ); xSignaturesDialog->beforeRun(); weld::DialogController::runAsync(xSignaturesDialog, [xSignaturesDialog, rxStorage, xSignStream, rCallback] (sal_Int32 nRet) { @@ -852,6 +858,12 @@ void DocumentDigitalSignatures::SignScriptingContentAsync( ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Macros, false, rCallback ); } +void DocumentDigitalSignatures::SetSignScriptingContent( + const css::uno::Reference<css::io::XStream>& xScriptingSignStream) +{ + mxScriptingSignStream = xScriptingSignStream; +} + sal_Bool DocumentDigitalSignatures::signPackageWithCertificate( css::uno::Reference<css::security::XCertificate> const& xCertificate, css::uno::Reference<css::embed::XStorage> const& xStorage, diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx index 8349a58a31ce..6fef60f01194 100644 --- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx +++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx @@ -354,7 +354,7 @@ void DigitalSignaturesDialog::SetStorage( const css::uno::Reference < css::embed || !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion); maSignatureManager.setStore(rxStore); - maSignatureManager.getSignatureHelper().SetStorage( maSignatureManager.getStore(), m_sODFVersion); + maSignatureManager.getSignatureHelper().SetStorage( maSignatureManager.getStore(), m_sODFVersion, {}); } void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream ) @@ -362,6 +362,26 @@ void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < cs maSignatureManager.setSignatureStream(rxStream); } +void DigitalSignaturesDialog::SetScriptingSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream ) +{ + if (!rxStream.is()) + { + return; + } + + uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); + moScriptSignatureManager.emplace(xContext, DocumentSignatureMode::Macros); + if (!moScriptSignatureManager->init()) + { + return; + } + moScriptSignatureManager->setStore(maSignatureManager.getStore()); + // This is the storage used by UriBindingHelper::getUriBinding(). + moScriptSignatureManager->getSignatureHelper().SetStorage(maSignatureManager.getStore(), m_sODFVersion); + maSignatureManager.getSignatureHelper().SetStorage(maSignatureManager.getStore(), m_sODFVersion, rxStream); + moScriptSignatureManager->setSignatureStream(rxStream); +} + bool DigitalSignaturesDialog::canAddRemove() { //FIXME: this func needs some cleanup, such as real split between @@ -513,6 +533,23 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, weld::Button&, void) if (aChooser->run() == RET_OK) { sal_Int32 nSecurityId; + + if (moScriptSignatureManager) + { + if (!moScriptSignatureManager->add(aChooser->GetSelectedCertificates()[0], + aChooser->GetSelectedSecurityContext(), + aChooser->GetDescription(), nSecurityId, + m_bAdESCompliant)) + { + return; + } + + moScriptSignatureManager->read(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false); + moScriptSignatureManager->write(m_bAdESCompliant); + + maSignatureManager.setScriptingSignatureStream(moScriptSignatureManager->getSignatureStream()); + } + if (!maSignatureManager.add(aChooser->GetSelectedCertificates()[0], aChooser->GetSelectedSecurityContext(), aChooser->GetDescription(), nSecurityId, m_bAdESCompliant)) return; diff --git a/xmlsecurity/source/helper/UriBindingHelper.cxx b/xmlsecurity/source/helper/UriBindingHelper.cxx index f6c36d2c8b36..4aabca28310f 100644 --- a/xmlsecurity/source/helper/UriBindingHelper.cxx +++ b/xmlsecurity/source/helper/UriBindingHelper.cxx @@ -28,6 +28,8 @@ #include <rtl/uri.hxx> #include <sal/log.hxx> +#include <documentsignaturehelper.hxx> + using namespace com::sun::star; // XUriBinding @@ -36,9 +38,10 @@ UriBindingHelper::UriBindingHelper() { } -UriBindingHelper::UriBindingHelper( const css::uno::Reference < css::embed::XStorage >& rxStorage ) +UriBindingHelper::UriBindingHelper( const css::uno::Reference < css::embed::XStorage >& rxStorage, const uno::Reference<io::XStream>& xScriptingSignatureStream ) { mxStorage = rxStorage; + mxScriptingSignatureStream = xScriptingSignatureStream; } void SAL_CALL UriBindingHelper::setUriBinding( const OUString& /*uri*/, const uno::Reference< io::XInputStream >&) @@ -50,7 +53,7 @@ uno::Reference< io::XInputStream > SAL_CALL UriBindingHelper::getUriBinding( con uno::Reference< io::XInputStream > xInputStream; if ( mxStorage.is() ) { - xInputStream = OpenInputStream( mxStorage, uri ); + xInputStream = OpenInputStream( mxStorage, uri, mxScriptingSignatureStream ); } else { @@ -62,7 +65,7 @@ uno::Reference< io::XInputStream > SAL_CALL UriBindingHelper::getUriBinding( con return xInputStream; } -uno::Reference < io::XInputStream > UriBindingHelper::OpenInputStream( const uno::Reference < embed::XStorage >& rxStore, const OUString& rURI ) +uno::Reference < io::XInputStream > UriBindingHelper::OpenInputStream( const uno::Reference < embed::XStorage >& rxStore, const OUString& rURI, const css::uno::Reference<css::io::XStream>& xScriptingSignatureStream ) { OSL_ASSERT(!rURI.isEmpty()); uno::Reference < io::XInputStream > xInStream; @@ -89,7 +92,23 @@ uno::Reference < io::XInputStream > UriBindingHelper::OpenInputStream( const uno uno::Reference< io::XStream > xStream; if (!rxStore->hasByName(sName)) - SAL_WARN("xmlsecurity.helper", "expected stream, but not found: " << sName); + { + if (xScriptingSignatureStream.is() && sName == DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName()) + { + xStream = xScriptingSignatureStream; + uno::Reference<io::XSeekable> xSeekable(xScriptingSignatureStream, uno::UNO_QUERY); + if (xSeekable.is()) + { + // Cloned streams are always positioned at the start, do the same in the overlay + // case. + xSeekable->seek(0); + } + } + else + { + SAL_WARN("xmlsecurity.helper", "expected stream, but not found: " << sName); + } + } else xStream = rxStore->cloneStreamElement( sName ); if ( !xStream.is() ) @@ -105,7 +124,7 @@ uno::Reference < io::XInputStream > UriBindingHelper::OpenInputStream( const uno OUString aElement = aURI.copy( nSepPos+1 ); uno::Reference < embed::XStorage > xSubStore = rxStore->openStorageElement( aStoreName, embed::ElementModes::READ ); - xInStream = OpenInputStream( xSubStore, aElement ); + xInStream = OpenInputStream( xSubStore, aElement, xScriptingSignatureStream ); } return xInStream; } diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx index 0bc34dcd379b..9ed1cef7dcff 100644 --- a/xmlsecurity/source/helper/documentsignaturemanager.cxx +++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx @@ -435,6 +435,15 @@ bool DocumentSignatureManager::add( std::vector<OUString> aElements = DocumentSignatureHelper::CreateElementList( mxStore, meSignatureMode, DocumentSignatureAlgorithm::OOo3_2); + + if (mxScriptingSignatureStream.is()) + { + aElements.emplace_back( + u"META-INF/"_ustr + + DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName()); + std::sort(aElements.begin(), aElements.end()); + } + DocumentSignatureHelper::AppendContentTypes(mxStore, aElements); for (OUString const& rUri : aElements) diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx index 3b13f79f33f1..6620e33b47a7 100644 --- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx +++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx @@ -71,10 +71,11 @@ XMLSignatureHelper::~XMLSignatureHelper() void XMLSignatureHelper::SetStorage( const Reference < css::embed::XStorage >& rxStorage, - std::u16string_view sODFVersion) + std::u16string_view sODFVersion, + const css::uno::Reference<css::io::XStream>& xScriptStream) { SAL_WARN_IF( mxUriBinding.is(), "xmlsecurity.helper", "SetStorage - UriBinding already set!" ); - mxUriBinding = new UriBindingHelper( rxStorage ); + mxUriBinding = new UriBindingHelper( rxStorage, xScriptStream ); SAL_WARN_IF(!rxStorage.is(), "xmlsecurity.helper", "SetStorage - empty storage!"); mbODFPre1_2 = DocumentSignatureHelper::isODFPre_1_2(sODFVersion); }