summaryrefslogtreecommitdiffstats
path: root/xmlsecurity
diff options
context:
space:
mode:
Diffstat (limited to 'xmlsecurity')
-rw-r--r--xmlsecurity/inc/certificatechooser.hxx18
-rw-r--r--xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx9
-rw-r--r--xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_lo242.odtbin0 -> 13599 bytes
-rw-r--r--xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odtbin0 -> 19707 bytes
-rw-r--r--xmlsecurity/qa/unit/signing/signing.cxx5
-rw-r--r--xmlsecurity/qa/unit/signing/signing2.cxx309
-rw-r--r--xmlsecurity/source/component/documentdigitalsignatures.cxx2
-rw-r--r--xmlsecurity/source/dialogs/certificatechooser.cxx3
-rw-r--r--xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx77
-rw-r--r--xmlsecurity/source/helper/xmlsignaturehelper.cxx68
-rw-r--r--xmlsecurity/source/xmlsec/nss/ciphercontext.cxx5
-rw-r--r--xmlsecurity/source/xmlsec/saxhelper.cxx15
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
new file mode 100644
index 0000000000..1747448ac5
--- /dev/null
+++ b/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_lo242.odt
Binary files differ
diff --git a/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odt b/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odt
new file mode 100644
index 0000000000..fb2b978bc0
--- /dev/null
+++ b/xmlsecurity/qa/unit/signing/data/encrypted_scriptsig_odf13.odt
Binary files differ
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() ;