2016-01-11 15:46:10 +01:00
|
|
|
/* -*- 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/.
|
|
|
|
*/
|
|
|
|
|
2016-11-18 19:06:29 +02:00
|
|
|
#include <config_features.h>
|
2017-12-06 14:02:25 +01:00
|
|
|
#include <config_gpgme.h>
|
2016-11-18 19:06:29 +02:00
|
|
|
|
2016-02-26 08:53:43 +01:00
|
|
|
#include <sal/config.h>
|
|
|
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
2016-01-11 15:46:10 +01:00
|
|
|
#include <test/bootstrapfixture.hxx>
|
|
|
|
#include <unotest/macros_test.hxx>
|
2016-11-24 15:39:35 +01:00
|
|
|
#include <test/xmltesttools.hxx>
|
2016-01-11 15:46:10 +01:00
|
|
|
|
|
|
|
#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>
|
2017-11-02 15:47:32 +01:00
|
|
|
#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
|
|
|
|
#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
|
2016-01-11 15:46:10 +01:00
|
|
|
|
|
|
|
#include <comphelper/processfactory.hxx>
|
2017-06-09 13:43:00 +02:00
|
|
|
#include <comphelper/propertysequence.hxx>
|
2016-01-11 15:46:10 +01:00
|
|
|
#include <unotools/mediadescriptor.hxx>
|
|
|
|
#include <unotools/tempfile.hxx>
|
|
|
|
#include <unotools/ucbstreamhelper.hxx>
|
|
|
|
#include <comphelper/storagehelper.hxx>
|
2016-02-04 09:31:16 +01:00
|
|
|
#include <sfx2/sfxbasemodel.hxx>
|
|
|
|
#include <sfx2/objsh.hxx>
|
2016-03-07 11:44:28 +01:00
|
|
|
#include <osl/file.hxx>
|
2017-12-08 00:10:42 +01:00
|
|
|
#include <osl/process.h>
|
2016-03-07 12:30:26 +01:00
|
|
|
#include <comphelper/ofopxmlhelper.hxx>
|
2016-01-11 15:46:10 +01:00
|
|
|
|
2016-05-27 10:56:17 +03:00
|
|
|
#include <documentsignaturehelper.hxx>
|
|
|
|
#include <xmlsignaturehelper.hxx>
|
2016-02-15 17:05:00 +01:00
|
|
|
#include <documentsignaturemanager.hxx>
|
2016-01-11 15:46:10 +01:00
|
|
|
|
|
|
|
using namespace com::sun::star;
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2017-08-23 18:11:38 +02:00
|
|
|
char const DATA_DIRECTORY[] = "/xmlsecurity/qa/unit/signing/data/";
|
2016-01-11 15:46:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Testsuite for the document signing feature.
|
2016-11-24 15:39:35 +01:00
|
|
|
class SigningTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
|
2016-01-11 15:46:10 +01:00
|
|
|
{
|
|
|
|
uno::Reference<uno::XComponentContext> mxComponentContext;
|
|
|
|
uno::Reference<lang::XComponent> mxComponent;
|
2017-06-21 13:34:30 +02:00
|
|
|
uno::Reference<xml::crypto::XSEInitializer> mxSEInitializer;
|
|
|
|
uno::Reference<xml::crypto::XXMLSecurityContext> mxSecurityContext;
|
2016-01-11 15:46:10 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
SigningTest();
|
|
|
|
virtual void setUp() override;
|
|
|
|
virtual void tearDown() override;
|
2016-11-24 15:39:35 +01:00
|
|
|
void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
|
2016-01-11 15:46:10 +01:00
|
|
|
|
|
|
|
void testDescription();
|
2016-03-11 14:53:13 +01:00
|
|
|
/// Test a typical ODF where all streams are signed.
|
|
|
|
void testODFGood();
|
|
|
|
/// Test a typical broken ODF signature where one stream is corrupted.
|
|
|
|
void testODFBroken();
|
2016-11-30 11:01:29 +01:00
|
|
|
/// Document has a signature stream, but no actual signatures.
|
|
|
|
void testODFNo();
|
2016-02-04 09:31:16 +01:00
|
|
|
/// Test a typical OOXML where a number of (but not all) streams are signed.
|
|
|
|
void testOOXMLPartial();
|
2016-02-04 09:39:32 +01:00
|
|
|
/// Test a typical broken OOXML signature where one stream is corrupted.
|
|
|
|
void testOOXMLBroken();
|
2016-02-15 17:51:00 +01:00
|
|
|
void testOOXMLDescription();
|
2016-03-04 11:18:17 +01:00
|
|
|
/// Test appending a new signature next to an existing one.
|
|
|
|
void testOOXMLAppend();
|
2016-03-04 15:41:35 +01:00
|
|
|
/// Test removing a signature from existing ones.
|
|
|
|
void testOOXMLRemove();
|
2016-03-07 12:30:26 +01:00
|
|
|
/// Test removing all signatures from a document.
|
|
|
|
void testOOXMLRemoveAll();
|
2016-11-18 19:06:29 +02:00
|
|
|
#if HAVE_FEATURE_PDFIMPORT
|
2016-10-13 13:14:04 +02:00
|
|
|
/// Test a typical PDF where the signature is good.
|
|
|
|
void testPDFGood();
|
|
|
|
/// Test a typical PDF where the signature is bad.
|
|
|
|
void testPDFBad();
|
|
|
|
/// Test a typical PDF which is not signed.
|
|
|
|
void testPDFNo();
|
2016-11-18 19:06:29 +02:00
|
|
|
#endif
|
2016-04-25 18:39:27 +02:00
|
|
|
void test96097Calc();
|
|
|
|
void test96097Doc();
|
2016-11-30 11:01:29 +01:00
|
|
|
/// Creates a XAdES signature from scratch.
|
2016-11-24 15:39:35 +01:00
|
|
|
void testXAdES();
|
2016-11-30 11:01:29 +01:00
|
|
|
/// Works with an existing good XAdES signature.
|
|
|
|
void testXAdESGood();
|
2017-11-02 15:47:32 +01:00
|
|
|
/// Test importing of signature line images
|
|
|
|
void testSignatureLineImages();
|
2017-12-08 00:10:42 +01:00
|
|
|
#if HAVE_FEATURE_GPGVERIFY
|
2017-12-06 14:02:25 +01:00
|
|
|
/// Test a typical ODF where all streams are GPG-signed.
|
|
|
|
void testODFGoodGPG();
|
|
|
|
/// Test a typical ODF where all streams are GPG-signed, but we don't trust the signature.
|
|
|
|
void testODFUntrustedGoodGPG();
|
|
|
|
/// Test a typical broken ODF signature where one stream is corrupted.
|
|
|
|
void testODFBrokenStreamGPG();
|
|
|
|
/// Test a typical broken ODF signature where the XML dsig hash is corrupted.
|
|
|
|
void testODFBrokenDsigGPG();
|
2018-03-18 11:25:41 +01:00
|
|
|
#if HAVE_GPGCONF_SOCKETDIR
|
2018-01-13 04:17:37 +01:00
|
|
|
/// Test loading an encrypted ODF document
|
|
|
|
void testODFEncryptedGPG();
|
2018-03-18 11:25:41 +01:00
|
|
|
#endif
|
2017-12-06 14:02:25 +01:00
|
|
|
#endif
|
2016-01-11 15:46:10 +01:00
|
|
|
CPPUNIT_TEST_SUITE(SigningTest);
|
|
|
|
CPPUNIT_TEST(testDescription);
|
2016-03-11 14:53:13 +01:00
|
|
|
CPPUNIT_TEST(testODFGood);
|
|
|
|
CPPUNIT_TEST(testODFBroken);
|
2016-11-30 11:01:29 +01:00
|
|
|
CPPUNIT_TEST(testODFNo);
|
2016-03-11 14:53:13 +01:00
|
|
|
CPPUNIT_TEST(testODFBroken);
|
2016-02-04 09:31:16 +01:00
|
|
|
CPPUNIT_TEST(testOOXMLPartial);
|
2016-02-04 09:39:32 +01:00
|
|
|
CPPUNIT_TEST(testOOXMLBroken);
|
2016-02-15 17:51:00 +01:00
|
|
|
CPPUNIT_TEST(testOOXMLDescription);
|
2016-03-04 11:18:17 +01:00
|
|
|
CPPUNIT_TEST(testOOXMLAppend);
|
2016-03-04 15:41:35 +01:00
|
|
|
CPPUNIT_TEST(testOOXMLRemove);
|
2016-03-07 12:30:26 +01:00
|
|
|
CPPUNIT_TEST(testOOXMLRemoveAll);
|
2016-11-18 19:06:29 +02:00
|
|
|
#if HAVE_FEATURE_PDFIMPORT
|
2016-10-13 13:14:04 +02:00
|
|
|
CPPUNIT_TEST(testPDFGood);
|
|
|
|
CPPUNIT_TEST(testPDFBad);
|
|
|
|
CPPUNIT_TEST(testPDFNo);
|
2016-11-18 19:06:29 +02:00
|
|
|
#endif
|
2016-04-25 18:39:27 +02:00
|
|
|
CPPUNIT_TEST(test96097Calc);
|
|
|
|
CPPUNIT_TEST(test96097Doc);
|
2016-11-24 15:39:35 +01:00
|
|
|
CPPUNIT_TEST(testXAdES);
|
2016-11-30 11:01:29 +01:00
|
|
|
CPPUNIT_TEST(testXAdESGood);
|
2017-11-02 15:47:32 +01:00
|
|
|
CPPUNIT_TEST(testSignatureLineImages);
|
2017-12-08 00:10:42 +01:00
|
|
|
#if HAVE_FEATURE_GPGVERIFY
|
2017-12-06 14:02:25 +01:00
|
|
|
CPPUNIT_TEST(testODFGoodGPG);
|
|
|
|
CPPUNIT_TEST(testODFUntrustedGoodGPG);
|
|
|
|
CPPUNIT_TEST(testODFBrokenStreamGPG);
|
|
|
|
CPPUNIT_TEST(testODFBrokenDsigGPG);
|
2018-03-18 11:25:41 +01:00
|
|
|
#if HAVE_GPGCONF_SOCKETDIR
|
2018-01-13 04:17:37 +01:00
|
|
|
CPPUNIT_TEST(testODFEncryptedGPG);
|
2018-03-18 11:25:41 +01:00
|
|
|
#endif
|
2017-12-06 14:02:25 +01:00
|
|
|
#endif
|
2016-01-11 15:46:10 +01:00
|
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
|
|
|
|
private:
|
2016-07-25 14:04:19 +02:00
|
|
|
void createDoc(const OUString& rURL);
|
|
|
|
void createCalc(const OUString& rURL);
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<security::XCertificate> getCertificate(DocumentSignatureManager& rSignatureManager);
|
2016-01-11 15:46:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
SigningTest::SigningTest()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::setUp()
|
|
|
|
{
|
|
|
|
test::BootstrapFixture::setUp();
|
|
|
|
|
|
|
|
mxComponentContext.set(comphelper::getComponentContext(getMultiServiceFactory()));
|
|
|
|
mxDesktop.set(frame::Desktop::create(mxComponentContext));
|
2017-06-21 13:34:30 +02:00
|
|
|
mxSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext);
|
|
|
|
mxSecurityContext = mxSEInitializer->createSecurityContext(OUString());
|
2016-08-02 09:10:32 +02:00
|
|
|
|
|
|
|
OUString aSourceDir = m_directories.getURLFromSrc(DATA_DIRECTORY);
|
2016-08-22 15:09:50 +02:00
|
|
|
OUString aTargetDir = m_directories.getURLFromWorkdir(
|
2016-08-29 17:40:38 +02:00
|
|
|
"/CppunitTest/xmlsecurity_signing.test.user/");
|
2017-12-14 13:50:14 +01:00
|
|
|
|
|
|
|
// Set up cert8.db in workdir/CppunitTest/
|
2016-08-02 09:10:32 +02:00
|
|
|
osl::File::copy(aSourceDir + "cert8.db", aTargetDir + "cert8.db");
|
2016-11-24 13:42:14 +01:00
|
|
|
osl::File::copy(aSourceDir + "key3.db", aTargetDir + "key3.db");
|
2017-12-14 13:50:14 +01:00
|
|
|
|
|
|
|
// Make gpg use our own defined setup & keys
|
|
|
|
osl::File::copy(aSourceDir + "pubring.gpg", aTargetDir + "pubring.gpg");
|
|
|
|
osl::File::copy(aSourceDir + "random_seed", aTargetDir + "random_seed");
|
|
|
|
osl::File::copy(aSourceDir + "secring.gpg", aTargetDir + "secring.gpg");
|
|
|
|
osl::File::copy(aSourceDir + "trustdb.gpg", aTargetDir + "trustdb.gpg");
|
|
|
|
|
2016-08-02 09:10:32 +02:00
|
|
|
OUString aTargetPath;
|
|
|
|
osl::FileBase::getSystemPathFromFileURL(aTargetDir, aTargetPath);
|
2017-12-14 13:50:14 +01:00
|
|
|
|
|
|
|
OUString mozCertVar("MOZILLA_CERTIFICATE_FOLDER");
|
|
|
|
osl_setEnvironment(mozCertVar.pData, aTargetPath.pData);
|
|
|
|
OUString gpgHomeVar("GNUPGHOME");
|
|
|
|
osl_setEnvironment(gpgHomeVar.pData, aTargetPath.pData);
|
2016-01-11 15:46:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::tearDown()
|
|
|
|
{
|
|
|
|
if (mxComponent.is())
|
|
|
|
mxComponent->dispose();
|
|
|
|
|
|
|
|
test::BootstrapFixture::tearDown();
|
|
|
|
}
|
|
|
|
|
2016-02-04 09:31:16 +01:00
|
|
|
void SigningTest::createDoc(const OUString& rURL)
|
2016-01-11 15:46:10 +01:00
|
|
|
{
|
|
|
|
if (mxComponent.is())
|
|
|
|
mxComponent->dispose();
|
2016-02-04 09:31:16 +01:00
|
|
|
if (rURL.isEmpty())
|
|
|
|
mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
|
|
|
|
else
|
|
|
|
mxComponent = loadFromDesktop(rURL, "com.sun.star.text.TextDocument");
|
2016-01-11 15:46:10 +01:00
|
|
|
}
|
|
|
|
|
2016-04-25 18:39:27 +02:00
|
|
|
void SigningTest::createCalc(const OUString& rURL)
|
|
|
|
{
|
|
|
|
if (mxComponent.is())
|
|
|
|
mxComponent->dispose();
|
|
|
|
if (rURL.isEmpty())
|
|
|
|
mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.sheet.SpreadsheetDocument");
|
|
|
|
else
|
|
|
|
mxComponent = loadFromDesktop(rURL, "com.sun.star.sheet.SpreadsheetDocument");
|
|
|
|
}
|
|
|
|
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<security::XCertificate> SigningTest::getCertificate(DocumentSignatureManager& rSignatureManager)
|
2016-01-11 15:46:10 +01:00
|
|
|
{
|
2016-11-24 13:42:14 +01:00
|
|
|
uno::Reference<security::XCertificate> xCertificate;
|
|
|
|
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = rSignatureManager.getSecurityEnvironment();
|
2016-11-24 13:42:14 +01:00
|
|
|
uno::Sequence<uno::Reference<security::XCertificate>> aCertificates = xSecurityEnvironment->getPersonalCertificates();
|
|
|
|
if (!aCertificates.hasElements())
|
|
|
|
return xCertificate;
|
|
|
|
|
|
|
|
return aCertificates[0];
|
2016-01-11 15:46:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testDescription()
|
|
|
|
{
|
2016-02-15 17:05:00 +01:00
|
|
|
// Create an empty document and store it to a tempfile, finally load it as a storage.
|
2016-07-25 14:04:19 +02:00
|
|
|
createDoc("");
|
2016-02-15 17:05:00 +01:00
|
|
|
|
2016-01-11 15:46:10 +01:00
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer8");
|
|
|
|
xStorable->storeAsURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
2016-11-01 14:49:56 +02:00
|
|
|
DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content);
|
2016-11-08 14:10:05 +01:00
|
|
|
CPPUNIT_ASSERT(aManager.init());
|
2016-02-15 17:05:00 +01:00
|
|
|
uno::Reference <embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aTempFile.GetURL(), embed::ElementModes::READWRITE);
|
|
|
|
CPPUNIT_ASSERT(xStorage.is());
|
|
|
|
aManager.mxStore = xStorage;
|
|
|
|
aManager.maSignatureHelper.SetStorage(xStorage, "1.2");
|
2016-01-11 15:46:10 +01:00
|
|
|
|
2016-02-15 17:05:00 +01:00
|
|
|
// Then add a signature document.
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager);
|
2016-11-24 13:42:14 +01:00
|
|
|
if (!xCertificate.is())
|
|
|
|
return;
|
2016-02-15 17:51:00 +01:00
|
|
|
OUString aDescription("SigningTest::testDescription");
|
|
|
|
sal_Int32 nSecurityId;
|
2017-06-21 13:34:30 +02:00
|
|
|
aManager.add(xCertificate, mxSecurityContext, aDescription, nSecurityId, false);
|
2016-02-15 17:51:00 +01:00
|
|
|
|
|
|
|
// Read back the signature and make sure that the description survives the roundtrip.
|
|
|
|
aManager.read(/*bUseTempStream=*/true);
|
|
|
|
std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations;
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size());
|
2016-02-15 17:51:00 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(aDescription, rInformations[0].ouDescription);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testOOXMLDescription()
|
|
|
|
{
|
|
|
|
// Create an empty document and store it to a tempfile, finally load it as a storage.
|
2016-07-25 14:04:19 +02:00
|
|
|
createDoc("");
|
2016-02-15 17:51:00 +01:00
|
|
|
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("MS Word 2007 XML");
|
|
|
|
xStorable->storeAsURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
2016-11-01 14:49:56 +02:00
|
|
|
DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content);
|
2016-11-08 14:10:05 +01:00
|
|
|
CPPUNIT_ASSERT(aManager.init());
|
2016-02-15 17:51:00 +01:00
|
|
|
uno::Reference <embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aTempFile.GetURL(), embed::ElementModes::READWRITE);
|
|
|
|
CPPUNIT_ASSERT(xStorage.is());
|
|
|
|
aManager.mxStore = xStorage;
|
|
|
|
aManager.maSignatureHelper.SetStorage(xStorage, "1.2");
|
|
|
|
|
2016-03-04 11:18:17 +01:00
|
|
|
// Then add a document signature.
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager);
|
2016-11-24 13:42:14 +01:00
|
|
|
if (!xCertificate.is())
|
|
|
|
return;
|
2016-02-15 17:05:00 +01:00
|
|
|
OUString aDescription("SigningTest::testDescription");
|
|
|
|
sal_Int32 nSecurityId;
|
2017-06-21 13:34:30 +02:00
|
|
|
aManager.add(xCertificate, mxSecurityContext, aDescription, nSecurityId, false);
|
2016-01-11 15:46:10 +01:00
|
|
|
|
|
|
|
// Read back the signature and make sure that the description survives the roundtrip.
|
2016-02-15 17:05:00 +01:00
|
|
|
aManager.read(/*bUseTempStream=*/true);
|
|
|
|
std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations;
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size());
|
2016-02-15 17:05:00 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(aDescription, rInformations[0].ouDescription);
|
2016-01-11 15:46:10 +01:00
|
|
|
}
|
|
|
|
|
2016-03-04 11:18:17 +01:00
|
|
|
void SigningTest::testOOXMLAppend()
|
|
|
|
{
|
2016-03-07 11:44:28 +01:00
|
|
|
// Copy the test document to a temporary file, as it'll be modified.
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
OUString aURL = aTempFile.GetURL();
|
2016-03-07 18:53:17 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(osl::File::RC::E_None,
|
2016-03-09 14:14:18 +01:00
|
|
|
osl::File::copy(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx", aURL));
|
2016-03-04 11:18:17 +01:00
|
|
|
// Load the test document as a storage and read its single signature.
|
2016-11-01 14:49:56 +02:00
|
|
|
DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content);
|
2016-11-08 14:10:05 +01:00
|
|
|
CPPUNIT_ASSERT(aManager.init());
|
2016-03-04 11:18:17 +01:00
|
|
|
uno::Reference <embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aURL, embed::ElementModes::READWRITE);
|
|
|
|
CPPUNIT_ASSERT(xStorage.is());
|
|
|
|
aManager.mxStore = xStorage;
|
|
|
|
aManager.maSignatureHelper.SetStorage(xStorage, "1.2");
|
|
|
|
aManager.read(/*bUseTempStream=*/false);
|
|
|
|
std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations;
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size());
|
2016-03-04 11:18:17 +01:00
|
|
|
|
|
|
|
// Then add a second document signature.
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager);
|
2016-11-24 13:42:14 +01:00
|
|
|
if (!xCertificate.is())
|
|
|
|
return;
|
2016-03-04 11:18:17 +01:00
|
|
|
sal_Int32 nSecurityId;
|
2017-06-21 13:34:30 +02:00
|
|
|
aManager.add(xCertificate, mxSecurityContext, OUString(), nSecurityId, false);
|
2016-03-04 11:18:17 +01:00
|
|
|
|
|
|
|
// Read back the signatures and make sure that we have the expected amount.
|
|
|
|
aManager.read(/*bUseTempStream=*/true);
|
|
|
|
// This was 1: the original signature was lost.
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations.size());
|
2016-03-04 11:18:17 +01:00
|
|
|
}
|
|
|
|
|
2016-03-04 15:41:35 +01:00
|
|
|
void SigningTest::testOOXMLRemove()
|
|
|
|
{
|
|
|
|
// Load the test document as a storage and read its signatures: purpose1 and purpose2.
|
2016-11-01 14:49:56 +02:00
|
|
|
DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content);
|
2016-11-08 14:10:05 +01:00
|
|
|
CPPUNIT_ASSERT(aManager.init());
|
2016-03-09 14:14:18 +01:00
|
|
|
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "multi.docx";
|
2016-03-04 15:41:35 +01:00
|
|
|
uno::Reference <embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aURL, embed::ElementModes::READWRITE);
|
|
|
|
CPPUNIT_ASSERT(xStorage.is());
|
|
|
|
aManager.mxStore = xStorage;
|
|
|
|
aManager.maSignatureHelper.SetStorage(xStorage, "1.2");
|
|
|
|
aManager.read(/*bUseTempStream=*/false);
|
|
|
|
std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations;
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations.size());
|
2016-03-04 15:41:35 +01:00
|
|
|
|
|
|
|
// Then remove the last added signature.
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager);
|
2016-11-24 13:42:14 +01:00
|
|
|
if (!xCertificate.is())
|
|
|
|
return;
|
2016-03-04 15:41:35 +01:00
|
|
|
aManager.remove(0);
|
|
|
|
|
|
|
|
// Read back the signatures and make sure that only purpose1 is left.
|
|
|
|
aManager.read(/*bUseTempStream=*/true);
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size());
|
2016-03-04 15:41:35 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(OUString("purpose1"), rInformations[0].ouDescription);
|
|
|
|
}
|
|
|
|
|
2016-03-07 12:30:26 +01:00
|
|
|
void SigningTest::testOOXMLRemoveAll()
|
|
|
|
{
|
|
|
|
// Copy the test document to a temporary file, as it'll be modified.
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
OUString aURL = aTempFile.GetURL();
|
2016-03-07 18:53:17 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL(osl::File::RC::E_None,
|
2016-03-09 14:14:18 +01:00
|
|
|
osl::File::copy(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx", aURL));
|
2016-03-07 12:30:26 +01:00
|
|
|
// Load the test document as a storage and read its single signature.
|
2016-11-01 14:49:56 +02:00
|
|
|
DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content);
|
2016-11-08 14:10:05 +01:00
|
|
|
CPPUNIT_ASSERT(aManager.init());
|
2016-03-07 12:30:26 +01:00
|
|
|
uno::Reference <embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aURL, embed::ElementModes::READWRITE);
|
|
|
|
CPPUNIT_ASSERT(xStorage.is());
|
|
|
|
aManager.mxStore = xStorage;
|
|
|
|
aManager.maSignatureHelper.SetStorage(xStorage, "1.2");
|
|
|
|
aManager.read(/*bUseTempStream=*/false);
|
|
|
|
std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations;
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size());
|
2016-03-07 12:30:26 +01:00
|
|
|
|
|
|
|
// Then remove the only signature in the document.
|
2016-11-08 14:10:05 +01:00
|
|
|
uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager);
|
2016-11-24 13:42:14 +01:00
|
|
|
if (!xCertificate.is())
|
|
|
|
return;
|
2016-03-07 12:30:26 +01:00
|
|
|
aManager.remove(0);
|
|
|
|
aManager.read(/*bUseTempStream=*/true);
|
2016-11-09 15:14:03 +02:00
|
|
|
aManager.write(/*bXAdESCompliantIfODF=*/false);
|
2016-03-07 12:30:26 +01:00
|
|
|
|
|
|
|
// Make sure that the signature count is zero and the whole signature storage is removed completely.
|
2016-04-04 08:57:19 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), rInformations.size());
|
2016-03-07 12:30:26 +01:00
|
|
|
uno::Reference<container::XNameAccess> xNameAccess(xStorage, uno::UNO_QUERY);
|
|
|
|
CPPUNIT_ASSERT(!xNameAccess->hasByName("_xmlsignatures"));
|
|
|
|
|
|
|
|
// And that content types no longer contains signature types.
|
2017-06-13 10:27:38 +02:00
|
|
|
uno::Reference<io::XStream> xStream(xStorage->openStreamElement("[Content_Types].xml", embed::ElementModes::READWRITE), uno::UNO_QUERY);
|
2016-03-07 12:30:26 +01:00
|
|
|
uno::Reference<io::XInputStream> xInputStream = xStream->getInputStream();
|
|
|
|
uno::Sequence< uno::Sequence<beans::StringPair> > aContentTypeInfo = comphelper::OFOPXMLHelper::ReadContentTypeSequence(xInputStream, mxComponentContext);
|
|
|
|
uno::Sequence<beans::StringPair>& rOverrides = aContentTypeInfo[1];
|
|
|
|
CPPUNIT_ASSERT_EQUAL(rOverrides.end(), std::find_if(rOverrides.begin(), rOverrides.end(), [](const beans::StringPair& rPair)
|
|
|
|
{
|
|
|
|
return rPair.First.startsWith("/_xmlsignatures/sig");
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2016-03-11 14:53:13 +01:00
|
|
|
void SigningTest::testODFGood()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "good.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
// We expect NOTVALIDATED in case the root CA is not imported on the system, and OK otherwise, so accept both.
|
|
|
|
SignatureState nActual = pObjectShell->GetDocumentSignatureState();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
(OString::number(
|
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
|
|
|
.getStr()),
|
|
|
|
(nActual == SignatureState::NOTVALIDATED
|
2016-03-16 15:13:51 +01:00
|
|
|
|| nActual == SignatureState::OK));
|
2016-03-11 14:53:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testODFBroken()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "bad.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
|
|
|
|
}
|
|
|
|
|
2016-11-30 11:01:29 +01:00
|
|
|
void SigningTest::testODFNo()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "no.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::NOSIGNATURES), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
|
|
|
|
}
|
|
|
|
|
2016-02-04 09:31:16 +01:00
|
|
|
void SigningTest::testOOXMLPartial()
|
|
|
|
{
|
2016-03-09 14:14:18 +01:00
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx");
|
2016-02-04 09:31:16 +01:00
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
// This was SignatureState::BROKEN due to missing RelationshipTransform and SHA-256 support.
|
|
|
|
// We expect NOTVALIDATED in case the root CA is not imported on the system, and PARTIAL_OK otherwise, so accept both.
|
2016-02-26 08:53:43 +01:00
|
|
|
SignatureState nActual = pObjectShell->GetDocumentSignatureState();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
(OString::number(
|
2016-02-29 10:21:34 +01:00
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
2016-02-26 08:53:43 +01:00
|
|
|
.getStr()),
|
|
|
|
(nActual == SignatureState::NOTVALIDATED
|
|
|
|
|| nActual == SignatureState::PARTIAL_OK));
|
2016-02-04 09:31:16 +01:00
|
|
|
}
|
|
|
|
|
2016-02-04 09:39:32 +01:00
|
|
|
void SigningTest::testOOXMLBroken()
|
|
|
|
{
|
2016-03-09 14:14:18 +01:00
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "bad.docx");
|
2016-02-04 09:39:32 +01:00
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
// This was SignatureState::NOTVALIDATED/PARTIAL_OK as we did not validate manifest references.
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
|
|
|
|
}
|
|
|
|
|
2016-11-18 19:06:29 +02:00
|
|
|
#if HAVE_FEATURE_PDFIMPORT
|
|
|
|
|
2016-10-13 13:14:04 +02:00
|
|
|
void SigningTest::testPDFGood()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "good.pdf");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
// We expect NOTVALIDATED in case the root CA is not imported on the system, and OK otherwise, so accept both.
|
|
|
|
SignatureState nActual = pObjectShell->GetDocumentSignatureState();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
(OString::number(
|
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
|
|
|
.getStr()),
|
|
|
|
(nActual == SignatureState::NOTVALIDATED
|
|
|
|
|| nActual == SignatureState::OK));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testPDFBad()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "bad.pdf");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testPDFNo()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "no.pdf");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::NOSIGNATURES), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
|
|
|
|
}
|
|
|
|
|
2016-11-18 19:06:29 +02:00
|
|
|
#endif
|
|
|
|
|
2016-04-25 18:39:27 +02:00
|
|
|
void SigningTest::test96097Calc()
|
|
|
|
{
|
|
|
|
createCalc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf96097.ods");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("Failed to access document base model", pBaseModel);
|
|
|
|
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pObjectShell);
|
|
|
|
|
|
|
|
SignatureState nActual = pObjectShell->GetScriptingSignatureState();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
(OString::number(
|
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
|
|
|
.getStr()),
|
|
|
|
(nActual == SignatureState::OK
|
|
|
|
|| nActual == SignatureState::NOTVALIDATED
|
|
|
|
|| nActual == SignatureState::INVALID));
|
|
|
|
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xDocStorable(mxComponent, uno::UNO_QUERY_THROW);
|
|
|
|
CPPUNIT_ASSERT(xDocStorable.is());
|
|
|
|
|
|
|
|
// Save a copy
|
|
|
|
utl::TempFile aTempFileSaveCopy;
|
|
|
|
aTempFileSaveCopy.EnableKillingFile();
|
2017-06-12 09:35:38 +02:00
|
|
|
uno::Sequence<beans::PropertyValue> descSaveACopy(comphelper::InitPropertySequence(
|
|
|
|
{
|
2017-06-09 13:43:00 +02:00
|
|
|
{ "SaveACopy", uno::Any(true) },
|
|
|
|
{ "FilterName", uno::Any(OUString("calc8")) }
|
|
|
|
}));
|
2016-04-25 18:39:27 +02:00
|
|
|
xDocStorable->storeToURL(aTempFileSaveCopy.GetURL(), descSaveACopy);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Save As
|
|
|
|
utl::TempFile aTempFileSaveAs;
|
|
|
|
aTempFileSaveAs.EnableKillingFile();
|
2017-06-12 09:35:38 +02:00
|
|
|
uno::Sequence<beans::PropertyValue> descSaveAs(comphelper::InitPropertySequence(
|
|
|
|
{
|
2017-06-09 13:43:00 +02:00
|
|
|
{ "FilterName", uno::Any(OUString("calc8")) }
|
|
|
|
}));
|
2016-04-25 18:39:27 +02:00
|
|
|
xDocStorable->storeAsURL(aTempFileSaveAs.GetURL(), descSaveAs);
|
|
|
|
}
|
2016-04-29 13:15:58 +02:00
|
|
|
catch (...)
|
2016-04-25 18:39:27 +02:00
|
|
|
{
|
|
|
|
CPPUNIT_FAIL("Fail to save as the document");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::test96097Doc()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf96097.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
|
|
|
|
SignatureState nActual = pObjectShell->GetScriptingSignatureState();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
(OString::number(
|
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
|
|
|
.getStr()),
|
|
|
|
(nActual == SignatureState::OK
|
|
|
|
|| nActual == SignatureState::NOTVALIDATED
|
|
|
|
|| nActual == SignatureState::INVALID));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uno::Reference<frame::XStorable> xDocStorable(mxComponent, uno::UNO_QUERY_THROW);
|
|
|
|
CPPUNIT_ASSERT(xDocStorable.is());
|
|
|
|
|
|
|
|
// Save a copy
|
|
|
|
utl::TempFile aTempFileSaveCopy;
|
|
|
|
aTempFileSaveCopy.EnableKillingFile();
|
2017-06-12 09:35:38 +02:00
|
|
|
uno::Sequence<beans::PropertyValue> descSaveACopy(comphelper::InitPropertySequence(
|
|
|
|
{
|
2017-06-09 13:43:00 +02:00
|
|
|
{ "SaveACopy", uno::Any(true) },
|
|
|
|
{ "FilterName", uno::Any(OUString("writer8")) }
|
|
|
|
}));
|
2016-04-25 18:39:27 +02:00
|
|
|
xDocStorable->storeToURL(aTempFileSaveCopy.GetURL(), descSaveACopy);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Save As
|
|
|
|
utl::TempFile aTempFileSaveAs;
|
|
|
|
aTempFileSaveAs.EnableKillingFile();
|
2017-06-12 09:35:38 +02:00
|
|
|
uno::Sequence<beans::PropertyValue> descSaveAs(comphelper::InitPropertySequence(
|
|
|
|
{
|
2017-06-09 13:43:00 +02:00
|
|
|
{ "FilterName", uno::Any(OUString("writer8")) }
|
|
|
|
}));
|
2016-04-25 18:39:27 +02:00
|
|
|
xDocStorable->storeAsURL(aTempFileSaveAs.GetURL(), descSaveAs);
|
|
|
|
}
|
2016-04-29 13:15:58 +02:00
|
|
|
catch (...)
|
2016-04-25 18:39:27 +02:00
|
|
|
{
|
|
|
|
CPPUNIT_FAIL("Fail to save as the document");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-24 15:39:35 +01:00
|
|
|
void SigningTest::testXAdES()
|
|
|
|
{
|
|
|
|
// Create an empty document, store it to a tempfile and load it as a storage.
|
|
|
|
createDoc(OUString());
|
|
|
|
|
|
|
|
utl::TempFile aTempFile;
|
|
|
|
aTempFile.EnableKillingFile();
|
|
|
|
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
|
|
|
|
utl::MediaDescriptor aMediaDescriptor;
|
|
|
|
aMediaDescriptor["FilterName"] <<= OUString("writer8");
|
|
|
|
xStorable->storeAsURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
|
|
|
|
|
|
|
|
DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content);
|
|
|
|
CPPUNIT_ASSERT(aManager.init());
|
|
|
|
uno::Reference <embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aTempFile.GetURL(), embed::ElementModes::READWRITE);
|
|
|
|
CPPUNIT_ASSERT(xStorage.is());
|
|
|
|
aManager.mxStore = xStorage;
|
|
|
|
aManager.maSignatureHelper.SetStorage(xStorage, "1.2");
|
|
|
|
|
|
|
|
// Create a signature.
|
|
|
|
uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager);
|
|
|
|
if (!xCertificate.is())
|
|
|
|
return;
|
|
|
|
sal_Int32 nSecurityId;
|
2017-06-21 13:34:30 +02:00
|
|
|
aManager.add(xCertificate, mxSecurityContext, /*rDescription=*/OUString(), nSecurityId, /*bAdESCompliant=*/true);
|
2016-11-24 15:39:35 +01:00
|
|
|
|
|
|
|
// Write to storage.
|
|
|
|
aManager.read(/*bUseTempStream=*/true);
|
|
|
|
aManager.write(/*bXAdESCompliantIfODF=*/true);
|
|
|
|
uno::Reference<embed::XTransactedObject> xTransactedObject(xStorage, uno::UNO_QUERY);
|
|
|
|
xTransactedObject->commit();
|
|
|
|
|
|
|
|
// Parse the resulting XML.
|
|
|
|
uno::Reference<embed::XStorage> xMetaInf = xStorage->openStorageElement("META-INF", embed::ElementModes::READ);
|
|
|
|
uno::Reference<io::XInputStream> xInputStream(xMetaInf->openStreamElement("documentsignatures.xml", embed::ElementModes::READ), uno::UNO_QUERY);
|
|
|
|
std::shared_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
|
|
|
|
xmlDocPtr pXmlDoc = parseXmlStream(pStream.get());
|
|
|
|
|
|
|
|
// Assert that the digest algorithm is SHA-256 in the bAdESCompliant case, not SHA-1.
|
|
|
|
assertXPath(pXmlDoc, "/odfds:document-signatures/dsig:Signature/dsig:SignedInfo/dsig:Reference[@URI='content.xml']/dsig:DigestMethod", "Algorithm", ALGO_XMLDSIGSHA256);
|
|
|
|
|
|
|
|
// Assert that the digest of the signing certificate is included.
|
|
|
|
assertXPath(pXmlDoc, "//xd:CertDigest", 1);
|
|
|
|
}
|
|
|
|
|
2016-11-30 11:01:29 +01:00
|
|
|
void SigningTest::testXAdESGood()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "good-xades.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
// We expect NOTVALIDATED in case the root CA is not imported on the system, and OK otherwise, so accept both.
|
|
|
|
SignatureState nActual = pObjectShell->GetDocumentSignatureState();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
(OString::number(
|
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
|
|
|
.getStr()),
|
|
|
|
(nActual == SignatureState::NOTVALIDATED
|
|
|
|
|| nActual == SignatureState::OK));
|
|
|
|
}
|
2017-11-02 15:47:32 +01:00
|
|
|
|
|
|
|
void SigningTest::testSignatureLineImages()
|
|
|
|
{
|
|
|
|
// Given: A document (docx) with a signature line and a valid signature
|
|
|
|
uno::Reference< security::XDocumentDigitalSignatures > xSignatures(
|
|
|
|
security::DocumentDigitalSignatures::createWithVersion(
|
2017-11-07 09:02:11 +01:00
|
|
|
comphelper::getProcessComponentContext(), "1.2"));
|
2017-11-02 15:47:32 +01:00
|
|
|
|
|
|
|
uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
|
2017-11-07 09:02:11 +01:00
|
|
|
ZIP_STORAGE_FORMAT_STRING, m_directories.getURLFromSrc(DATA_DIRECTORY) + "signatureline.docx",
|
|
|
|
embed::ElementModes::READ);
|
2017-11-02 15:47:32 +01:00
|
|
|
CPPUNIT_ASSERT(xStorage.is());
|
|
|
|
|
|
|
|
uno::Sequence< security::DocumentSignatureInformation > xSignatureInfo =
|
|
|
|
xSignatures->verifyScriptingContentSignatures(xStorage, uno::Reference< io::XInputStream >());
|
|
|
|
|
|
|
|
// The signature should have a valid signature, and signature line with two valid images
|
|
|
|
CPPUNIT_ASSERT(xSignatureInfo[0].SignatureIsValid);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(OUString("{DEE0514B-13E8-4674-A831-46E3CDB18BB4}"), xSignatureInfo[0].SignatureLineId);
|
|
|
|
CPPUNIT_ASSERT(xSignatureInfo[0].ValidSignatureLineImage.is());
|
|
|
|
CPPUNIT_ASSERT(xSignatureInfo[0].InvalidSignatureLineImage.is());
|
|
|
|
}
|
|
|
|
|
2017-12-08 00:10:42 +01:00
|
|
|
#if HAVE_FEATURE_GPGVERIFY
|
2017-12-06 14:02:25 +01:00
|
|
|
void SigningTest::testODFGoodGPG()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "goodGPG.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
// Our local gpg config fully trusts the signing cert, so in
|
|
|
|
// contrast to the X509 test we can fail on NOTVALIDATED here
|
|
|
|
SignatureState nActual = pObjectShell->GetDocumentSignatureState();
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE(
|
|
|
|
(OString::number(
|
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
|
|
|
.getStr()),
|
|
|
|
nActual, SignatureState::OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testODFUntrustedGoodGPG()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "untrustedGoodGPG.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
// Our local gpg config does _not_ trust the signing cert, so in
|
|
|
|
// contrast to the X509 test we can fail everything but
|
|
|
|
// NOTVALIDATED here
|
|
|
|
SignatureState nActual = pObjectShell->GetDocumentSignatureState();
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE(
|
|
|
|
(OString::number(
|
|
|
|
static_cast<std::underlying_type<SignatureState>::type>(nActual))
|
|
|
|
.getStr()),
|
|
|
|
nActual, SignatureState::NOTVALIDATED);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testODFBrokenStreamGPG()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "badStreamGPG.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SigningTest::testODFBrokenDsigGPG()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "badDsigGPG.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
|
|
|
|
}
|
2018-01-13 04:17:37 +01:00
|
|
|
|
2018-03-18 11:25:41 +01:00
|
|
|
#if HAVE_GPGCONF_SOCKETDIR
|
|
|
|
|
2018-01-13 04:17:37 +01:00
|
|
|
void SigningTest::testODFEncryptedGPG()
|
|
|
|
{
|
|
|
|
createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "encryptedGPG.odt");
|
|
|
|
SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
|
|
|
|
CPPUNIT_ASSERT(pBaseModel);
|
|
|
|
SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
|
|
|
|
CPPUNIT_ASSERT(pObjectShell);
|
|
|
|
}
|
|
|
|
|
2017-12-06 14:02:25 +01:00
|
|
|
#endif
|
|
|
|
|
2018-03-18 11:25:41 +01:00
|
|
|
#endif
|
|
|
|
|
2016-11-24 15:39:35 +01:00
|
|
|
void SigningTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
|
|
|
|
{
|
|
|
|
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("odfds"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0"));
|
|
|
|
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#"));
|
|
|
|
}
|
|
|
|
|
2016-01-11 15:46:10 +01:00
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(SigningTest);
|
|
|
|
|
|
|
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|