From 106c642b7542d587e961774cac515611982c6f0d Mon Sep 17 00:00:00 2001 From: Tomaž Vajngerl Date: Tue, 17 Jan 2017 17:55:44 +0100 Subject: sw: roundtrip test of OOXML decryption/encryption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Idea2a46a692aed666eb8dbc6185ae001d30757c2 Reviewed-on: https://gerrit.libreoffice.org/33228 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl --- sw/CppunitTest_sw_ooxmlencryption.mk | 49 ++++++++++ sw/Module_sw.mk | 1 + sw/ooxmlexport_setup.mk | 1 + sw/qa/extras/docbookexport/docbookexport.cxx | 2 +- sw/qa/extras/htmlexport/htmlexport.cxx | 4 +- sw/qa/extras/htmlimport/htmlimport.cxx | 2 +- sw/qa/extras/inc/swmodeltestbase.hxx | 99 +++++++++++++++------ .../ooxmlexport/data/Encrypted_MSO2007_abc.docx | Bin 0 -> 18432 bytes .../ooxmlexport/data/Encrypted_MSO2010_abc.docx | Bin 0 -> 19456 bytes .../ooxmlexport/data/Encrypted_MSO2013_abc.docx | Bin 0 -> 17920 bytes sw/qa/extras/ooxmlexport/ooxmlencryption.cxx | 47 ++++++++++ sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 7 +- sw/qa/extras/ww8import/ww8import.cxx | 2 +- 13 files changed, 178 insertions(+), 36 deletions(-) create mode 100644 sw/CppunitTest_sw_ooxmlencryption.mk create mode 100644 sw/qa/extras/ooxmlexport/data/Encrypted_MSO2007_abc.docx create mode 100644 sw/qa/extras/ooxmlexport/data/Encrypted_MSO2010_abc.docx create mode 100644 sw/qa/extras/ooxmlexport/data/Encrypted_MSO2013_abc.docx create mode 100644 sw/qa/extras/ooxmlexport/ooxmlencryption.cxx (limited to 'sw') diff --git a/sw/CppunitTest_sw_ooxmlencryption.mk b/sw/CppunitTest_sw_ooxmlencryption.mk new file mode 100644 index 000000000000..09b2fb1c0130 --- /dev/null +++ b/sw/CppunitTest_sw_ooxmlencryption.mk @@ -0,0 +1,49 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,sw_ooxmlencryption)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sw_ooxmlencryption, \ + sw/qa/extras/ooxmlexport/ooxmlencryption \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sw_ooxmlencryption, \ + $(sw_ooxmlexport_libraries) \ +)) + +$(eval $(call gb_CppunitTest_use_externals,sw_ooxmlencryption,\ + boost_headers \ + libxml2 \ +)) + +$(eval $(call gb_CppunitTest_set_include,sw_ooxmlencryption,\ + -I$(SRCDIR)/sw/inc \ + -I$(SRCDIR)/sw/source/core/inc \ + -I$(SRCDIR)/sw/qa/extras/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,sw_ooxmlencryption)) +$(eval $(call gb_CppunitTest_use_ure,sw_ooxmlencryption)) +$(eval $(call gb_CppunitTest_use_vcl,sw_ooxmlencryption)) + +$(eval $(call gb_CppunitTest_use_components,sw_ooxmlencryption,\ + $(sw_ooxmlexport_components) \ + filter/source/storagefilterdetect/storagefd \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,sw_ooxmlencryption)) + +$(eval $(call gb_CppunitTest_use_packages,sw_ooxmlencryption,\ + oox_generated \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk index 04d33eebb4d4..8ef8a26fcf04 100644 --- a/sw/Module_sw.mk +++ b/sw/Module_sw.mk @@ -65,6 +65,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\ CppunitTest_sw_ooxmlexport9 \ CppunitTest_sw_ooxmlfieldexport \ CppunitTest_sw_ooxmlw14export \ + CppunitTest_sw_ooxmlencryption \ CppunitTest_sw_ooxmlimport \ CppunitTest_sw_ww8export \ CppunitTest_sw_ww8export2 \ diff --git a/sw/ooxmlexport_setup.mk b/sw/ooxmlexport_setup.mk index 91ffc4b431f0..ae1b27f9cd84 100644 --- a/sw/ooxmlexport_setup.mk +++ b/sw/ooxmlexport_setup.mk @@ -59,6 +59,7 @@ define sw_ooxmlexport_components sw/util/swd \ sw/util/msword \ sfx2/util/sfx \ + sot/util/sot \ starmath/util/sm \ svl/source/fsstor/fsstorage \ svl/util/svl \ diff --git a/sw/qa/extras/docbookexport/docbookexport.cxx b/sw/qa/extras/docbookexport/docbookexport.cxx index d341a3c55a35..6fa3f66e5a9d 100644 --- a/sw/qa/extras/docbookexport/docbookexport.cxx +++ b/sw/qa/extras/docbookexport/docbookexport.cxx @@ -23,7 +23,7 @@ public: {} }; -#define DECLARE_DOCBOOKEXPORT_TEST(TestName, filename) DECLARE_SW_EXPORT_TEST(TestName, filename, DocbookExportTest) +#define DECLARE_DOCBOOKEXPORT_TEST(TestName, filename) DECLARE_SW_EXPORT_TEST(TestName, filename, nullptr, DocbookExportTest) DECLARE_DOCBOOKEXPORT_TEST(testsimple, "simple.docx") { diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index d6453aa81af3..e6a996df4166 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -67,7 +67,7 @@ private: }; -#define DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, HtmlExportTest) +#define DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, HtmlExportTest) DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo81276, "fdo81276.html") { @@ -126,7 +126,7 @@ DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testCharacterBorder, "charborder.odt") // No shadow } -#define DECLARE_HTMLEXPORT_TEST(TestName, filename) DECLARE_SW_EXPORT_TEST(TestName, filename, HtmlExportTest) +#define DECLARE_HTMLEXPORT_TEST(TestName, filename) DECLARE_SW_EXPORT_TEST(TestName, filename, nullptr, HtmlExportTest) DECLARE_HTMLEXPORT_TEST(testExportOfImages, "textAndImage.docx") { diff --git a/sw/qa/extras/htmlimport/htmlimport.cxx b/sw/qa/extras/htmlimport/htmlimport.cxx index 4491f11f734c..66d070db4752 100644 --- a/sw/qa/extras/htmlimport/htmlimport.cxx +++ b/sw/qa/extras/htmlimport/htmlimport.cxx @@ -26,7 +26,7 @@ class HtmlImportTest : public SwModelTestBase HtmlImportTest() : SwModelTestBase("sw/qa/extras/htmlimport/data/", "HTML (StarWriter)") {} }; -#define DECLARE_HTMLIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, HtmlImportTest) +#define DECLARE_HTMLIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, nullptr, HtmlImportTest) DECLARE_HTMLIMPORT_TEST(testPictureImport, "picture.html") { diff --git a/sw/qa/extras/inc/swmodeltestbase.hxx b/sw/qa/extras/inc/swmodeltestbase.hxx index 3097db6a7d8b..07b04ea2ba4d 100644 --- a/sw/qa/extras/inc/swmodeltestbase.hxx +++ b/sw/qa/extras/inc/swmodeltestbase.hxx @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -64,7 +65,7 @@ using namespace css; * } * */ -#define DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, BaseClass) \ +#define DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, password, BaseClass) \ class TestName : public BaseClass { \ protected:\ virtual OUString getTestName() override { return OUString(#TestName); } \ @@ -75,25 +76,25 @@ using namespace css; CPPUNIT_TEST_SUITE_END(); \ \ void Import() { \ - executeImportTest(filename);\ + executeImportTest(filename, password);\ }\ void Import_Export_Import() {\ - executeImportExportImportTest(filename);\ + executeImportExportImportTest(filename, password);\ }\ void verify() override;\ }; \ CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \ void TestName::verify() -#define DECLARE_OOXMLIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, Test) -#define DECLARE_OOXMLEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test) -#define DECLARE_RTFIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, Test) -#define DECLARE_RTFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test) -#define DECLARE_ODFIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, Test) -#define DECLARE_ODFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test) -#define DECLARE_WW8EXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, Test) +#define DECLARE_OOXMLIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, nullptr, Test) +#define DECLARE_OOXMLEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test) +#define DECLARE_RTFIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, nullptr, Test) +#define DECLARE_RTFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test) +#define DECLARE_ODFIMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, nullptr, Test) +#define DECLARE_ODFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test) +#define DECLARE_WW8EXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test) -#define DECLARE_SW_IMPORT_TEST(TestName, filename, BaseClass) \ +#define DECLARE_SW_IMPORT_TEST(TestName, filename, password, BaseClass) \ class TestName : public BaseClass { \ protected:\ virtual OUString getTestName() override { return OUString(#TestName); } \ @@ -103,14 +104,14 @@ using namespace css; CPPUNIT_TEST_SUITE_END(); \ \ void Import() { \ - executeImportTest(filename);\ + executeImportTest(filename, password);\ }\ void verify() override;\ }; \ CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \ void TestName::verify() -#define DECLARE_SW_EXPORT_TEST(TestName, filename, BaseClass) \ +#define DECLARE_SW_EXPORT_TEST(TestName, filename, password, BaseClass) \ class TestName : public BaseClass { \ protected:\ virtual OUString getTestName() override { return OUString(#TestName); } \ @@ -120,7 +121,7 @@ using namespace css; CPPUNIT_TEST_SUITE_END(); \ \ void Import_Export() {\ - executeImportExport(filename);\ + executeImportExport(filename, password);\ }\ void verify() override;\ }; \ @@ -136,6 +137,8 @@ private: protected: uno::Reference< lang::XComponent > mxComponent; + rtl::Reference xInteractionHandler; + xmlBufferPtr mpXmlBuffer; const char* mpTestDocumentPath; const char* mpFilter; @@ -211,7 +214,7 @@ protected: * Helper func used by each unit test to test the 'import' code. * (Loads the requested file and then calls 'verify' method) */ - void executeImportTest(const char* filename) + void executeImportTest(const char* filename, const char* pPassword = nullptr) { // If the testcase is stored in some other format, it's pointless to test. if (mustTestImportOf(filename)) @@ -219,7 +222,7 @@ protected: maTempFile.EnableKillingFile(false); header(); std::unique_ptr const pChanges(preTest(filename)); - load(mpTestDocumentPath, filename); + load(mpTestDocumentPath, filename, pPassword); verify(); finish(); maTempFile.EnableKillingFile(); @@ -231,14 +234,14 @@ protected: * (Loads the requested file, save it to temp file, load the * temp file and then calls 'verify' method) */ - void executeImportExportImportTest(const char* filename) + void executeImportExportImportTest(const char* filename, const char* pPassword = nullptr) { maTempFile.EnableKillingFile(false); header(); std::unique_ptr const pChanges(preTest(filename)); - load(mpTestDocumentPath, filename); + load(mpTestDocumentPath, filename, pPassword); postLoad(filename); - reload(mpFilter, filename); + reload(mpFilter, filename, pPassword); verify(); finish(); maTempFile.EnableKillingFile(); @@ -250,12 +253,12 @@ protected: * the initial document condition), exports with the desired * export filter and then calls 'verify' method) */ - void executeImportExport(const char* filename) + void executeImportExport(const char* filename, const char* pPassword = nullptr) { maTempFile.EnableKillingFile(false); header(); std::unique_ptr const pChanges(preTest(filename)); - load(mpTestDocumentPath, filename); + load(mpTestDocumentPath, filename, pPassword); save(OUString::createFromAscii(mpFilter), maTempFile); maTempFile.EnableKillingFile(false); verify(); @@ -595,26 +598,50 @@ protected: std::cout << "File tested,Execution Time (ms)" << std::endl; } - void load(const char* pDir, const char* pName) + void load(const char* pDir, const char* pName, const char* pPassword = nullptr) { - return loadURL(m_directories.getURLFromSrc(pDir) + OUString::createFromAscii(pName), pName); + return loadURL(m_directories.getURLFromSrc(pDir) + OUString::createFromAscii(pName), pName, pPassword); } - void loadURL(OUString const& rURL, const char* pName) + void setTestInteractionHandler(const char* pPassword, std::vector& rFilterOptions) + { + OUString sPassword = OUString::createFromAscii(pPassword); + rFilterOptions.resize(rFilterOptions.size() + 1); + xInteractionHandler = rtl::Reference(new TestInteractionHandler(sPassword)); + uno::Reference const xInteraction(xInteractionHandler.get()); + rFilterOptions[0].Name = "InteractionHandler"; + rFilterOptions[0].Value <<= xInteraction; + } + + void loadURL(OUString const& rURL, const char* pName, const char* pPassword = nullptr) { if (mxComponent.is()) mxComponent->dispose(); + + std::vector aFilterOptions; + + if (pPassword) + { + setTestInteractionHandler(pPassword, aFilterOptions); + } + // Output name early, so in the case of a hang, the name of the hanging input file is visible. if (pName) std::cout << pName << ":\n"; mnStartTime = osl_getGlobalTimer(); - mxComponent = loadFromDesktop(rURL, "com.sun.star.text.TextDocument"); + mxComponent = loadFromDesktop(rURL, "com.sun.star.text.TextDocument", comphelper::containerToSequence(aFilterOptions)); + + if (pPassword) + { + CPPUNIT_ASSERT_MESSAGE("Password set but not requested", xInteractionHandler->wasPasswordRequested()); + } + discardDumpedLayout(); if (pName && mustCalcLayoutOf(pName)) calcLayout(); } - void reload(const char* pFilter, const char* filename) + void reload(const char* pFilter, const char* filename, const char* pPassword = nullptr) { uno::Reference xStorable(mxComponent, uno::UNO_QUERY); OUString aFilterName = OUString::createFromAscii(pFilter); @@ -622,11 +649,29 @@ protected: aMediaDescriptor["FilterName"] <<= aFilterName; if (!maFilterOptions.isEmpty()) aMediaDescriptor["FilterOptions"] <<= maFilterOptions; + if (pPassword) + { + OUString sPassword = OUString::createFromAscii(pPassword); + css::uno::Sequence aEncryptionData { + { "OOXPassword", css::uno::makeAny(sPassword) } + }; + aMediaDescriptor[utl::MediaDescriptor::PROP_ENCRYPTIONDATA()] <<= aEncryptionData; + } xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); uno::Reference xComponent(xStorable, uno::UNO_QUERY); xComponent->dispose(); mbExported = true; - mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument"); + + std::vector aFilterOptions; + if (pPassword) + { + setTestInteractionHandler(pPassword, aFilterOptions); + } + mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument", comphelper::containerToSequence(aFilterOptions)); + if (pPassword) + { + CPPUNIT_ASSERT_MESSAGE("Password set but not requested", xInteractionHandler->wasPasswordRequested()); + } if (mustValidate(filename)) { if(aFilterName == "Office Open XML Text") diff --git a/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2007_abc.docx b/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2007_abc.docx new file mode 100644 index 000000000000..27566d4a7334 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2007_abc.docx differ diff --git a/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2010_abc.docx b/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2010_abc.docx new file mode 100644 index 000000000000..4881e351db33 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2010_abc.docx differ diff --git a/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2013_abc.docx b/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2013_abc.docx new file mode 100644 index 000000000000..28fa85c26141 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/Encrypted_MSO2013_abc.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlencryption.cxx b/sw/qa/extras/ooxmlexport/ooxmlencryption.cxx new file mode 100644 index 000000000000..6547676d82d1 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/ooxmlencryption.cxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +class Test : public SwModelTestBase +{ +public: + Test() : SwModelTestBase("/sw/qa/extras/ooxmlexport/data/", "Office Open XML Text") {} + +protected: + bool mustTestImportOf(const char* filename) const override { + return (OString(filename).endsWith(".docx")); + } +}; + +DECLARE_SW_ROUNDTRIP_TEST(testPassword2007, "Encrypted_MSO2007_abc.docx", "abc", Test) +{ + // Standard encryption format, AES 128, SHA1 + uno::Reference xParagraph(getParagraph(1)); + CPPUNIT_ASSERT_EQUAL(OUString("abc"), xParagraph->getString()); +} + +DECLARE_SW_ROUNDTRIP_TEST(testPassword2010, "Encrypted_MSO2010_abc.docx", "abc", Test) +{ + // Agile encryption format, AES 128, CBC, SHA1 + uno::Reference xParagraph(getParagraph(1)); + CPPUNIT_ASSERT_EQUAL(OUString("abc"), xParagraph->getString()); +} + +DECLARE_SW_ROUNDTRIP_TEST(testPassword2013, "Encrypted_MSO2013_abc.docx", "abc", Test) +{ + // Agile encryption format, AES 256, CBC, SHA512 + uno::Reference xParagraph(getParagraph(1)); + CPPUNIT_ASSERT_EQUAL(OUString("ABC"), xParagraph->getString()); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 2d1c66ba94cd..97a0991eab72 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -86,7 +86,7 @@ class FailTest : public Test { public: // UGLY: hacky manual override of MacrosTest::loadFromDesktop - void executeImportTest(const char* filename) + void executeImportTest(const char* filename, const char* /*password*/) { header(); preTest(filename); @@ -125,7 +125,7 @@ DECLARE_OOXMLIMPORT_TEST(testImageHyperlink, "image-hyperlink.docx") #if !defined(_WIN32) -DECLARE_SW_IMPORT_TEST(testMathMalformedXml, "math-malformed_xml.docx", FailTest) +DECLARE_SW_IMPORT_TEST(testMathMalformedXml, "math-malformed_xml.docx", nullptr, FailTest) { CPPUNIT_ASSERT(!mxComponent.is()); } @@ -1226,8 +1226,7 @@ protected: } }; -DECLARE_SW_IMPORT_TEST(testHFLinkToPrev, "headerfooter-link-to-prev.docx", - testHFBase) +DECLARE_SW_IMPORT_TEST(testHFLinkToPrev, "headerfooter-link-to-prev.docx", nullptr, testHFBase) { uno::Reference xPageStyles = getStyles("PageStyles"); diff --git a/sw/qa/extras/ww8import/ww8import.cxx b/sw/qa/extras/ww8import/ww8import.cxx index 85f4ca311e9c..f26f1cbd05a7 100644 --- a/sw/qa/extras/ww8import/ww8import.cxx +++ b/sw/qa/extras/ww8import/ww8import.cxx @@ -19,7 +19,7 @@ public: } }; -#define DECLARE_WW8IMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, Test) +#define DECLARE_WW8IMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, nullptr, Test) DECLARE_WW8IMPORT_TEST(testFloatingTableSectionMargins, "floating-table-section-margins.doc") { -- cgit