diff options
Diffstat (limited to '')
-rw-r--r-- | xmlsecurity/inc/certificatechooser.hxx | 18 | ||||
-rw-r--r-- | xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx | 9 | ||||
-rw-r--r-- | xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_lo242.odt | bin | 0 -> 13599 bytes | |||
-rw-r--r-- | xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odt | bin | 0 -> 19707 bytes | |||
-rw-r--r-- | xmlsecurity/qa/unit/signing/signing.cxx | 5 | ||||
-rw-r--r-- | xmlsecurity/qa/unit/signing/signing2.cxx | 309 | ||||
-rw-r--r-- | xmlsecurity/source/component/documentdigitalsignatures.cxx | 2 | ||||
-rw-r--r-- | xmlsecurity/source/dialogs/certificatechooser.cxx | 3 | ||||
-rw-r--r-- | xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx | 77 | ||||
-rw-r--r-- | xmlsecurity/source/helper/xmlsignaturehelper.cxx | 68 | ||||
-rw-r--r-- | xmlsecurity/source/xmlsec/nss/ciphercontext.cxx | 5 | ||||
-rw-r--r-- | xmlsecurity/source/xmlsec/saxhelper.cxx | 15 |
12 files changed, 476 insertions, 35 deletions
diff --git a/xmlsecurity/inc/certificatechooser.hxx b/xmlsecurity/inc/certificatechooser.hxx index 12303fbf1c..b0cf7c7cdc 100644 --- a/xmlsecurity/inc/certificatechooser.hxx +++ b/xmlsecurity/inc/certificatechooser.hxx @@ -51,8 +51,6 @@ enum class UserAction class CertificateChooser final : public weld::GenericDialogController { private: - static inline CertificateChooser* mxInstance = nullptr; - std::vector< css::uno::Reference< css::xml::crypto::XXMLSecurityContext > > mxSecurityContexts; std::vector<std::shared_ptr<UserData>> mvUserData; @@ -91,14 +89,18 @@ public: UserAction eAction); virtual ~CertificateChooser() override; - static CertificateChooser* getInstance(weld::Window* _pParent, + static std::unique_ptr<CertificateChooser> getInstance(weld::Window* _pParent, std::vector< css::uno::Reference< css::xml::crypto::XXMLSecurityContext > > && rxSecurityContexts, UserAction eAction) { - if (!mxInstance) - { - mxInstance = new CertificateChooser(_pParent, std::move(rxSecurityContexts), eAction); - } - return mxInstance; + // Don't reuse CertificateChooser instances + // Reusing the same instance will, in the following case, lead to a + // crash. It appears that the CertificateChooser is getting disposed + // somewhere as mpDialogImpl in its base class ends up being null: + // 1. Create an empty Writer document and add a digital signature + // in the Digital Signatures dialog + // 2. File > Save As the document, check the "Encrypt with GPG key" + // checkbox, press Encrypt, and crash in Dialog::ImplStartExecute() + return std::make_unique<CertificateChooser>(_pParent, std::move(rxSecurityContexts), eAction); } short run() override; diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index 0196a4707b..46981b250a 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -63,7 +63,6 @@ protected: public: PDFSigningTest(); void setUp() override; - void tearDown() override; }; PDFSigningTest::PDFSigningTest() {} @@ -71,7 +70,7 @@ PDFSigningTest::PDFSigningTest() {} void PDFSigningTest::setUp() { test::BootstrapFixture::setUp(); - MacrosTest::setUpNssGpg(m_directories, "xmlsecurity_pdfsigning"); + MacrosTest::setUpX509(m_directories, "xmlsecurity_pdfsigning"); uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext); @@ -86,12 +85,6 @@ void PDFSigningTest::setUp() #endif } -void PDFSigningTest::tearDown() -{ - MacrosTest::tearDownNssGpg(); - test::BootstrapFixture::tearDown(); -} - std::vector<SignatureInformation> PDFSigningTest::verify(const OUString& rURL, size_t nCount) { uno::Reference<xml::crypto::XSEInitializer> xSEInitializer diff --git a/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_lo242.odt b/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_lo242.odt Binary files differnew file mode 100644 index 0000000000..1747448ac5 --- /dev/null +++ b/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_lo242.odt diff --git a/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odt b/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odt Binary files differnew file mode 100644 index 0000000000..fb2b978bc0 --- /dev/null +++ b/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odt diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx index 9f449d26d6..316eaf22f5 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -92,7 +92,8 @@ void SigningTest::setUp() { UnoApiXmlTest::setUp(); - MacrosTest::setUpNssGpg(m_directories, "xmlsecurity_signing"); + MacrosTest::setUpX509(m_directories, "xmlsecurity_signing"); + MacrosTest::setUpGpg(m_directories, "xmlsecurity_signing"); // Initialize crypto after setting up the environment variables. mxSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext); @@ -108,7 +109,7 @@ void SigningTest::setUp() void SigningTest::tearDown() { - MacrosTest::tearDownNssGpg(); + MacrosTest::tearDownGpg(); UnoApiXmlTest::tearDown(); } diff --git a/xmlsecurity/qa/unit/signing/signing2.cxx b/xmlsecurity/qa/unit/signing/signing2.cxx index aef3c7f088..50baa98223 100644 --- a/xmlsecurity/qa/unit/signing/signing2.cxx +++ b/xmlsecurity/qa/unit/signing/signing2.cxx @@ -9,14 +9,27 @@ #include <sal/config.h> +#include <config_crypto.h> + +#if USE_CRYPTO_NSS +#include <secoid.h> +#endif + #include <test/unoapixml_test.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/embed/XStorage.hpp> #include <com/sun/star/frame/Desktop.hpp> #include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/text/XTextDocument.hpp> #include <com/sun/star/util/XCloseable.hpp> #include <com/sun/star/xml/crypto/SEInitializer.hpp> +#include <officecfg/Office/Common.hxx> + +#include <sfx2/sfxbasemodel.hxx> +#include <sfx2/objsh.hxx> +#include <comphelper/documentconstants.hxx> #include <comphelper/propertysequence.hxx> #include <unotools/tempfile.hxx> #include <unotools/ucbstreamhelper.hxx> @@ -30,8 +43,14 @@ using namespace css; /// Testsuite for the document signing feature. class SigningTest2 : public UnoApiXmlTest { +protected: + uno::Reference<xml::crypto::XSEInitializer> mxSEInitializer; + uno::Reference<xml::crypto::XXMLSecurityContext> mxSecurityContext; + public: SigningTest2(); + virtual void setUp() override; + virtual void tearDown() override; void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override; }; @@ -40,6 +59,32 @@ SigningTest2::SigningTest2() { } +void SigningTest2::setUp() +{ + UnoApiXmlTest::setUp(); + + MacrosTest::setUpX509(m_directories, "xmlsecurity_signing2"); + MacrosTest::setUpGpg(m_directories, "xmlsecurity_signing2"); + + // Initialize crypto after setting up the environment variables. + mxSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext); + mxSecurityContext = mxSEInitializer->createSecurityContext(OUString()); +#if USE_CRYPTO_NSS +#ifdef NSS_USE_ALG_IN_ANY_SIGNATURE + // policy may disallow using SHA1 for signatures but unit test documents + // have such existing signatures (call this after createSecurityContext!) + NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_ANY_SIGNATURE, 0); +#endif +#endif +} + +void SigningTest2::tearDown() +{ + MacrosTest::tearDownGpg(); + + UnoApiXmlTest::tearDown(); +} + /// Test if a macro signature from a ODF Database is preserved when saving CPPUNIT_TEST_FIXTURE(SigningTest2, testPreserveMacroSignatureODB) { @@ -66,6 +111,263 @@ CPPUNIT_TEST_FIXTURE(SigningTest2, testPreserveMacroSignatureODB) "ID_00a7002f009000bc00ce00f7004400460080002f002e00e400e0003700df00e8"); } +CPPUNIT_TEST_FIXTURE(SigningTest2, testPasswordPreserveMacroSignatureODF13) +{ + // load ODF 1.3 encrypted document + load(createFileURL(u"encrypted_scriptsig_odf13.odt"), "password"); + { + uno::Reference<text::XTextDocument> xTextDoc(mxComponent, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(OUString("secret"), xTextDoc->getText()->getString()); + // test macro signature + SfxBaseModel* pBaseModel(dynamic_cast<SfxBaseModel*>(mxComponent.get())); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell(pBaseModel->GetObjectShell()); + uno::Reference<beans::XPropertySet> xPropSet(pObjectShell->GetStorage(), + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(ODFVER_013_TEXT, + xPropSet->getPropertyValue("Version").get<OUString>()); + CPPUNIT_ASSERT_EQUAL(SignatureState::OK, pObjectShell->GetScriptingSignatureState()); + } + + saveAndReload("writer8", "password"); + { + // test standard ODF 1.2/1.3/1.4 encryption + xmlDocUniquePtr pXmlDoc = parseExport("META-INF/manifest.xml"); + assertXPath(pXmlDoc, "/manifest:manifest"_ostr, "version"_ostr, "1.3"); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry[@manifest:size != '0']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data[@manifest:checksum-type and @manifest:checksum]"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[@manifest:algorithm-name='http://www.w3.org/2001/04/xmlenc#aes256-cbc']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[string-length(@manifest:initialisation-vector) = 24]"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:start-key-generation[@manifest:start-key-generation-name='http://www.w3.org/2000/09/xmldsig#sha256' and @manifest:key-size='32']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:key-derivation-name='PBKDF2' and @manifest:key-size='32']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:iteration-count='100000']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[string-length(@manifest:salt) = 24]"_ostr, + 8); + // test reimport + uno::Reference<text::XTextDocument> xTextDoc(mxComponent, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(OUString("secret"), xTextDoc->getText()->getString()); + // test macro signature - this didn't actually work! + // using Zip Storage means the encrypted streams are signed, so + // after encrypting again the sigature didn't match and was dropped + // assertDocument(CPPUNIT_SOURCELINE(), "writer8", SignatureState::NOSIGNATURES, + // SignatureState::OK, ODFVER_013_TEXT); + } + + { + Resetter resetter([]() { + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::ExperimentalMode::set(false, pBatch); + return pBatch->commit(); + }); + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::ExperimentalMode::set(true, pBatch); + pBatch->commit(); + + // store it experimental - reload + saveAndReload("writer8", "password"); + + // test wholesome ODF extended encryption + xmlDocUniquePtr pXmlDoc = parseExport("META-INF/manifest.xml"); + assertXPath(pXmlDoc, "/manifest:manifest"_ostr, "version"_ostr, "1.3"); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry"_ostr, 1); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry"_ostr, "full-path"_ostr, + "encrypted-package"); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry[@manifest:size != '0']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data[@manifest:checksum-type or @manifest:checksum]"_ostr, + 0); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[@manifest:algorithm-name='http://www.w3.org/2009/xmlenc11#aes256-gcm']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[string-length(@manifest:initialisation-vector) = 16]"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:start-key-generation[@manifest:start-key-generation-name='http://www.w3.org/2001/04/xmlenc#sha256' and @manifest:key-size='32']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:key-derivation-name='urn:org:documentfoundation:names:experimental:office:manifest:argon2id' and @manifest:key-size='32']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:iteration-count]"_ostr, + 0); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[string-length(@manifest:salt) = 24]"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@loext:argon2-iterations='3' and @loext:argon2-memory='65536' and @loext:argon2-lanes='4']"_ostr, + 1); + // test reimport + uno::Reference<text::XTextDocument> xTextDoc(mxComponent, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(OUString("secret"), xTextDoc->getText()->getString()); + } +} + +CPPUNIT_TEST_FIXTURE(SigningTest2, testPasswordPreserveMacroSignatureODFWholesomeLO242) +{ + // load wholesome ODF (extended) encrypted document + load(createFileURL(u"encrypted_scriptsig_lo242.odt"), "password"); + { + uno::Reference<text::XTextDocument> xTextDoc(mxComponent, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(OUString("secret"), xTextDoc->getText()->getString()); + // test macro signature + SfxBaseModel* pBaseModel(dynamic_cast<SfxBaseModel*>(mxComponent.get())); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell(pBaseModel->GetObjectShell()); + uno::Reference<beans::XPropertySet> xPropSet(pObjectShell->GetStorage(), + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(ODFVER_013_TEXT, + xPropSet->getPropertyValue("Version").get<OUString>()); + CPPUNIT_ASSERT_EQUAL(SignatureState::OK, pObjectShell->GetScriptingSignatureState()); + } + + { + Resetter resetter([]() { + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::ExperimentalMode::set(false, pBatch); + return pBatch->commit(); + }); + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::ExperimentalMode::set(true, pBatch); + pBatch->commit(); + + // store it experimental - reload + saveAndReload("writer8", "password"); + + // test wholesome ODF extended encryption + xmlDocUniquePtr pXmlDoc = parseExport("META-INF/manifest.xml"); + assertXPath(pXmlDoc, "/manifest:manifest"_ostr, "version"_ostr, "1.3"); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry"_ostr, 1); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry"_ostr, "full-path"_ostr, + "encrypted-package"); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry[@manifest:size != '0']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data[@manifest:checksum-type or @manifest:checksum]"_ostr, + 0); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[@manifest:algorithm-name='http://www.w3.org/2009/xmlenc11#aes256-gcm']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[string-length(@manifest:initialisation-vector) = 16]"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:start-key-generation[@manifest:start-key-generation-name='http://www.w3.org/2001/04/xmlenc#sha256' and @manifest:key-size='32']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:key-derivation-name='urn:org:documentfoundation:names:experimental:office:manifest:argon2id' and @manifest:key-size='32']"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:iteration-count]"_ostr, + 0); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[string-length(@manifest:salt) = 24]"_ostr, + 1); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@loext:argon2-iterations='3' and @loext:argon2-memory='65536' and @loext:argon2-lanes='4']"_ostr, + 1); + // test reimport + uno::Reference<text::XTextDocument> xTextDoc(mxComponent, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(OUString("secret"), xTextDoc->getText()->getString()); + // test macro signature - this should work now + SfxBaseModel* pBaseModel(dynamic_cast<SfxBaseModel*>(mxComponent.get())); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell(pBaseModel->GetObjectShell()); + uno::Reference<beans::XPropertySet> xPropSet(pObjectShell->GetStorage(), + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(ODFVER_013_TEXT, + xPropSet->getPropertyValue("Version").get<OUString>()); + CPPUNIT_ASSERT_EQUAL(SignatureState::OK, pObjectShell->GetScriptingSignatureState()); + } + + saveAndReload("writer8", "password"); + { + // test standard ODF 1.2/1.3/1.4 encryption + xmlDocUniquePtr pXmlDoc = parseExport("META-INF/manifest.xml"); + assertXPath(pXmlDoc, "/manifest:manifest"_ostr, "version"_ostr, "1.3"); + assertXPath(pXmlDoc, "/manifest:manifest/manifest:file-entry[@manifest:size != '0']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data[@manifest:checksum-type and @manifest:checksum]"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[@manifest:algorithm-name='http://www.w3.org/2001/04/xmlenc#aes256-cbc']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:algorithm[string-length(@manifest:initialisation-vector) = 24]"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:start-key-generation[@manifest:start-key-generation-name='http://www.w3.org/2000/09/xmldsig#sha256' and @manifest:key-size='32']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:key-derivation-name='PBKDF2' and @manifest:key-size='32']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[@manifest:iteration-count='100000']"_ostr, + 8); + assertXPath( + pXmlDoc, + "/manifest:manifest/manifest:file-entry/manifest:encryption-data/manifest:key-derivation[string-length(@manifest:salt) = 24]"_ostr, + 8); + // test reimport + uno::Reference<text::XTextDocument> xTextDoc(mxComponent, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(OUString("secret"), xTextDoc->getText()->getString()); + // test macro signature - this didn't actually work! + // using Zip Storage means the encrypted streams are signed, so + // after encrypting again the sigature didn't match and was dropped + // assertDocument(CPPUNIT_SOURCELINE(), "writer8", SignatureState::NOSIGNATURES, + // SignatureState::OK, ODFVER_013_TEXT); + } +} + void SigningTest2::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) { xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("odfds"), @@ -73,6 +375,13 @@ void SigningTest2::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dsig"), BAD_CAST("http://www.w3.org/2000/09/xmldsig#")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xd"), BAD_CAST("http://uri.etsi.org/01903/v1.3.2#")); + + // manifest.xml + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("manifest"), + BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0")); + xmlXPathRegisterNs( + pXmlXpathCtx, BAD_CAST("loext"), + BAD_CAST("urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0")); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index 4ad63b36ed..c1768c0e95 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -709,7 +709,7 @@ DocumentDigitalSignatures::chooseCertificatesImpl(std::map<OUString, OUString>& xSecContexts.push_back(aSignatureManager.getGpgSecurityContext()); } - CertificateChooser* aChooser = CertificateChooser::getInstance(Application::GetFrameWeld(mxParentWindow), std::move(xSecContexts), eAction); + std::unique_ptr<CertificateChooser> aChooser = CertificateChooser::getInstance(Application::GetFrameWeld(mxParentWindow), std::move(xSecContexts), eAction); if (aChooser->run() != RET_OK) return { Reference< css::security::XCertificate >(nullptr) }; diff --git a/xmlsecurity/source/dialogs/certificatechooser.cxx b/xmlsecurity/source/dialogs/certificatechooser.cxx index 9dba3e9e90..7305490933 100644 --- a/xmlsecurity/source/dialogs/certificatechooser.cxx +++ b/xmlsecurity/source/dialogs/certificatechooser.cxx @@ -56,7 +56,6 @@ CertificateChooser::CertificateChooser(weld::Window* _pParent, { auto nControlWidth = m_xCertLB->get_approximate_digit_width() * 105; m_xCertLB->set_size_request(nControlWidth, m_xCertLB->get_height_rows(12)); - m_xCertLB->make_sorted(); m_xCertLB->connect_changed( LINK( this, CertificateChooser, CertificateHighlightHdl ) ); m_xCertLB->connect_row_activated( LINK( this, CertificateChooser, CertificateSelectHdl ) ); @@ -136,6 +135,7 @@ void CertificateChooser::ImplInitialize(bool mbSearch) return; m_xCertLB->clear(); + m_xCertLB->make_unsorted(); m_xCertLB->freeze(); SvtUserOptions aUserOpts; @@ -257,6 +257,7 @@ void CertificateChooser::ImplInitialize(bool mbSearch) m_xCertLB->thaw(); m_xCertLB->unselect_all(); + m_xCertLB->make_sorted(); if (oSelectRow) { diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx index 3cd13c6060..8349a58a31 100644 --- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx +++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx @@ -74,6 +74,10 @@ #include <Shlobj.h> #endif +#if defined MACOSX +#include <sys/stat.h> +#endif + using namespace comphelper; using namespace css::security; using namespace css::uno; @@ -121,6 +125,12 @@ namespace u"GNU\\GnuPG\\bin\\kleopatra.exe", u"GNU\\GnuPG\\bin\\launch-gpa.exe", u"GNU\\GnuPG\\bin\\gpa.exe"}; +#elif defined MACOSX + constexpr std::u16string_view aGUIServers[] + = { u"/Applications/GPG Keychain.app", + u"/Applications/Trusted Key Manager.app", // tdf#147291 + u"/Applications/SCinterface/scManager.app", // tdf#147291 + u"/System/Applications/Utilities/Keychain Access.app"}; #else constexpr std::u16string_view aGUIServers[] = { u"kleopatra", u"seahorse", u"gpa", u"kgpg"}; @@ -154,26 +164,55 @@ void GetCertificateManager(OUString& sExecutable) OUString aCetMgrConfig = officecfg::Office::Common::Security::Scripting::CertMgrPath::get(); if (!aCetMgrConfig.isEmpty()) { + if (aCetMgrConfig.indexOf('/') != -1 #ifdef _WIN32 - sal_Int32 nLastBackslashIndex = aCetMgrConfig.lastIndexOf('\\'); -#else - sal_Int32 nLastBackslashIndex = aCetMgrConfig.lastIndexOf('/'); + || aCetMgrConfig.indexOf('\\') != -1 #endif + ) + { + sExecutable = aCetMgrConfig; + return; + } osl::FileBase::RC searchError = osl::File::searchFileURL( - aCetMgrConfig.copy(0, nLastBackslashIndex + 1), aPath, + aCetMgrConfig, aPath, aFoundGUIServer); if (searchError == osl::FileBase::E_None) + { + osl::File::getSystemPathFromFileURL(aFoundGUIServer, sExecutable); return; + } } for (const auto& rServer: aGUIServers) { - osl::FileBase::RC searchError = osl::File::searchFileURL( - OUString(rServer), aPath, - aFoundGUIServer); - if (searchError == osl::FileBase::E_None) + bool bSetCertMgrPath = false; + +#ifdef MACOSX + // On macOS, the list of default certificate manager applications + // includes absolute paths so check if the path exists and is a + // directory + if (rServer.starts_with('/')) + { + OString aSysPath = OUString(rServer).toUtf8(); + if (struct stat st; stat(aSysPath.getStr(), &st) == 0 && S_ISDIR(st.st_mode)) + { + bSetCertMgrPath = true; + sExecutable = rServer; + } + } +#endif + + if (!bSetCertMgrPath) + { + osl::FileBase::RC searchError = osl::File::searchFileURL( + OUString(rServer), aPath, + aFoundGUIServer); + if (searchError == osl::FileBase::E_None && osl::File::getSystemPathFromFileURL(aFoundGUIServer, sExecutable) == osl::FileBase::E_None) + bSetCertMgrPath = true; + } + + if (bSetCertMgrPath) { - osl::File::getSystemPathFromFileURL(aFoundGUIServer, sExecutable); std::shared_ptr<comphelper::ConfigurationChanges> pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Security::Scripting::CertMgrPath::set(sExecutable, @@ -470,7 +509,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, weld::Button&, void) if (DocumentSignatureHelper::CanSignWithGPG(maSignatureManager.getStore(), m_sODFVersion)) xSecContexts.push_back(maSignatureManager.getGpgSecurityContext()); - CertificateChooser* aChooser = CertificateChooser::getInstance(m_xDialog.get(), std::move(xSecContexts), UserAction::Sign); + std::unique_ptr<CertificateChooser> aChooser = CertificateChooser::getInstance(m_xDialog.get(), std::move(xSecContexts), UserAction::Sign); if (aChooser->run() == RET_OK) { sal_Int32 nSecurityId; @@ -551,8 +590,22 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, CertMgrButtonHdl, weld::Button&, void) uno::Reference<css::system::XSystemShellExecute> xSystemShell( css::system::SystemShellExecute::create(xContext)); - xSystemShell->execute(sExecutable, OUString(), - css::system::SystemShellExecuteFlags::DEFAULTS); + try + { + xSystemShell->execute(sExecutable, OUString(), + css::system::SystemShellExecuteFlags::DEFAULTS); + } + catch (...) + { + // Related tdf#159307 fix uncloseable windows due to uncaught exception + // XSystemShellExecute::execute() throws an exception for a variety + // of common error conditions such as files or directories that + // are non-existent or non-executable. Failure to catch such + // exceptions would cause the document window to be uncloseable + // and the application to be unquittable. + TOOLS_WARN_EXCEPTION( "xmlsecurity.dialogs", "executable failed!" ); + sExecutable = OUString(); + } } OUString sDialogText = (sExecutable.isEmpty() ? diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx index 0b5825b125..3b13f79f33 100644 --- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx +++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx @@ -22,6 +22,7 @@ #include <documentsignaturehelper.hxx> #include <xsecctl.hxx> #include <biginteger.hxx> +#include <certificate.hxx> #include <UriBindingHelper.hxx> @@ -702,7 +703,72 @@ XMLSignatureHelper::CheckAndUpdateSignatureInformation( } if (CheckX509Data(xSecEnv, temp, certs, tempResult)) { - datas.emplace_back(tempResult); + if (rInfo.maEncapsulatedX509Certificates.empty()) // optional, XAdES + { + datas.emplace_back(tempResult); + } + else + { + // check for consistency between X509Data and EncapsulatedX509Certificate + // (LO produces just the signing certificate in X509Data and + // the entire chain in EncapsulatedX509Certificate so in this case + // using EncapsulatedX509Certificate yields additional intermediate + // certificates that may help in verifying) + std::vector<SignatureInformation::X509CertInfo> encapsulatedCertInfos; + for (OUString const& it : rInfo.maEncapsulatedX509Certificates) + { + encapsulatedCertInfos.emplace_back(); + encapsulatedCertInfos.back().X509Certificate = it; + } + std::vector<uno::Reference<security::XCertificate>> encapsulatedCerts; + SignatureInformation::X509Data encapsulatedResult; + if (CheckX509Data(xSecEnv, encapsulatedCertInfos, encapsulatedCerts, encapsulatedResult)) + { + auto const pXCertificate(dynamic_cast<xmlsecurity::Certificate*>(certs.back().get())); + auto const pECertificate(dynamic_cast<xmlsecurity::Certificate*>(encapsulatedCerts.back().get())); + assert(pXCertificate && pECertificate); // was just created by CheckX509Data + if (pXCertificate->getSHA256Thumbprint() == pECertificate->getSHA256Thumbprint()) + { + // both are chains - take the longer one + if (encapsulatedCerts.size() < certs.size()) + { + datas.emplace_back(tempResult); + } + else + { +#if 0 + // extra info needed in testSigningMultipleTimes_ODT + // ... but with it, it fails with BROKEN signature? + // fails even on the first signature, because somehow + // the xd:SigningCertificate element was signed + // containing only one certificate, but in the final + // file it contains all 3 certificates due to this here. + for (size_t i = 0; i < encapsulatedResult.size(); ++i) + { + encapsulatedResult[i].X509IssuerName = encapsulatedCerts[i]->getIssuerName(); + encapsulatedResult[i].X509SerialNumber = xmlsecurity::bigIntegerToNumericString(encapsulatedCerts[i]->getSerialNumber()); + encapsulatedResult[i].X509Subject = encapsulatedCerts[i]->getSubjectName(); + auto const pCertificate(dynamic_cast<xmlsecurity::Certificate*>(encapsulatedCerts[i].get())); + assert(pCertificate); // this was just created by CheckX509Data + OUStringBuffer aBuffer; + comphelper::Base64::encode(aBuffer, pCertificate->getSHA256Thumbprint()); + encapsulatedResult[i].CertDigest = aBuffer.makeStringAndClear(); + } + datas.emplace_back(encapsulatedResult); +#else + // keep the X509Data stuff in datas but return the + // longer EncapsulatedX509Certificate chain + datas.emplace_back(tempResult); +#endif + certs = encapsulatedCerts; // overwrite this seems easier + } + } + else + { + SAL_WARN("xmlsecurity.comp", "X509Data and EncapsulatedX509Certificate contain different certificates"); + } + } + } } // rInfo is a copy, update the original diff --git a/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx b/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx index c3bbfdb0f2..e5f2a89d11 100644 --- a/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx +++ b/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx @@ -326,7 +326,10 @@ uno::Sequence< ::sal_Int8 > SAL_CALL OCipherContext::finalizeCipherContextAndDis if ( nPaddingSize > 1 ) { rtlRandomPool aRandomPool = rtl_random_createPool(); - rtl_random_getBytes( aRandomPool, pLastBlock + nOldLastBlockLen, nPaddingSize - 1 ); + if (rtl_random_getBytes(aRandomPool, pLastBlock + nOldLastBlockLen, nPaddingSize - 1) != rtl_Random_E_None) + { + throw uno::RuntimeException("rtl_random_getBytes failed"); + } rtl_random_destroyPool ( aRandomPool ); } pLastBlock[m_aLastBlock.getLength() - 1] = static_cast< sal_Int8 >( nPaddingSize ); diff --git a/xmlsecurity/source/xmlsec/saxhelper.cxx b/xmlsecurity/source/xmlsec/saxhelper.cxx index ff576db496..0d39584894 100644 --- a/xmlsecurity/source/xmlsec/saxhelper.cxx +++ b/xmlsecurity/source/xmlsec/saxhelper.cxx @@ -118,11 +118,24 @@ SAXHelper::SAXHelper( ) * compile error: * xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS ; */ +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) +#endif xmlSubstituteEntitiesDefault(0) ; - #ifndef XMLSEC_NO_XSLT xmlIndentTreeOutput = 1 ; #endif /* XMLSEC_NO_XSLT */ +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif m_pParserCtxt = xmlNewParserCtxt() ; |