diff options
-rw-r--r-- | sfx2/source/doc/objstor.cxx | 30 | ||||
-rw-r--r-- | xmlsecurity/CppunitTest_xmlsecurity_signing.mk | 4 | ||||
-rw-r--r-- | xmlsecurity/qa/unit/signing/data/tdf42316.ott | bin | 0 -> 10242 bytes | |||
-rw-r--r-- | xmlsecurity/qa/unit/signing/data/tdf42316_odt12.ott | bin | 0 -> 14625 bytes | |||
-rw-r--r-- | xmlsecurity/qa/unit/signing/signing.cxx | 245 |
5 files changed, 271 insertions, 8 deletions
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx index 9375989e35e3..f3ef1c2992a3 100644 --- a/sfx2/source/doc/objstor.cxx +++ b/sfx2/source/doc/objstor.cxx @@ -1167,10 +1167,18 @@ bool SfxObjectShell::SaveTo_Impl {} // preserve only if the same filter has been used - bTryToPreserveScriptSignature = pMedium->GetFilter() && pFilter && pMedium->GetFilter()->GetFilterName() == pFilter->GetFilterName(); - + // for templates, strip the _template from the filter name for comparison + OUString aMediumFilter = pMedium->GetFilter()->GetFilterName(); + if (aMediumFilter.endsWith("_template")) + aMediumFilter = aMediumFilter.copy(0, aMediumFilter.getLength() - 9); + bTryToPreserveScriptSignature = pMedium->GetFilter() && pFilter && aMediumFilter == pFilter->GetFilterName(); + + // signatures were specified in ODF 1.2 but were used since much longer. + // LO will still correctly validate an old style signature on an ODF 1.2 + // document, but technically this is not correct, so this prevents old + // signatures to be copied over to a version 1.2 document bNoPreserveForOasis = ( - (aODFVersion == ODFVER_012_TEXT && nVersion == SvtSaveOptions::ODFVER_011) || + (aODFVersion == ODFVER_012_TEXT && nVersion < SvtSaveOptions::ODFVER_012) || (aODFVersion.isEmpty() && nVersion >= SvtSaveOptions::ODFVER_012) ); } @@ -2017,13 +2025,21 @@ bool SfxObjectShell::DoSaveCompleted( SfxMedium* pNewMed, bool bRegisterRecent ) {} } + const SfxBoolItem* pTemplateItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_TEMPLATE, false); + bool bTemplate = pTemplateItem && pTemplateItem->GetValue(); + // before the title regenerated the document must lose the signatures pImpl->nDocumentSignatureState = SignatureState::NOSIGNATURES; - pImpl->nScriptingSignatureState = pNewMed->GetCachedSignatureState_Impl(); - OSL_ENSURE( pImpl->nScriptingSignatureState != SignatureState::BROKEN, "The signature must not be broken at this place" ); + if (!bTemplate) + { + pImpl->nScriptingSignatureState = pNewMed->GetCachedSignatureState_Impl(); + OSL_ENSURE( pImpl->nScriptingSignatureState != SignatureState::BROKEN, "The signature must not be broken at this place" ); - // TODO/LATER: in future the medium must control own signature state, not the document - pNewMed->SetCachedSignatureState_Impl( SignatureState::NOSIGNATURES ); // set the default value back + // TODO/LATER: in future the medium must control own signature state, not the document + pNewMed->SetCachedSignatureState_Impl( SignatureState::NOSIGNATURES ); // set the default value back + } + else + pNewMed->SetCachedSignatureState_Impl( pImpl->nScriptingSignatureState ); // Set new title if (!pNewMed->GetName().isEmpty() && SfxObjectCreateMode::EMBEDDED != eCreateMode) diff --git a/xmlsecurity/CppunitTest_xmlsecurity_signing.mk b/xmlsecurity/CppunitTest_xmlsecurity_signing.mk index 418aa21a27c9..84e7a76c043b 100644 --- a/xmlsecurity/CppunitTest_xmlsecurity_signing.mk +++ b/xmlsecurity/CppunitTest_xmlsecurity_signing.mk @@ -60,4 +60,8 @@ $(call gb_CppunitTest_get_target,xmlsecurity_signing): \ LIBO_LD_PATH=$$LD_LIBRARY_PATH endif +$(eval $(call gb_CppunitTest_use_custom_headers,xmlsecurity_signing,\ + officecfg/registry \ +)) + # vim: set noet sw=4 ts=4: diff --git a/xmlsecurity/qa/unit/signing/data/tdf42316.ott b/xmlsecurity/qa/unit/signing/data/tdf42316.ott Binary files differnew file mode 100644 index 000000000000..95162a627176 --- /dev/null +++ b/xmlsecurity/qa/unit/signing/data/tdf42316.ott diff --git a/xmlsecurity/qa/unit/signing/data/tdf42316_odt12.ott b/xmlsecurity/qa/unit/signing/data/tdf42316_odt12.ott Binary files differnew file mode 100644 index 000000000000..ecff48709109 --- /dev/null +++ b/xmlsecurity/qa/unit/signing/data/tdf42316_odt12.ott diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx index e316a4dc7ef9..87411c7afa72 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -18,13 +18,15 @@ #include <unotest/macros_test.hxx> #include <test/xmltesttools.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> #include <com/sun/star/embed/XStorage.hpp> #include <com/sun/star/embed/XTransactedObject.hpp> #include <com/sun/star/frame/Desktop.hpp> #include <com/sun/star/frame/XStorable.hpp> -#include <com/sun/star/xml/crypto/SEInitializer.hpp> #include <com/sun/star/security/DocumentDigitalSignatures.hpp> #include <com/sun/star/security/XDocumentDigitalSignatures.hpp> +#include <com/sun/star/xml/crypto/SEInitializer.hpp> #include <comphelper/processfactory.hxx> #include <comphelper/propertysequence.hxx> @@ -37,6 +39,7 @@ #include <osl/file.hxx> #include <osl/process.h> #include <osl/thread.hxx> +#include <comphelper/sequence.hxx> #include <comphelper/ofopxmlhelper.hxx> #include <unotools/streamwrap.hxx> @@ -45,6 +48,10 @@ #include <documentsignaturemanager.hxx> #include <certificate.hxx> #include <xsecctl.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <officecfg/Office/Common.hxx> +#include <comphelper/configuration.hxx> using namespace com::sun::star; @@ -78,6 +85,9 @@ protected: uno::Reference<security::XCertificate> getCertificate(DocumentSignatureManager& rSignatureManager, svl::crypto::SignatureMethodAlgorithm eAlgo); + SfxObjectShell* assertDocument(const ::CppUnit::SourceLine aSrcLine, + const OUString& rFilterName, const SignatureState nDocSign, + const SignatureState nMacroSign, const OUString& sVersion); }; SigningTest::SigningTest() {} @@ -955,6 +965,239 @@ CPPUNIT_TEST_FIXTURE(SigningTest, testODFEncryptedGPG) #endif +SfxObjectShell* SigningTest::assertDocument(const ::CppUnit::SourceLine aSrcLine, + const OUString& rFilterName, + const SignatureState nDocSign, + const SignatureState nMacroSign, + const OUString& sVersion) +{ + std::string sPos = aSrcLine.fileName() + ":" + OString::number(aSrcLine.lineNumber()).getStr(); + + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sPos, pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT_MESSAGE(sPos, pObjectShell); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sPos, rFilterName, + pObjectShell->GetMedium()->GetFilter()->GetFilterName()); + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sPos, nDocSign, nActual); + nActual = pObjectShell->GetScriptingSignatureState(); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sPos, nMacroSign, nActual); + + OUString aODFVersion; + uno::Reference<beans::XPropertySet> xPropSet(pObjectShell->GetStorage(), uno::UNO_QUERY_THROW); + xPropSet->getPropertyValue("Version") >>= aODFVersion; + CPPUNIT_ASSERT_EQUAL(sVersion, aODFVersion); + + return pObjectShell; +} + +/// Test if a macro signature from a OTT 1.2 template is preserved for ODT 1.2 +CPPUNIT_TEST_FIXTURE(SigningTest, testPreserveMacroTemplateSignature12) +{ + const OUString aURL(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf42316_odt12.ott"); + const OUString sLoadMessage = "loading failed: " + aURL; + + // load the template as-is to validate signatures + mxComponent = loadFromDesktop( + aURL, OUString(), comphelper::InitPropertySequence({ { "AsTemplate", uno::Any(false) } })); + CPPUNIT_ASSERT_MESSAGE(OUStringToOString(sLoadMessage, RTL_TEXTENCODING_UTF8).getStr(), + mxComponent.is()); + + // we are a template, and have a valid document and macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8_template", SignatureState::OK, SignatureState::OK, + ODFVER_012_TEXT); + mxComponent->dispose(); + + // create new document from template + // we can't use createDoc / MacrosTest::loadFromDesktop, because ALWAYS_EXECUTE_NO_WARN + // won't verify the signature for templates, so the resulting document won't be able to + // preserve the templates signature. + mxComponent = mxDesktop->loadComponentFromURL( + aURL, "_default", 0, + comphelper::InitPropertySequence( + { { "MacroExecutionMode", + uno::Any(document::MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN) } })); + CPPUNIT_ASSERT_MESSAGE(OUStringToOString(sLoadMessage, RTL_TEXTENCODING_UTF8).getStr(), + mxComponent.is()); + + // we are somehow a template (?), and have just a valid macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8_template", SignatureState::NOSIGNATURES, + SignatureState::OK, ODFVER_012_TEXT); + + // save as new ODT document + utl::TempFile aTempFileSaveAs; + aTempFileSaveAs.EnableKillingFile(); + try + { + uno::Reference<frame::XStorable> xDocStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> descSaveAs( + comphelper::InitPropertySequence({ { "FilterName", uno::Any(OUString("writer8")) } })); + xDocStorable->storeAsURL(aTempFileSaveAs.GetURL(), descSaveAs); + } + catch (...) + { + CPPUNIT_FAIL("Failed to save ODT document"); + } + + // load saved document + createDoc(aTempFileSaveAs.GetURL()); + + // the loaded document is a ODT with a macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8", SignatureState::NOSIGNATURES, + SignatureState::OK, ODFVER_012_TEXT); +} + +/// Test if a macro signature from an OTT 1.0 is dropped for ODT 1.2 +CPPUNIT_TEST_FIXTURE(SigningTest, testDropMacroTemplateSignature) +{ + const OUString aURL(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf42316.ott"); + const OUString sLoadMessage = "loading failed: " + aURL; + + // load the template as-is to validate signatures + mxComponent = loadFromDesktop( + aURL, OUString(), comphelper::InitPropertySequence({ { "AsTemplate", uno::Any(false) } })); + CPPUNIT_ASSERT_MESSAGE(OUStringToOString(sLoadMessage, RTL_TEXTENCODING_UTF8).getStr(), + mxComponent.is()); + + // we are a template, and have a valid document and macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8_template", SignatureState::NOSIGNATURES, + SignatureState::NOTVALIDATED, OUString()); + mxComponent->dispose(); + + // create new document from template + // we can't use createDoc / MacrosTest::loadFromDesktop, because ALWAYS_EXECUTE_NO_WARN + // won't verify the signature for templates, so the resulting document won't be able to + // preserve the templates signature. + mxComponent = mxDesktop->loadComponentFromURL( + aURL, "_default", 0, + comphelper::InitPropertySequence( + { { "MacroExecutionMode", + uno::Any(document::MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN) } })); + CPPUNIT_ASSERT_MESSAGE(OUStringToOString(sLoadMessage, RTL_TEXTENCODING_UTF8).getStr(), + mxComponent.is()); + + // we are somehow a template (?), and have just a valid macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8_template", SignatureState::NOSIGNATURES, + SignatureState::NOTVALIDATED, OUString()); + + // save as new ODT document + utl::TempFile aTempFileSaveAs; + aTempFileSaveAs.EnableKillingFile(); + try + { + uno::Reference<frame::XStorable> xDocStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> descSaveAs( + comphelper::InitPropertySequence({ { "FilterName", uno::Any(OUString("writer8")) } })); + xDocStorable->storeAsURL(aTempFileSaveAs.GetURL(), descSaveAs); + } + catch (...) + { + CPPUNIT_FAIL("Failed to save ODT document"); + } + + // load saved document + createDoc(aTempFileSaveAs.GetURL()); + + // the loaded document is a 1.2 ODT without any signatures + assertDocument(CPPUNIT_SOURCELINE(), "writer8", SignatureState::NOSIGNATURES, + SignatureState::NOSIGNATURES, ODFVER_012_TEXT); +} + +class Resetter +{ +private: + std::function<void()> m_Func; + +public: + Resetter(std::function<void()> const& rFunc) + : m_Func(rFunc) + { + } + ~Resetter() + { + try + { + m_Func(); + } + catch (...) // has to be reliable + { + fprintf(stderr, "resetter failed with exception\n"); + abort(); + } + } +}; + +/// Test if a macro signature from a OTT 1.0 template is preserved for ODT 1.0 +CPPUNIT_TEST_FIXTURE(SigningTest, testPreserveMacroTemplateSignature10) +{ + // set ODF version 1.0 / 1.1 as default + Resetter _([]() { + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch); + return pBatch->commit(); + }); + std::shared_ptr<comphelper::ConfigurationChanges> pBatch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Save::ODF::DefaultVersion::set(2, pBatch); + pBatch->commit(); + + const OUString aURL(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf42316.ott"); + const OUString sLoadMessage = "loading failed: " + aURL; + + // load the template as-is to validate signatures + mxComponent = loadFromDesktop( + aURL, OUString(), comphelper::InitPropertySequence({ { "AsTemplate", uno::Any(false) } })); + CPPUNIT_ASSERT_MESSAGE(OUStringToOString(sLoadMessage, RTL_TEXTENCODING_UTF8).getStr(), + mxComponent.is()); + + // we are a template, and have a valid document and macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8_template", SignatureState::NOSIGNATURES, + SignatureState::NOTVALIDATED, OUString()); + + mxComponent->dispose(); + + // create new document from template + // we can't use createDoc / MacrosTest::loadFromDesktop, because ALWAYS_EXECUTE_NO_WARN + // won't verify the signature for templates, so the resulting document won't be able to + // preserve the templates signature. + mxComponent = mxDesktop->loadComponentFromURL( + aURL, "_default", 0, + comphelper::InitPropertySequence( + { { "MacroExecutionMode", + uno::Any(document::MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN) } })); + CPPUNIT_ASSERT_MESSAGE(OUStringToOString(sLoadMessage, RTL_TEXTENCODING_UTF8).getStr(), + mxComponent.is()); + + // we are somehow a template (?), and have just a valid macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8_template", SignatureState::NOSIGNATURES, + SignatureState::NOTVALIDATED, OUString()); + + // save as new ODT document + utl::TempFile aTempFileSaveAs; + aTempFileSaveAs.EnableKillingFile(); + try + { + uno::Reference<frame::XStorable> xDocStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> descSaveAs( + comphelper::InitPropertySequence({ { "FilterName", uno::Any(OUString("writer8")) } })); + xDocStorable->storeAsURL(aTempFileSaveAs.GetURL(), descSaveAs); + } + catch (...) + { + CPPUNIT_FAIL("Failed to save ODT document"); + } + + // load saved document + createDoc(aTempFileSaveAs.GetURL()); + + // the loaded document is a ODT with a macro signature + assertDocument(CPPUNIT_SOURCELINE(), "writer8", SignatureState::NOSIGNATURES, + SignatureState::NOTVALIDATED, OUString()); +} + #endif void SigningTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) |