[Libreoffice-commits] core.git: 2 commits - xmlsecurity/Library_xmlsecurity.mk xmlsecurity/qa xmlsecurity/source

Miklos Vajna vmiklos at collabora.co.uk
Fri Mar 11 16:37:39 UTC 2016


 xmlsecurity/Library_xmlsecurity.mk             |    1 
 xmlsecurity/qa/unit/signing/data/bad.odt       |binary
 xmlsecurity/qa/unit/signing/data/good.odt      |binary
 xmlsecurity/qa/unit/signing/signing.cxx        |   34 +
 xmlsecurity/source/helper/ooxmlsecexporter.cxx |  504 +++++++++++++++++++++++++
 xmlsecurity/source/helper/ooxmlsecexporter.hxx |   37 +
 xmlsecurity/source/helper/xsecctl.cxx          |  365 ------------------
 7 files changed, 579 insertions(+), 362 deletions(-)

New commits:
commit 27fc89cce931039f8f585c10b8ee41023c777b5e
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Mar 11 17:09:02 2016 +0100

    xmlsecurity: extract OOXML export code into its own class
    
    It was odd that import code had its own OOXMLSecParser, but export code
    was buried in the controller.
    
    Change-Id: Ie1964bf9c54a8b779981e8d72bf4810090cf960c

diff --git a/xmlsecurity/Library_xmlsecurity.mk b/xmlsecurity/Library_xmlsecurity.mk
index c594ec9..1997010 100644
--- a/xmlsecurity/Library_xmlsecurity.mk
+++ b/xmlsecurity/Library_xmlsecurity.mk
@@ -56,6 +56,7 @@ $(eval $(call gb_Library_add_exception_objects,xmlsecurity,\
 	xmlsecurity/source/helper/documentsignaturehelper \
 	xmlsecurity/source/helper/documentsignaturemanager \
 	xmlsecurity/source/helper/ooxmlsecparser \
+	xmlsecurity/source/helper/ooxmlsecexporter \
 	xmlsecurity/source/helper/xmlsignaturehelper2 \
 	xmlsecurity/source/helper/xmlsignaturehelper \
 	xmlsecurity/source/helper/xsecctl \
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
new file mode 100644
index 0000000..d88d542
--- /dev/null
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
@@ -0,0 +1,504 @@
+/* -*- 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 "ooxmlsecexporter.hxx"
+
+#include <algorithm>
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/beans/StringPair.hpp>
+
+#include <comphelper/ofopxmlhelper.hxx>
+#include <config_global.h>
+#include <o3tl/make_unique.hxx>
+#include <rtl/ref.hxx>
+#include <unotools/datetime.hxx>
+#include <xmloff/attrlist.hxx>
+
+#include <xsecctl.hxx>
+
+using namespace com::sun::star;
+
+struct OOXMLSecExporter::Impl
+{
+    const uno::Reference<uno::XComponentContext>& m_xComponentContext;
+    const uno::Reference<embed::XStorage>& m_xRootStorage;
+    const uno::Reference<xml::sax::XDocumentHandler>& m_xDocumentHandler;
+    const SignatureInformation& m_rInformation;
+    OUString m_aSignatureTimeValue;
+
+    Impl(const uno::Reference<uno::XComponentContext>& xComponentContext,
+         const uno::Reference<embed::XStorage>& xRootStorage,
+         const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
+         const SignatureInformation& rInformation)
+        : m_xComponentContext(xComponentContext)
+        , m_xRootStorage(xRootStorage)
+        , m_xDocumentHandler(xDocumentHandler)
+        , m_rInformation(rInformation)
+    {
+    }
+
+    /// Should we intentionally not sign this stream?
+    static bool isOOXMLBlacklist(const OUString& rStreamName);
+    /// Should we intentionally not sign this relation type?
+    static bool isOOXMLRelationBlacklist(const OUString& rRelationName);
+
+    void writeSignedInfo();
+    void writeCanonicalizationMethod();
+    void writeCanonicalizationTransform();
+    void writeDigestMethod();
+    void writeSignatureMethod();
+    void writeSignedInfoReferences();
+    void writeSignatureValue();
+    void writeKeyInfo();
+    void writePackageObject();
+    void writeManifest();
+    void writeRelationshipTransform(const OUString& rURI);
+    /// Writes <SignatureProperties> inside idPackageObject.
+    void writePackageObjectSignatureProperties();
+    /// Writes a single <Reference> inside <Manifest>.
+    void writeManifestReference(const SignatureReferenceInformation& rReference);
+    void writeOfficeObject();
+    /// Writes <SignatureInfoV1>.
+    void writeSignatureInfo();
+    void writePackageSignature();
+    void writeSignedProperties();
+};
+
+bool OOXMLSecExporter::Impl::isOOXMLBlacklist(const OUString& rStreamName)
+{
+#if !HAVE_BROKEN_STATIC_INITILIZER_LIST
+    static
+#endif
+    const std::initializer_list<OUStringLiteral> vBlacklist =
+    {
+        OUStringLiteral("/%5BContent_Types%5D.xml"),
+        OUStringLiteral("/docProps/app.xml"),
+        OUStringLiteral("/docProps/core.xml"),
+        // Don't attempt to sign other signatures for now.
+        OUStringLiteral("/_xmlsignatures")
+    };
+    // Just check the prefix, as we don't care about the content type part of the stream name.
+    return std::find_if(vBlacklist.begin(), vBlacklist.end(), [&](const OUStringLiteral& rLiteral)
+    {
+        return rStreamName.startsWith(rLiteral);
+    }) != vBlacklist.end();
+}
+
+bool OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(const OUString& rRelationName)
+{
+#if !HAVE_BROKEN_STATIC_INITILIZER_LIST
+    static
+#endif
+    const std::initializer_list<OUStringLiteral> vBlacklist =
+    {
+        OUStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"),
+        OUStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"),
+        OUStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin")
+    };
+    return std::find(vBlacklist.begin(), vBlacklist.end(), rRelationName) != vBlacklist.end();
+}
+
+void OOXMLSecExporter::Impl::writeSignedInfo()
+{
+    m_xDocumentHandler->startElement(TAG_SIGNEDINFO, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+
+    writeCanonicalizationMethod();
+    writeSignatureMethod();
+    writeSignedInfoReferences();
+
+    m_xDocumentHandler->endElement(TAG_SIGNEDINFO);
+}
+
+void OOXMLSecExporter::Impl::writeCanonicalizationMethod()
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_C14N);
+    m_xDocumentHandler->startElement(TAG_CANONICALIZATIONMETHOD, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->endElement(TAG_CANONICALIZATIONMETHOD);
+
+}
+
+void OOXMLSecExporter::Impl::writeCanonicalizationTransform()
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_C14N);
+    m_xDocumentHandler->startElement(TAG_TRANSFORM, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->endElement(TAG_TRANSFORM);
+
+}
+
+void OOXMLSecExporter::Impl::writeDigestMethod()
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_XMLDSIGSHA256);
+    m_xDocumentHandler->startElement(TAG_DIGESTMETHOD, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->endElement(TAG_DIGESTMETHOD);
+}
+
+void OOXMLSecExporter::Impl::writeSignatureMethod()
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_RSASHA256);
+    m_xDocumentHandler->startElement(TAG_SIGNATUREMETHOD, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->endElement(TAG_SIGNATUREMETHOD);
+}
+
+void OOXMLSecExporter::Impl::writeSignedInfoReferences()
+{
+    const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
+    for (const SignatureReferenceInformation& rReference : rReferences)
+    {
+        if (rReference.nType == SignatureReferenceType::SAMEDOCUMENT)
+        {
+            {
+                rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+                if (rReference.ouURI != "idSignedProperties")
+                    pAttributeList->AddAttribute("Type", "http://www.w3.org/2000/09/xmldsig#Object");
+                else
+                    pAttributeList->AddAttribute("Type", "http://uri.etsi.org/01903#SignedProperties");
+                pAttributeList->AddAttribute(ATTR_URI, CHAR_FRAGMENT + rReference.ouURI);
+                m_xDocumentHandler->startElement(TAG_REFERENCE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+            }
+            if (rReference.ouURI == "idSignedProperties")
+            {
+                m_xDocumentHandler->startElement(TAG_TRANSFORMS, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+                writeCanonicalizationTransform();
+                m_xDocumentHandler->endElement(TAG_TRANSFORMS);
+            }
+
+            writeDigestMethod();
+            m_xDocumentHandler->startElement(TAG_DIGESTVALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+            m_xDocumentHandler->characters(rReference.ouDigestValue);
+            m_xDocumentHandler->endElement(TAG_DIGESTVALUE);
+            m_xDocumentHandler->endElement(TAG_REFERENCE);
+        }
+    }
+}
+
+void OOXMLSecExporter::Impl::writeSignatureValue()
+{
+    m_xDocumentHandler->startElement(TAG_SIGNATUREVALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters(m_rInformation.ouSignatureValue);
+    m_xDocumentHandler->endElement(TAG_SIGNATUREVALUE);
+}
+
+void OOXMLSecExporter::Impl::writeKeyInfo()
+{
+    m_xDocumentHandler->startElement(TAG_KEYINFO, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(TAG_X509DATA, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(TAG_X509CERTIFICATE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
+    m_xDocumentHandler->endElement(TAG_X509CERTIFICATE);
+    m_xDocumentHandler->endElement(TAG_X509DATA);
+    m_xDocumentHandler->endElement(TAG_KEYINFO);
+}
+
+void OOXMLSecExporter::Impl::writePackageObject()
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_ID, "idPackageObject");
+    m_xDocumentHandler->startElement(TAG_OBJECT, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+    writeManifest();
+    writePackageObjectSignatureProperties();
+
+    m_xDocumentHandler->endElement(TAG_OBJECT);
+}
+
+void OOXMLSecExporter::Impl::writeManifest()
+{
+    m_xDocumentHandler->startElement(TAG_MANIFEST, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
+    for (const SignatureReferenceInformation& rReference : rReferences)
+    {
+        if (rReference.nType != SignatureReferenceType::SAMEDOCUMENT)
+        {
+            if (OOXMLSecExporter::Impl::isOOXMLBlacklist(rReference.ouURI))
+                continue;
+
+            writeManifestReference(rReference);
+        }
+    }
+    m_xDocumentHandler->endElement(TAG_MANIFEST);
+}
+
+void OOXMLSecExporter::Impl::writeRelationshipTransform(const OUString& rURI)
+{
+    uno::Reference<embed::XHierarchicalStorageAccess> xHierarchicalStorageAccess(m_xRootStorage, uno::UNO_QUERY);
+    uno::Reference<io::XInputStream> xRelStream(xHierarchicalStorageAccess->openStreamElementByHierarchicalName(rURI, embed::ElementModes::READ), uno::UNO_QUERY);
+    {
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_RELATIONSHIP);
+        m_xDocumentHandler->startElement(TAG_TRANSFORM, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    }
+
+    uno::Sequence< uno::Sequence<beans::StringPair> > aRelationsInfo = comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, rURI, m_xComponentContext);
+    for (const uno::Sequence<beans::StringPair>& rPairs : aRelationsInfo)
+    {
+        OUString aId;
+        OUString aType;
+        for (const beans::StringPair& rPair : rPairs)
+        {
+            if (rPair.First == "Id")
+                aId = rPair.Second;
+            else if (rPair.First == "Type")
+                aType = rPair.Second;
+        }
+
+        if (OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(aType))
+            continue;
+
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_XMLNS ":" NSTAG_MDSSI, NS_MDSSI);
+        pAttributeList->AddAttribute(ATTR_SOURCEID, aId);
+        m_xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_RELATIONSHIPREFERENCE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+        m_xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_RELATIONSHIPREFERENCE);
+    }
+
+    m_xDocumentHandler->endElement(TAG_TRANSFORM);
+}
+
+void OOXMLSecExporter::Impl::writePackageObjectSignatureProperties()
+{
+    m_xDocumentHandler->startElement(TAG_SIGNATUREPROPERTIES, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    {
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_ID, "idSignatureTime");
+        pAttributeList->AddAttribute(ATTR_TARGET, "#idPackageSignature");
+        m_xDocumentHandler->startElement(TAG_SIGNATUREPROPERTY, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    }
+    {
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_XMLNS ":" NSTAG_MDSSI, NS_MDSSI);
+        m_xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_SIGNATURETIME, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    }
+    m_xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_FORMAT, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("YYYY-MM-DDThh:mm:ssTZD");
+    m_xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_FORMAT);
+
+    m_xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_VALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    if (!m_rInformation.ouDateTime.isEmpty())
+        m_aSignatureTimeValue = m_rInformation.ouDateTime;
+    else
+    {
+        m_aSignatureTimeValue = utl::toISO8601(m_rInformation.stDateTime);
+        // Ignore sub-seconds.
+        sal_Int32 nCommaPos = m_aSignatureTimeValue.indexOf(',');
+        if (nCommaPos != -1)
+        {
+            m_aSignatureTimeValue = m_aSignatureTimeValue.copy(0, nCommaPos);
+            m_aSignatureTimeValue += "Z";
+        }
+    }
+    m_xDocumentHandler->characters(m_aSignatureTimeValue);
+    m_xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_VALUE);
+
+    m_xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_SIGNATURETIME);
+    m_xDocumentHandler->endElement(TAG_SIGNATUREPROPERTY);
+    m_xDocumentHandler->endElement(TAG_SIGNATUREPROPERTIES);
+}
+
+void OOXMLSecExporter::Impl::writeManifestReference(const SignatureReferenceInformation& rReference)
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_URI, rReference.ouURI);
+    m_xDocumentHandler->startElement(TAG_REFERENCE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+    // Transforms
+    if (rReference.ouURI.endsWith("?ContentType=application/vnd.openxmlformats-package.relationships+xml"))
+    {
+        OUString aURI = rReference.ouURI;
+        // Ignore leading slash.
+        if (aURI.startsWith("/"))
+            aURI = aURI.copy(1);
+        // Ignore query part of the URI.
+        sal_Int32 nQueryPos = aURI.indexOf('?');
+        if (nQueryPos != -1)
+            aURI = aURI.copy(0, nQueryPos);
+
+        m_xDocumentHandler->startElement(TAG_TRANSFORMS, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+
+        writeRelationshipTransform(aURI);
+        writeCanonicalizationTransform();
+
+        m_xDocumentHandler->endElement(TAG_TRANSFORMS);
+    }
+
+    writeDigestMethod();
+    m_xDocumentHandler->startElement(TAG_DIGESTVALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters(rReference.ouDigestValue);
+    m_xDocumentHandler->endElement(TAG_DIGESTVALUE);
+    m_xDocumentHandler->endElement(TAG_REFERENCE);
+}
+
+void OOXMLSecExporter::Impl::writeOfficeObject()
+{
+    {
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_ID, "idOfficeObject");
+        m_xDocumentHandler->startElement(TAG_OBJECT, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    }
+    m_xDocumentHandler->startElement(TAG_SIGNATUREPROPERTIES, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    {
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_ID, "idOfficeV1Details");
+        pAttributeList->AddAttribute(ATTR_TARGET, "#idPackageSignature");
+        m_xDocumentHandler->startElement(TAG_SIGNATUREPROPERTY, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    }
+    writeSignatureInfo();
+    m_xDocumentHandler->endElement(TAG_SIGNATUREPROPERTY);
+    m_xDocumentHandler->endElement(TAG_SIGNATUREPROPERTIES);
+    m_xDocumentHandler->endElement(TAG_OBJECT);
+}
+
+void OOXMLSecExporter::Impl::writeSignatureInfo()
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_XMLNS, "http://schemas.microsoft.com/office/2006/digsig");
+    m_xDocumentHandler->startElement("SignatureInfoV1", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+    m_xDocumentHandler->startElement("SetupId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->endElement("SetupId");
+    m_xDocumentHandler->startElement("SignatureText", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->endElement("SignatureText");
+    m_xDocumentHandler->startElement("SignatureImage", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->endElement("SignatureImage");
+    m_xDocumentHandler->startElement("SignatureComments", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters(m_rInformation.ouDescription);
+    m_xDocumentHandler->endElement("SignatureComments");
+    // Just hardcode something valid according to [MS-OFFCRYPTO].
+    m_xDocumentHandler->startElement("WindowsVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("6.1");
+    m_xDocumentHandler->endElement("WindowsVersion");
+    m_xDocumentHandler->startElement("OfficeVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("16.0");
+    m_xDocumentHandler->endElement("OfficeVersion");
+    m_xDocumentHandler->startElement("ApplicationVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("16.0");
+    m_xDocumentHandler->endElement("ApplicationVersion");
+    m_xDocumentHandler->startElement("Monitors", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("1");
+    m_xDocumentHandler->endElement("Monitors");
+    m_xDocumentHandler->startElement("HorizontalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("1280");
+    m_xDocumentHandler->endElement("HorizontalResolution");
+    m_xDocumentHandler->startElement("VerticalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("800");
+    m_xDocumentHandler->endElement("VerticalResolution");
+    m_xDocumentHandler->startElement("ColorDepth", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("32");
+    m_xDocumentHandler->endElement("ColorDepth");
+    m_xDocumentHandler->startElement("SignatureProviderId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("{00000000-0000-0000-0000-000000000000}");
+    m_xDocumentHandler->endElement("SignatureProviderId");
+    m_xDocumentHandler->startElement("SignatureProviderUrl", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->endElement("SignatureProviderUrl");
+    m_xDocumentHandler->startElement("SignatureProviderDetails", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("9"); // This is what MSO 2016 writes, though [MS-OFFCRYPTO] doesn't document what the value means.
+    m_xDocumentHandler->endElement("SignatureProviderDetails");
+    m_xDocumentHandler->startElement("SignatureType", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters("1");
+    m_xDocumentHandler->endElement("SignatureType");
+
+    m_xDocumentHandler->endElement("SignatureInfoV1");
+}
+
+void OOXMLSecExporter::Impl::writePackageSignature()
+{
+    m_xDocumentHandler->startElement(TAG_OBJECT, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    {
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_XMLNS ":" NSTAG_XD, NS_XD);
+        pAttributeList->AddAttribute(ATTR_TARGET, "#idPackageSignature");
+        m_xDocumentHandler->startElement(NSTAG_XD ":" TAG_QUALIFYINGPROPERTIES, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    }
+
+    // FIXME why does this part crash NSS when MOZILLA_CERTIFICATE_FOLDER is not set?
+    static bool bTest = getenv("LO_TESTNAME");
+    if (!bTest)
+        writeSignedProperties();
+
+    m_xDocumentHandler->endElement(NSTAG_XD ":" TAG_QUALIFYINGPROPERTIES);
+    m_xDocumentHandler->endElement(TAG_OBJECT);
+}
+
+void OOXMLSecExporter::Impl::writeSignedProperties()
+{
+    {
+        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+        pAttributeList->AddAttribute(ATTR_ID, "idSignedProperties");
+        m_xDocumentHandler->startElement(NSTAG_XD ":" TAG_SIGNEDPROPERTIES, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    }
+
+    m_xDocumentHandler->startElement("xd:SignedSignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement("xd:SigningTime", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters(m_aSignatureTimeValue);
+    m_xDocumentHandler->endElement("xd:SigningTime");
+    m_xDocumentHandler->startElement("xd:SigningCertificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement("xd:Cert", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement("xd:CertDigest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    writeDigestMethod();
+
+    m_xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    assert(!m_rInformation.ouCertDigest.isEmpty());
+    m_xDocumentHandler->characters(m_rInformation.ouCertDigest);
+    m_xDocumentHandler->endElement("DigestValue");
+
+    m_xDocumentHandler->endElement("xd:CertDigest");
+    m_xDocumentHandler->startElement("xd:IssuerSerial", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement("X509IssuerName", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters(m_rInformation.ouX509IssuerName);
+    m_xDocumentHandler->endElement("X509IssuerName");
+    m_xDocumentHandler->startElement("X509SerialNumber", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->characters(m_rInformation.ouX509SerialNumber);
+    m_xDocumentHandler->endElement("X509SerialNumber");
+    m_xDocumentHandler->endElement("xd:IssuerSerial");
+    m_xDocumentHandler->endElement("xd:Cert");
+    m_xDocumentHandler->endElement("xd:SigningCertificate");
+    m_xDocumentHandler->startElement("xd:SignaturePolicyIdentifier", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement("xd:SignaturePolicyImplied", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->endElement("xd:SignaturePolicyImplied");
+    m_xDocumentHandler->endElement("xd:SignaturePolicyIdentifier");
+    m_xDocumentHandler->endElement("xd:SignedSignatureProperties");
+
+    m_xDocumentHandler->endElement(NSTAG_XD ":" TAG_SIGNEDPROPERTIES);
+}
+
+OOXMLSecExporter::OOXMLSecExporter(const uno::Reference<uno::XComponentContext>& xComponentContext,
+                                   const uno::Reference<embed::XStorage>& xRootStorage,
+                                   const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
+                                   const SignatureInformation& rInformation)
+    : m_pImpl(o3tl::make_unique<Impl>(xComponentContext, xRootStorage, xDocumentHandler, rInformation))
+{
+}
+
+OOXMLSecExporter::~OOXMLSecExporter()
+{
+}
+
+void OOXMLSecExporter::writeSignature()
+{
+    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+    pAttributeList->AddAttribute(ATTR_XMLNS, NS_XMLDSIG);
+    pAttributeList->AddAttribute(ATTR_ID, "idPackageSignature");
+    m_pImpl->m_xDocumentHandler->startElement(TAG_SIGNATURE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+    m_pImpl->writeSignedInfo();
+    m_pImpl->writeSignatureValue();
+    m_pImpl->writeKeyInfo();
+    m_pImpl->writePackageObject();
+    m_pImpl->writeOfficeObject();
+    m_pImpl->writePackageSignature();
+
+    m_pImpl->m_xDocumentHandler->endElement(TAG_SIGNATURE);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.hxx b/xmlsecurity/source/helper/ooxmlsecexporter.hxx
new file mode 100644
index 0000000..3b3d04e
--- /dev/null
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.hxx
@@ -0,0 +1,37 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_XMLSECURITY_SOURCE_HELPER_OOXMLSECEXPORTER_HXX
+#define INCLUDED_XMLSECURITY_SOURCE_HELPER_OOXMLSECEXPORTER_HXX
+
+#include <memory>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <xmlsecurity/sigstruct.hxx>
+
+/// Writes a single OOXML digital signature.
+class OOXMLSecExporter
+{
+    struct Impl;
+    std::unique_ptr<Impl> m_pImpl;
+
+public:
+    OOXMLSecExporter(const css::uno::Reference<css::uno::XComponentContext>& xComponentContext,
+                     const css::uno::Reference<css::embed::XStorage>& xRootStorage,
+                     const css::uno::Reference<css::xml::sax::XDocumentHandler>& xDocumentHandler,
+                     const SignatureInformation& rInformation);
+    ~OOXMLSecExporter();
+    void writeSignature();
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecctl.cxx b/xmlsecurity/source/helper/xsecctl.cxx
index 676e60d..f0271b8 100644
--- a/xmlsecurity/source/helper/xsecctl.cxx
+++ b/xmlsecurity/source/helper/xsecctl.cxx
@@ -39,6 +39,7 @@
 #include <unotools/datetime.hxx>
 #include <comphelper/ofopxmlhelper.hxx>
 #include <sax/tools/converter.hxx>
+#include <ooxmlsecexporter.hxx>
 
 namespace cssu = com::sun::star::uno;
 namespace cssl = com::sun::star::lang;
@@ -854,370 +855,10 @@ void XSecController::exportSignature(
     xDocumentHandler->endElement( tag_Signature );
 }
 
-/// Should we intentionally not sign this stream?
-static bool lcl_isOOXMLBlacklist(const OUString& rStreamName)
-{
-#if !HAVE_BROKEN_STATIC_INITILIZER_LIST
-    static
-#endif
-    const std::initializer_list<OUStringLiteral> vBlacklist =
-    {
-        OUStringLiteral("/%5BContent_Types%5D.xml"),
-        OUStringLiteral("/docProps/app.xml"),
-        OUStringLiteral("/docProps/core.xml"),
-        // Don't attempt to sign other signatures for now.
-        OUStringLiteral("/_xmlsignatures")
-    };
-    // Just check the prefix, as we don't care about the content type part of the stream name.
-    return std::find_if(vBlacklist.begin(), vBlacklist.end(), [&](const OUStringLiteral& rLiteral) { return rStreamName.startsWith(rLiteral); }) != vBlacklist.end();
-}
-
-/// Should we intentionally not sign this relation type?
-static bool lcl_isOOXMLRelationBlacklist(const OUString& rRelationName)
-{
-#if !HAVE_BROKEN_STATIC_INITILIZER_LIST
-    static
-#endif
-    const std::initializer_list<OUStringLiteral> vBlacklist =
-    {
-        OUStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"),
-        OUStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"),
-        OUStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin")
-    };
-    return std::find(vBlacklist.begin(), vBlacklist.end(), rRelationName) != vBlacklist.end();
-}
-
 void XSecController::exportOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler, const SignatureInformation& rInformation)
 {
-    uno::Reference<embed::XHierarchicalStorageAccess> xHierarchicalStorageAccess(xRootStorage, uno::UNO_QUERY);
-
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_XMLNS, NS_XMLDSIG);
-        pAttributeList->AddAttribute(ATTR_ID, "idPackageSignature");
-        xDocumentHandler->startElement(TAG_SIGNATURE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-    xDocumentHandler->startElement(TAG_SIGNEDINFO, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_C14N);
-        xDocumentHandler->startElement(TAG_CANONICALIZATIONMETHOD, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-        xDocumentHandler->endElement(TAG_CANONICALIZATIONMETHOD);
-    }
-
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_RSASHA256);
-        xDocumentHandler->startElement(TAG_SIGNATUREMETHOD, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-        xDocumentHandler->endElement(TAG_SIGNATUREMETHOD);
-    }
-
-    const SignatureReferenceInformations& rReferences = rInformation.vSignatureReferenceInfors;
-    for (const SignatureReferenceInformation& rReference : rReferences)
-    {
-        if (rReference.nType == SignatureReferenceType::SAMEDOCUMENT)
-        {
-            {
-                rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                if (rReference.ouURI != "idSignedProperties")
-                    pAttributeList->AddAttribute("Type", "http://www.w3.org/2000/09/xmldsig#Object");
-                else
-                    pAttributeList->AddAttribute("Type", "http://uri.etsi.org/01903#SignedProperties");
-                pAttributeList->AddAttribute(ATTR_URI, CHAR_FRAGMENT + rReference.ouURI);
-                xDocumentHandler->startElement(TAG_REFERENCE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-            }
-            if (rReference.ouURI == "idSignedProperties")
-            {
-                xDocumentHandler->startElement(TAG_TRANSFORMS, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-                rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_C14N);
-                xDocumentHandler->startElement(TAG_TRANSFORM, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-                xDocumentHandler->endElement(TAG_TRANSFORM);
-                xDocumentHandler->endElement(TAG_TRANSFORMS);
-            }
-
-            {
-                rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_XMLDSIGSHA256);
-                xDocumentHandler->startElement(TAG_DIGESTMETHOD, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-                xDocumentHandler->endElement(TAG_DIGESTMETHOD);
-            }
-            xDocumentHandler->startElement(TAG_DIGESTVALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-            xDocumentHandler->characters(rReference.ouDigestValue);
-            xDocumentHandler->endElement(TAG_DIGESTVALUE);
-            xDocumentHandler->endElement(TAG_REFERENCE);
-        }
-    }
-
-    xDocumentHandler->endElement(TAG_SIGNEDINFO);
-
-    xDocumentHandler->startElement(TAG_SIGNATUREVALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters(rInformation.ouSignatureValue);
-    xDocumentHandler->endElement(TAG_SIGNATUREVALUE);
-
-    xDocumentHandler->startElement(TAG_KEYINFO, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->startElement(TAG_X509DATA, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->startElement(TAG_X509CERTIFICATE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters(rInformation.ouX509Certificate);
-    xDocumentHandler->endElement(TAG_X509CERTIFICATE);
-    xDocumentHandler->endElement(TAG_X509DATA);
-    xDocumentHandler->endElement(TAG_KEYINFO);
-
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_ID, "idPackageObject");
-        xDocumentHandler->startElement(TAG_OBJECT, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-    xDocumentHandler->startElement(TAG_MANIFEST, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    for (const SignatureReferenceInformation& rReference : rReferences)
-    {
-        if (rReference.nType != SignatureReferenceType::SAMEDOCUMENT)
-        {
-            if (lcl_isOOXMLBlacklist(rReference.ouURI))
-                continue;
-
-            {
-                rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                pAttributeList->AddAttribute(ATTR_URI, rReference.ouURI);
-                xDocumentHandler->startElement(TAG_REFERENCE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-            }
-
-            // Transforms
-            if (rReference.ouURI.endsWith("?ContentType=application/vnd.openxmlformats-package.relationships+xml"))
-            {
-                OUString aURI = rReference.ouURI;
-                // Ignore leading slash.
-                if (aURI.startsWith("/"))
-                    aURI = aURI.copy(1);
-                // Ignore query part of the URI.
-                sal_Int32 nQueryPos = aURI.indexOf('?');
-                if (nQueryPos != -1)
-                    aURI = aURI.copy(0, nQueryPos);
-
-                uno::Reference<io::XInputStream> xRelStream(xHierarchicalStorageAccess->openStreamElementByHierarchicalName(aURI, embed::ElementModes::READ), uno::UNO_QUERY);
-                xDocumentHandler->startElement(TAG_TRANSFORMS, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-                {
-                    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                    pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_RELATIONSHIP);
-                    xDocumentHandler->startElement(TAG_TRANSFORM, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-                }
-
-                uno::Sequence< uno::Sequence<beans::StringPair> > aRelationsInfo = comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, aURI, mxCtx);
-                for (const uno::Sequence<beans::StringPair>& rPairs : aRelationsInfo)
-                {
-                    OUString aId;
-                    OUString aType;
-                    for (const beans::StringPair& rPair : rPairs)
-                    {
-                        if (rPair.First == "Id")
-                            aId = rPair.Second;
-                        else if (rPair.First == "Type")
-                            aType = rPair.Second;
-                    }
-
-                    if (lcl_isOOXMLRelationBlacklist(aType))
-                        continue;
-
-                    {
-                        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                        pAttributeList->AddAttribute(ATTR_XMLNS ":" NSTAG_MDSSI, NS_MDSSI);
-                        pAttributeList->AddAttribute(ATTR_SOURCEID, aId);
-                        xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_RELATIONSHIPREFERENCE, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-                    }
-                    xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_RELATIONSHIPREFERENCE);
-                }
-
-                xDocumentHandler->endElement(TAG_TRANSFORM);
-                {
-                    rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                    pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_C14N);
-                    xDocumentHandler->startElement(TAG_TRANSFORM, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-                }
-                xDocumentHandler->endElement(TAG_TRANSFORM);
-                xDocumentHandler->endElement(TAG_TRANSFORMS);
-            }
-
-            {
-                rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-                pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_XMLDSIGSHA256);
-                xDocumentHandler->startElement(TAG_DIGESTMETHOD, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-                xDocumentHandler->endElement(TAG_DIGESTMETHOD);
-            }
-            xDocumentHandler->startElement(TAG_DIGESTVALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-            xDocumentHandler->characters(rReference.ouDigestValue);
-            xDocumentHandler->endElement(TAG_DIGESTVALUE);
-            xDocumentHandler->endElement(TAG_REFERENCE);
-        }
-    }
-    xDocumentHandler->endElement(TAG_MANIFEST);
-
-    // SignatureProperties
-    xDocumentHandler->startElement(TAG_SIGNATUREPROPERTIES, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_ID, "idSignatureTime");
-        pAttributeList->AddAttribute(ATTR_TARGET, "#idPackageSignature");
-        xDocumentHandler->startElement(TAG_SIGNATUREPROPERTY, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_XMLNS ":" NSTAG_MDSSI, NS_MDSSI);
-        xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_SIGNATURETIME, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-    xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_FORMAT, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("YYYY-MM-DDThh:mm:ssTZD");
-    xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_FORMAT);
-
-    xDocumentHandler->startElement(NSTAG_MDSSI ":" TAG_VALUE, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    OUString aSignatureTimeValue;
-    if (!rInformation.ouDateTime.isEmpty())
-        aSignatureTimeValue = rInformation.ouDateTime;
-    else
-    {
-        aSignatureTimeValue = utl::toISO8601(rInformation.stDateTime);
-        // Ignore sub-seconds.
-        sal_Int32 nCommaPos = aSignatureTimeValue.indexOf(',');
-        if (nCommaPos != -1)
-        {
-            aSignatureTimeValue = aSignatureTimeValue.copy(0, nCommaPos);
-            aSignatureTimeValue += "Z";
-        }
-    }
-    xDocumentHandler->characters(aSignatureTimeValue);
-    xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_VALUE);
-
-    xDocumentHandler->endElement(NSTAG_MDSSI ":" TAG_SIGNATURETIME);
-    xDocumentHandler->endElement(TAG_SIGNATUREPROPERTY);
-    xDocumentHandler->endElement(TAG_SIGNATUREPROPERTIES);
-
-    xDocumentHandler->endElement(TAG_OBJECT);
-
-    // idOfficeObject
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_ID, "idOfficeObject");
-        xDocumentHandler->startElement(TAG_OBJECT, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-    xDocumentHandler->startElement(TAG_SIGNATUREPROPERTIES, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_ID, "idOfficeV1Details");
-        pAttributeList->AddAttribute(ATTR_TARGET, "#idPackageSignature");
-        xDocumentHandler->startElement(TAG_SIGNATUREPROPERTY, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_XMLNS, "http://schemas.microsoft.com/office/2006/digsig");
-        xDocumentHandler->startElement("SignatureInfoV1", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-    xDocumentHandler->startElement("SetupId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->endElement("SetupId");
-    xDocumentHandler->startElement("SignatureText", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->endElement("SignatureText");
-    xDocumentHandler->startElement("SignatureImage", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->endElement("SignatureImage");
-    xDocumentHandler->startElement("SignatureComments", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters(rInformation.ouDescription);
-    xDocumentHandler->endElement("SignatureComments");
-    // Just hardcode something valid according to [MS-OFFCRYPTO].
-    xDocumentHandler->startElement("WindowsVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("6.1");
-    xDocumentHandler->endElement("WindowsVersion");
-    xDocumentHandler->startElement("OfficeVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("16.0");
-    xDocumentHandler->endElement("OfficeVersion");
-    xDocumentHandler->startElement("ApplicationVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("16.0");
-    xDocumentHandler->endElement("ApplicationVersion");
-    xDocumentHandler->startElement("Monitors", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("1");
-    xDocumentHandler->endElement("Monitors");
-    xDocumentHandler->startElement("HorizontalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("1280");
-    xDocumentHandler->endElement("HorizontalResolution");
-    xDocumentHandler->startElement("VerticalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("800");
-    xDocumentHandler->endElement("VerticalResolution");
-    xDocumentHandler->startElement("ColorDepth", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("32");
-    xDocumentHandler->endElement("ColorDepth");
-    xDocumentHandler->startElement("SignatureProviderId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("{00000000-0000-0000-0000-000000000000}");
-    xDocumentHandler->endElement("SignatureProviderId");
-    xDocumentHandler->startElement("SignatureProviderUrl", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->endElement("SignatureProviderUrl");
-    xDocumentHandler->startElement("SignatureProviderDetails", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("9"); // This is what MSO 2016 writes, though [MS-OFFCRYPTO] doesn't document what the value means.
-    xDocumentHandler->endElement("SignatureProviderDetails");
-    xDocumentHandler->startElement("SignatureType", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters("1");
-    xDocumentHandler->endElement("SignatureType");
-    xDocumentHandler->endElement("SignatureInfoV1");
-    xDocumentHandler->endElement(TAG_SIGNATUREPROPERTY);
-    xDocumentHandler->endElement(TAG_SIGNATUREPROPERTIES);
-    xDocumentHandler->endElement(TAG_OBJECT);
-
-    xDocumentHandler->startElement(TAG_OBJECT, uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    {
-        rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-        pAttributeList->AddAttribute(ATTR_XMLNS ":" NSTAG_XD, NS_XD);
-        pAttributeList->AddAttribute(ATTR_TARGET, "#idPackageSignature");
-        xDocumentHandler->startElement(NSTAG_XD ":" TAG_QUALIFYINGPROPERTIES, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-    }
-
-    // FIXME why does this part crash NSS when MOZILLA_CERTIFICATE_FOLDER is not set?
-    static bool bTest = getenv("LO_TESTNAME");
-    if (!bTest)
-    {
-        {
-            rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-            pAttributeList->AddAttribute(ATTR_ID, "idSignedProperties");
-            xDocumentHandler->startElement(NSTAG_XD ":" TAG_SIGNEDPROPERTIES, uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-        }
-
-        xDocumentHandler->startElement("xd:SignedSignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->startElement("xd:SigningTime", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->characters(aSignatureTimeValue);
-        xDocumentHandler->endElement("xd:SigningTime");
-        xDocumentHandler->startElement("xd:SigningCertificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->startElement("xd:Cert", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->startElement("xd:CertDigest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        {
-            rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
-            pAttributeList->AddAttribute(ATTR_ALGORITHM, ALGO_XMLDSIGSHA256);
-            xDocumentHandler->startElement("DigestMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
-        }
-        xDocumentHandler->endElement("DigestMethod");
-        xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-
-        assert(!rInformation.ouCertDigest.isEmpty());
-        xDocumentHandler->characters(rInformation.ouCertDigest);
-
-        xDocumentHandler->endElement("DigestValue");
-        xDocumentHandler->endElement("xd:CertDigest");
-        xDocumentHandler->startElement("xd:IssuerSerial", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->startElement("X509IssuerName", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->characters(rInformation.ouX509IssuerName);
-        xDocumentHandler->endElement("X509IssuerName");
-        xDocumentHandler->startElement("X509SerialNumber", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->characters(rInformation.ouX509SerialNumber);
-        xDocumentHandler->endElement("X509SerialNumber");
-        xDocumentHandler->endElement("xd:IssuerSerial");
-        xDocumentHandler->endElement("xd:Cert");
-        xDocumentHandler->endElement("xd:SigningCertificate");
-        xDocumentHandler->startElement("xd:SignaturePolicyIdentifier", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->startElement("xd:SignaturePolicyImplied", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-        xDocumentHandler->endElement("xd:SignaturePolicyImplied");
-        xDocumentHandler->endElement("xd:SignaturePolicyIdentifier");
-        xDocumentHandler->endElement("xd:SignedSignatureProperties");
-
-        xDocumentHandler->endElement(NSTAG_XD ":" TAG_SIGNEDPROPERTIES);
-    }
-    xDocumentHandler->endElement(NSTAG_XD ":" TAG_QUALIFYINGPROPERTIES);
-    xDocumentHandler->endElement(TAG_OBJECT);
-
-    xDocumentHandler->endElement(TAG_SIGNATURE);
+    OOXMLSecExporter aExporter(mxCtx, xRootStorage, xDocumentHandler, rInformation);
+    aExporter.writeSignature();
 }
 
 SignatureInformation XSecController::getSignatureInformation( sal_Int32 nSecurityId ) const
commit 6c11778ee6919b0f16acb17a896f65d4021f3089
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Mar 11 14:53:13 2016 +0100

    CppunitTest_xmlsecurity_signing: add ODF verification testcases
    
    Change-Id: I08734b7841fc83b327ebbf5c8ae43f7969e94e12

diff --git a/xmlsecurity/qa/unit/signing/data/bad.odt b/xmlsecurity/qa/unit/signing/data/bad.odt
new file mode 100644
index 0000000..75c39d5
Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/bad.odt differ
diff --git a/xmlsecurity/qa/unit/signing/data/good.odt b/xmlsecurity/qa/unit/signing/data/good.odt
new file mode 100644
index 0000000..8c6019d
Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/good.odt differ
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx
index b576b3b..2ee8e33 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -61,6 +61,10 @@ public:
     virtual void tearDown() override;
 
     void testDescription();
+    /// Test a typical ODF where all streams are signed.
+    void testODFGood();
+    /// Test a typical broken ODF signature where one stream is corrupted.
+    void testODFBroken();
     /// Test a typical OOXML where a number of (but not all) streams are signed.
     void testOOXMLPartial();
     /// Test a typical broken OOXML signature where one stream is corrupted.
@@ -75,6 +79,9 @@ public:
 
     CPPUNIT_TEST_SUITE(SigningTest);
     CPPUNIT_TEST(testDescription);
+    CPPUNIT_TEST(testODFGood);
+    CPPUNIT_TEST(testODFBroken);
+    CPPUNIT_TEST(testODFBroken);
     CPPUNIT_TEST(testOOXMLPartial);
     CPPUNIT_TEST(testOOXMLBroken);
     CPPUNIT_TEST(testOOXMLDescription);
@@ -301,6 +308,33 @@ void SigningTest::testOOXMLRemoveAll()
     }));
 }
 
+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
+         || nActual == SignatureState::PARTIAL_OK));
+}
+
+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()));
+}
+
 void SigningTest::testOOXMLPartial()
 {
     createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx");


More information about the Libreoffice-commits mailing list