include/sfx2/digitalsignatures.hxx | 7 + offapi/com/sun/star/security/XDocumentDigitalSignatures.idl | 4 sfx2/source/doc/docfile.cxx | 15 ++- xmlsecurity/inc/documentsignaturemanager.hxx | 2 xmlsecurity/source/component/documentdigitalsignatures.cxx | 49 +++++++----- xmlsecurity/source/helper/documentsignaturemanager.cxx | 31 +++++++ 6 files changed, 82 insertions(+), 26 deletions(-)
New commits: commit b46628863a68a5239aeae06298f9675193009644 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Sep 10 10:11:54 2024 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Sep 12 11:29:38 2024 +0200 cool#9992 lok doc sign: async DocumentDigitalSignatures::ImplViewSignatures() Currently SfxObjectShell::CheckIsReadonly() has a hack for the LOK case to show the signatures dialog read-only, as only that is async. The next step is to make DocumentDigitalSignatures::ImplViewSignatures() async, though that requires all callers of the function to be async, so make DocumentDigitalSignatures::signScriptingContent() async as well. There is also DocumentDigitalSignatures::signPackage(), but turns out that's dead code, so just remove it. Once this is in place, we had a problem that the callbacks tried to interact with libxmlsec, but the dialog was still alive in DocumentDigitalSignatures::ImplViewSignatures() by the time the callback was running, so there were two DocumentSignatureManager instances at the same time, and both assumes it should call the global libxmlsec init/uninit, which resulted in failing to verify the just created signature. Fix this similar to how Tomaz fixed the same problem around pdfium in commit 067a8a954c8e1d8d6465a4ab5fb61e93f16c26c2 (pdfium: only init pdfium library one and destroy on LO exit, 2020-06-03). (cherry picked from commit 07df95e75a728fbbce03f6d6efdf9dbceab6c581) Change-Id: I3fb63c06195564732e1576dbd755157e676fb762 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173156 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/include/sfx2/digitalsignatures.hxx b/include/sfx2/digitalsignatures.hxx index bb0abd6e54e3..b364c9518931 100644 --- a/include/sfx2/digitalsignatures.hxx +++ b/include/sfx2/digitalsignatures.hxx @@ -38,6 +38,13 @@ public: const std::function<void(bool)>& rCallback) = 0; + /// Async replacement for signScriptingContent(). + virtual void + SignScriptingContentAsync(const css::uno::Reference<css::embed::XStorage>& rxStorage, + const css::uno::Reference<css::io::XStream>& xSignStream, + const std::function<void(bool)>& rCallback) + = 0; + protected: ~DigitalSignatures() noexcept = default; }; diff --git a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl index 58dfe915ba10..195a940894f4 100644 --- a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl +++ b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl @@ -78,6 +78,8 @@ interface XDocumentDigitalSignatures : com::sun::star::uno::XInterface /** signs the content of the Scripting including macros and basic dialogs <p>The rest of document content will not be signed.</p> + + Deprecated, this synchronous version would block the UI till signing is in progress. */ boolean signScriptingContent( [in] ::com::sun::star::embed::XStorage xStorage, [in] ::com::sun::star::io::XStream xSignStream); @@ -102,6 +104,8 @@ interface XDocumentDigitalSignatures : com::sun::star::uno::XInterface string getScriptingContentSignatureDefaultStreamName(); /** signs the full Package, which means everything in the storage except the content of META-INF + + Deprecated, this synchronous version would block the UI till signing is in progress. */ boolean signPackage( [in] ::com::sun::star::embed::XStorage Storage, [in] ::com::sun::star::io::XStream xSignStream); diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index 2b7a1fb82453..79f89d17cb63 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -4382,6 +4382,8 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, throw uno::RuntimeException(); } + auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get()); + assert(xModelSigner); if ( bSignScriptingContent ) { // If the signature has already the document signature it will be removed @@ -4395,8 +4397,10 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, // xWriteableZipStor because a writable storage can't have 2 // instances of sub-storage for the same directory open, but with // independent storages it somehow works - if (xSigner->signScriptingContent(GetScriptingStorageToSign_Impl(), xStream)) - { + xModelSigner->SignScriptingContentAsync( + GetScriptingStorageToSign_Impl(), xStream, + [this, xSigner, xMetaInf, xWriteableZipStor, + onSignDocumentContentFinished](bool bRet) { // remove the document signature if any OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName(); if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( aDocSigName ) ) @@ -4423,13 +4427,12 @@ void SfxMedium::SignContents_Impl(weld::Window* pDialogParent, || !uno::Reference<util::XModifiable>(pImpl->xStorage, uno::UNO_QUERY_THROW)->isModified()); // the temporary file has been written, commit it to the original file Commit(); - bChanges = true; - } + onSignDocumentContentFinished(bRet); + }); + return; } else { - auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get()); - assert(xModelSigner); if (xMetaInf.is()) { // ODF. diff --git a/xmlsecurity/inc/documentsignaturemanager.hxx b/xmlsecurity/inc/documentsignaturemanager.hxx index ab89e5b96674..9f0c5d61f9e2 100644 --- a/xmlsecurity/inc/documentsignaturemanager.hxx +++ b/xmlsecurity/inc/documentsignaturemanager.hxx @@ -54,6 +54,7 @@ class XComponentContext; } } class PDFSignatureHelper; +class Xmlsec; /// Manages signatures (addition, removal), used by DigitalSignaturesDialog. class XMLSECURITY_DLLPUBLIC DocumentSignatureManager @@ -75,6 +76,7 @@ private: css::uno::Reference<css::xml::crypto::XXMLSecurityContext> mxSecurityContext; css::uno::Reference<css::xml::crypto::XSEInitializer> mxGpgSEInitializer; css::uno::Reference<css::xml::crypto::XXMLSecurityContext> mxGpgSecurityContext; + std::shared_ptr<Xmlsec> mpXmlsecLibrary; public: DocumentSignatureManager(const css::uno::Reference<css::uno::XComponentContext>& xContext, diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index 7d4c96e78679..e498bd7c2dcc 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -89,9 +89,10 @@ private: bool m_bHasDocumentSignature; /// @throws css::uno::RuntimeException - bool ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& rxStorage, + void ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& rxStorage, const css::uno::Reference<css::io::XStream>& xSignStream, - DocumentSignatureMode eMode, bool bReadOnly); + DocumentSignatureMode eMode, bool bReadOnly, + const std::function<void(bool)>& rCallback); /// @throws css::uno::RuntimeException void ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& rxStorage, const css::uno::Reference<css::io::XInputStream>& xSignStream, @@ -221,6 +222,10 @@ public: void SignDocumentContentAsync(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::SignScriptingContentAsync(). + 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; }; } @@ -359,12 +364,10 @@ OUString DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName } sal_Bool DocumentDigitalSignatures::signScriptingContent( - const Reference< css::embed::XStorage >& rxStorage, - const Reference< css::io::XStream >& xSignStream ) + const Reference< css::embed::XStorage >& /*rxStorage*/, + const Reference< css::io::XStream >& /*xSignStream*/ ) { - OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); - OSL_ENSURE(m_nArgumentsCount == 2, "DocumentDigitalSignatures: Service was not initialized properly"); - return ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Macros, false ); + for (;;) { std::abort(); } // avoid "must return a value" warnings } Sequence< css::security::DocumentSignatureInformation > @@ -391,11 +394,10 @@ OUString DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamNam sal_Bool DocumentDigitalSignatures::signPackage( - const Reference< css::embed::XStorage >& rxStorage, - const Reference< css::io::XStream >& xSignStream ) + const Reference< css::embed::XStorage >& /*rxStorage*/, + const Reference< css::io::XStream >& /*xSignStream*/ ) { - OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); - return ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Package, false ); + for (;;) { std::abort(); } // avoid "must return a value" warnings } Sequence< css::security::DocumentSignatureInformation > @@ -429,12 +431,12 @@ void DocumentDigitalSignatures::ImplViewSignatures( Reference< io::XStream > xStream; if ( xSignStream.is() ) xStream.set( xSignStream, UNO_QUERY ); - ImplViewSignatures( rxStorage, xStream, eMode, bReadOnly ); + ImplViewSignatures( rxStorage, xStream, eMode, bReadOnly, [](bool /*bSuccess*/){} ); } -bool DocumentDigitalSignatures::ImplViewSignatures( +void DocumentDigitalSignatures::ImplViewSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XStream >& xSignStream, - DocumentSignatureMode eMode, bool bReadOnly ) + DocumentSignatureMode eMode, bool bReadOnly, const std::function<void(bool)>& rCallback ) { bool bChanges = false; auto xSignaturesDialog = std::make_shared<DigitalSignaturesDialog>( @@ -452,7 +454,8 @@ bool DocumentDigitalSignatures::ImplViewSignatures( { xSignaturesDialog->beforeRun(); weld::DialogController::runAsync(xSignaturesDialog, [] (sal_Int32) {}); - return false; + rCallback(false); + return; } else if (xSignaturesDialog->run() == RET_OK) { @@ -466,6 +469,8 @@ bool DocumentDigitalSignatures::ImplViewSignatures( xTrans->commit(); } } + rCallback(bChanges); + return; } } else @@ -476,7 +481,7 @@ bool DocumentDigitalSignatures::ImplViewSignatures( xBox->run(); } - return bChanges; + rCallback(bChanges); } Sequence< css::security::DocumentSignatureInformation > @@ -838,8 +843,16 @@ void DocumentDigitalSignatures::SignDocumentContentAsync(const css::uno::Referen const std::function<void(bool)>& rCallback) { OSL_ENSURE(!m_sODFVersion.isEmpty(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); - bool bRet = ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Content, false ); - rCallback(bRet); + ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Content, false, rCallback ); +} + +void DocumentDigitalSignatures::SignScriptingContentAsync( + const Reference<css::embed::XStorage>& rxStorage, + const Reference<css::io::XStream>& xSignStream, const std::function<void(bool)>& rCallback) +{ + OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); + OSL_ENSURE(m_nArgumentsCount == 2, "DocumentDigitalSignatures: Service was not initialized properly"); + ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Macros, false, rCallback ); } sal_Bool DocumentDigitalSignatures::signPackageWithCertificate( diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx index 80d74c27ba53..0bc34dcd379b 100644 --- a/xmlsecurity/source/helper/documentsignaturemanager.cxx +++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx @@ -56,6 +56,33 @@ using namespace css; using namespace css::graphic; using namespace css::uno; +/// RAII class to init / shut down libxmlsec. +class Xmlsec +{ +public: + Xmlsec(); + ~Xmlsec(); +}; + +Xmlsec::Xmlsec() { initXmlSec(); } + +Xmlsec::~Xmlsec() { deInitXmlSec(); } + +namespace +{ +/// Shared access to libxmlsec, to avoid double init. +struct XmlsecLibrary +{ + static std::shared_ptr<Xmlsec>& get(); +}; + +std::shared_ptr<Xmlsec>& XmlsecLibrary::get() +{ + static std::shared_ptr<Xmlsec> pInstance = std::make_shared<Xmlsec>(); + return pInstance; +} +} + DocumentSignatureManager::DocumentSignatureManager( const uno::Reference<uno::XComponentContext>& xContext, DocumentSignatureMode eMode) : mxContext(xContext) @@ -64,7 +91,7 @@ DocumentSignatureManager::DocumentSignatureManager( { } -DocumentSignatureManager::~DocumentSignatureManager() { deInitXmlSec(); } +DocumentSignatureManager::~DocumentSignatureManager() { mpXmlsecLibrary.reset(); } bool DocumentSignatureManager::init() { @@ -76,7 +103,7 @@ bool DocumentSignatureManager::init() "DocumentSignatureManager::Init - mxGpgSEInitializer already set!"); // xmlsec is needed by both services, so init before those - initXmlSec(); + mpXmlsecLibrary = XmlsecLibrary::get(); mxSEInitializer = xml::crypto::SEInitializer::create(mxContext); #if HAVE_FEATURE_GPGME