Blob Blame History Raw
From 78f208c5aa615ccf6738d2a174564269e5f3e0ab Mon Sep 17 00:00:00 2001
From: Michael Stahl <michael.stahl@allotropia.de>
Date: Tue, 30 Mar 2021 17:37:31 +0200
Subject: [PATCH] xmlsecurity: replace OOXMLSecParser implementation

This is similar to 12b15be8f4f930a04d8056b9219ac969b42a9784 and following
commits, but OOXMLSecParser has some differences to XSecParser, such as
using a ds:Manifest, and requires a couple extra namespaces.

Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113381
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit cc1d19f7bbaefa5fb22ebd1344112755068b93c9)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113360
(cherry picked from commit 5e2c137c27310e76050f2247077b1311baee4381)

Change-Id: I56e39d9609db8fcad50ca1632ff482c1f0a30ff5
---
 include/xmloff/xmlnmspe.hxx                  |    3 +
 xmlsecurity/source/helper/ooxmlsecparser.cxx | 1473 +++++++++++++++---
 xmlsecurity/source/helper/ooxmlsecparser.hxx |   78 +-
 3 files changed, 1314 insertions(+), 240 deletions(-)

diff --git a/include/xmloff/xmlnmspe.hxx b/include/xmloff/xmlnmspe.hxx
index 302a134f92fe..bebb1d656b40 100644
--- a/include/xmloff/xmlnmspe.hxx
+++ b/include/xmloff/xmlnmspe.hxx
@@ -73,6 +73,9 @@ XML_NAMESPACE( XML_NAMESPACE_DSIG,            39U )
 XML_NAMESPACE( XML_NAMESPACE_DS,              40U )
 XML_NAMESPACE( XML_NAMESPACE_XADES132,        41U )
 XML_NAMESPACE( XML_NAMESPACE_XADES141,        42U )
+// OOXML digital signature extension namespaces, also based on xmldsig-core
+XML_NAMESPACE( XML_NAMESPACE_MDSSI,           43U )
+XML_NAMESPACE( XML_NAMESPACE_MSODIGSIG,       44U )
 
 // namespaces for odf extended formats
 
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx b/xmlsecurity/source/helper/ooxmlsecparser.cxx
index a25872fc057d..42f226f57d14 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -11,32 +11,1241 @@
 #include "ooxmlsecparser.hxx"
 #include <xmlsignaturehelper.hxx>
 #include <xsecctl.hxx>
+
+#include <xmloff/xmlnmspe.hxx>
+#include <xmloff/xmlimp.hxx>
+
+#include <com/sun/star/xml/sax/SAXException.hpp>
+
 #include <sal/log.hxx>
 
-using namespace com::sun::star;
+using namespace com::sun::star;
+
+class OOXMLSecParser::Context
+{
+    protected:
+        friend class OOXMLSecParser;
+        OOXMLSecParser & m_rParser;
+    private:
+        std::unique_ptr<SvXMLNamespaceMap> m_pOldNamespaceMap;
+
+    public:
+        Context(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : m_rParser(rParser)
+            , m_pOldNamespaceMap(std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual ~Context() = default;
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& /*xAttrs*/)
+        {
+        }
+
+        virtual void EndElement()
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/);
+
+        virtual void Characters(OUString const& /*rChars*/)
+        {
+        }
+};
+
+// it's possible that an unsupported element has an Id attribute and a
+// ds:Reference digesting it - probably this means XSecController needs to know
+// about it. (For known elements, the Id attribute is only processed according
+// to the schema.)
+class OOXMLSecParser::UnknownContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        UnknownContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+};
+
+auto OOXMLSecParser::Context::CreateChildContext(
+    std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+    sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/)
+-> std::unique_ptr<Context>
+{
+    // default: create new base context
+    return std::make_unique<UnknownContext>(m_rParser, std::move(pOldNamespaceMap));
+}
+
+/**
+note: anything in ds:Object should be trusted *only* if there is a ds:Reference
+      to it so it is signed (exception: the xades:EncapsulatedX509Certificate).
+      ds:SignedInfo precedes all ds:Object.
+
+      There may be multiple ds:Signature for purpose of counter-signatures
+      but the way XAdES describes these, only the ds:SignatureValue element
+      would be referenced, so requiring a ds:Reference for anything in
+      ds:Object shouldn't cause issues.
+ */
+class OOXMLSecParser::ReferencedContextImpl
+    : public OOXMLSecParser::Context
+{
+    protected:
+        bool m_isReferenced;
+
+    public:
+        ReferencedContextImpl(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_isReferenced(isReferenced)
+        {
+        }
+
+        OUString CheckIdAttrReferenced(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs)
+        {
+            OUString const id(m_rParser.HandleIdAttr(xAttrs));
+            if (!id.isEmpty() && m_rParser.m_pXSecController->haveReferenceForId(id))
+            {
+                m_isReferenced = true;
+            }
+            return id;
+        }
+};
+
+class OOXMLSecParser::DsX509CertificateContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsX509CertificateContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsX509SerialNumberContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsX509SerialNumberContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsX509IssuerNameContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsX509IssuerNameContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsX509IssuerSerialContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rX509IssuerName;
+        OUString & m_rX509SerialNumber;
+
+    public:
+        DsX509IssuerSerialContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rIssuerName, OUString & rSerialNumber)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rX509IssuerName(rIssuerName)
+            , m_rX509SerialNumber(rSerialNumber)
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerName")
+            {
+                return std::make_unique<DsX509IssuerNameContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509IssuerName);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "X509SerialNumber")
+            {
+                return std::make_unique<DsX509SerialNumberContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509SerialNumber);
+            }
+            // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+/// can't be sure what is supposed to happen here because the spec is clear as mud
+class OOXMLSecParser::DsX509DataContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        // sigh... "No ordering is implied by the above constraints."
+        // so store the ball of mud in vectors and try to figure it out later.
+        std::vector<std::pair<OUString, OUString>> m_X509IssuerSerials;
+        std::vector<OUString> m_X509Certificates;
+
+    public:
+        DsX509DataContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setX509Data(m_X509IssuerSerials, m_X509Certificates);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerSerial")
+            {
+                m_X509IssuerSerials.emplace_back();
+                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerSerials.back().first, m_X509IssuerSerials.back().second);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "X509Certificate")
+            {
+                m_X509Certificates.emplace_back();
+                return std::make_unique<DsX509CertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_X509Certificates.back());
+            }
+            // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsKeyInfoContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsKeyInfoContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "X509Data")
+            {
+                return std::make_unique<DsX509DataContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            // missing: ds:PGPData
+            // missing: ds:KeyName, ds:KeyValue, ds:RetrievalMethod, ds:SPKIData, ds:MgmtData
+            // (old code would read ds:Transform inside ds:RetrievalMethod but
+            // presumably that was a bug)
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+
+};
+
+class OOXMLSecParser::DsSignatureValueContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString m_Value;
+
+    public:
+        DsSignatureValueContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setSignatureValue(m_Value);
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_Value += rChars;
+        }
+};
+
+class OOXMLSecParser::DsDigestValueContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsDigestValueContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& /*xAttrs*/) override
+        {
+            m_rValue.clear();
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsDigestMethodContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        sal_Int32 & m_rReferenceDigestID;
+
+    public:
+        DsDigestMethodContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                sal_Int32 & rReferenceDigestID)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rReferenceDigestID(rReferenceDigestID)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            OUString ouAlgorithm = xAttrs->getValueByName("Algorithm");
+
+            SAL_WARN_IF( ouAlgorithm.isEmpty(), "xmlsecurity.helper", "no Algorithm in Reference" );
+            if (!ouAlgorithm.isEmpty())
+            {
+                SAL_WARN_IF( ouAlgorithm != ALGO_XMLDSIGSHA1
+                             && ouAlgorithm != ALGO_XMLDSIGSHA256
+                             && ouAlgorithm != ALGO_XMLDSIGSHA512,
+                             "xmlsecurity.helper", "Algorithm neither SHA1, SHA256 nor SHA512");
+                if (ouAlgorithm == ALGO_XMLDSIGSHA1)
+                    m_rReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+                else if (ouAlgorithm == ALGO_XMLDSIGSHA256)
+                    m_rReferenceDigestID = css::xml::crypto::DigestID::SHA256;
+                else if (ouAlgorithm == ALGO_XMLDSIGSHA512)
+                    m_rReferenceDigestID = css::xml::crypto::DigestID::SHA512;
+                else
+                    m_rReferenceDigestID = 0;
+            }
+        }
+};
+
+class OOXMLSecParser::DsTransformContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        bool & m_rIsC14N;
+
+    public:
+        DsTransformContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool & rIsC14N)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rIsC14N(rIsC14N)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            OUString aAlgorithm = xAttrs->getValueByName("Algorithm");
+
+            if (aAlgorithm == ALGO_RELATIONSHIP)
+            {
+                m_rIsC14N = true;
+            }
+        }
+};
+
+class OOXMLSecParser::DsTransformsContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        bool & m_rIsC14N;
+
+    public:
+        DsTransformsContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool & rIsC14N)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rIsC14N(rIsC14N)
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Transform")
+            {
+                return std::make_unique<DsTransformContext>(m_rParser, std::move(pOldNamespaceMap), m_rIsC14N);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsReferenceContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString m_URI;
+        OUString m_Type;
+        OUString m_DigestValue;
+        bool m_IsC14N = false;
+        // Relevant for ODF. The digest algorithm selected by the DigestMethod
+        // element's Algorithm attribute. @see css::xml::crypto::DigestID.
+        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA256;
+
+    public:
+        DsReferenceContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+
+            m_URI = xAttrs->getValueByName("URI");
+            SAL_WARN_IF(m_URI.isEmpty(), "xmlsecurity.helper", "URI is empty");
+            // Remember the type of this reference.
+            m_Type = xAttrs->getValueByName("Type");
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_URI.startsWith("#"))
+            {
+                /*
+                * remove the first character '#' from the attribute value
+                */
+                m_rParser.m_pXSecController->addReference(m_URI.copy(1), m_nReferenceDigestID, m_Type);
+            }
+            else
+            {
+                if (m_IsC14N) // this is determined by nested ds:Transform
+                {
+                    m_rParser.m_pXSecController->addStreamReference(m_URI, false, m_nReferenceDigestID);
+                }
+                else
+            /*
+            * it must be an octet stream
+            */
+                {
+                    m_rParser.m_pXSecController->addStreamReference(m_URI, true, m_nReferenceDigestID);
+                }
+            }
+
+            m_rParser.m_pXSecController->setDigestValue(m_nReferenceDigestID, m_DigestValue);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Transforms")
+            {
+                return std::make_unique<DsTransformsContext>(m_rParser, std::move(pOldNamespaceMap), m_IsC14N);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
+            {
+                return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_nReferenceDigestID);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
+            {
+                return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_DigestValue);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsSignatureMethodContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsSignatureMethodContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            OUString ouAlgorithm = xAttrs->getValueByName("Algorithm");
+            if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256
+                || ouAlgorithm == ALGO_ECDSASHA512)
+            {
+                m_rParser.m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
+            }
+        }
+};
+
+class OOXMLSecParser::DsSignedInfoContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsSignedInfoContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setReferenceCount();
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureMethod")
+            {
+                return std::make_unique<DsSignatureMethodContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Reference")
+            {
+                return std::make_unique<DsReferenceContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            // missing: ds:CanonicalizationMethod
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesCertDigestContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rDigestValue;
+        sal_Int32 & m_rReferenceDigestID;
+
+    public:
+        XadesCertDigestContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rDigestValue, sal_Int32 & rReferenceDigestID)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rDigestValue(rDigestValue)
+            , m_rReferenceDigestID(rReferenceDigestID)
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
+            {
+                return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_rReferenceDigestID);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
+            {
+                return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_rDigestValue);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesCertContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+        OUString m_CertDigest;
+        OUString m_X509IssuerName;
+        OUString m_X509SerialNumber;
+
+    public:
+        XadesCertContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                m_rParser.m_pXSecController->setX509CertDigest(m_CertDigest, m_nReferenceDigestID, m_X509IssuerName, m_X509SerialNumber);
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned xades:Cert");
+            }
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "CertDigest")
+            {
+                return std::make_unique<XadesCertDigestContext>(m_rParser, std::move(pOldNamespaceMap), m_CertDigest, m_nReferenceDigestID);
+            }
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "IssuerSerial")
+            {
+                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesSigningCertificateContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesSigningCertificateContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "Cert")
+            {
+                return std::make_unique<XadesCertContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesSigningTimeContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        OUString m_Value;
+
+    public:
+        XadesSigningTimeContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                m_rParser.m_pXSecController->setDate("", m_Value);
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SigningTime");
+            }
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_Value += rChars;
+        }
+};
+
+class OOXMLSecParser::XadesSignedSignaturePropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesSignedSignaturePropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningTime")
+            {
+                return std::make_unique<XadesSigningTimeContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningCertificate")
+            {
+                return std::make_unique<XadesSigningCertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            // missing: xades:SignaturePolicyIdentifier, xades:SignatureProductionPlace, xades:SignerRole
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesSignedPropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesSignedPropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedSignatureProperties")
+            {
+                return std::make_unique<XadesSignedSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            // missing: xades:SignedDataObjectProperties
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesQualifyingPropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesQualifyingPropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedProperties")
+            {
+                return std::make_unique<XadesSignedPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            // missing: xades:UnsignedSignatureProperties
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::MsodigsigSetupIDContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MsodigsigSetupIDContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::MsodigsigSignatureCommentsContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MsodigsigSignatureCommentsContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::MsodigsigSignatureInfoV1Context
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        OUString m_SetupID;
+        OUString m_SignatureComments;
+
+    public:
+        MsodigsigSignatureInfoV1Context(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SetupID")
+            {
+                return std::make_unique<MsodigsigSetupIDContext>(m_rParser, std::move(pOldNamespaceMap), m_SetupID);
+            }
+            if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SignatureComments")
+            {
+                return std::make_unique<MsodigsigSignatureCommentsContext>(m_rParser, std::move(pOldNamespaceMap), m_SignatureComments);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                if (!m_SetupID.isEmpty())
+                {
+                    m_rParser.m_pXSecController->setSignatureLineId(m_SetupID);
+                }
+                if (!m_SignatureComments.isEmpty())
+                {
+                    m_rParser.m_pXSecController->setDescription("", m_SignatureComments);
+
+                }
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureInfoV1");
+            }
+        }
+};
+
+class OOXMLSecParser::MdssiValueContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MdssiValueContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::MdssiSignatureTimeContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MdssiSignatureTimeContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_MDSSI && rName == "Value")
+            {
+                return std::make_unique<MdssiValueContext>(m_rParser, std::move(pOldNamespaceMap), m_rValue);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+
+class OOXMLSecParser::DsSignaturePropertyContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        enum class SignatureProperty { Unknown, Date, Info };
+        SignatureProperty m_Property = SignatureProperty::Unknown;
+        OUString m_Id;
+        OUString m_Value;
+
+    public:
+        DsSignaturePropertyContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            m_Id = CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                switch (m_Property)
+                {
+                    case SignatureProperty::Unknown:
+                        SAL_INFO("xmlsecurity.helper", "Unknown property in ds:Object ignored");
+                        break;
+                    case SignatureProperty::Info:
+                        break; // handled by child context
+                    case SignatureProperty::Date:
+                        m_rParser.m_pXSecController->setDate(m_Id, m_Value);
+                        break;
+                }
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureProperty");
+            }
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_MDSSI && rName == "SignatureTime")
+            {
+                m_Property = SignatureProperty::Date;
+                return std::make_unique<MdssiSignatureTimeContext>(m_rParser, std::move(pOldNamespaceMap), m_Value);
+            }
+            if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SignatureInfoV1")
+            {
+                return std::make_unique<MsodigsigSignatureInfoV1Context>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsSignaturePropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        DsSignaturePropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperty")
+            {
+                return std::make_unique<DsSignaturePropertyContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsManifestContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        DsManifestContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+#if 0
+        ???
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setReferenceCount();
+        }
+#endif
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Reference")
+            {
+                return std::make_unique<DsReferenceContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            // missing: ds:CanonicalizationMethod
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsObjectContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+        enum class Mode { Default, ValidSignatureLineImage, InvalidSignatureLineImage };
+        Mode m_Mode = Mode::Default;
+        OUString m_Value;
+
+    public:
+        DsObjectContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            // init with "false" here - the Signature element can't be referenced by its child
+            : OOXMLSecParser::ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), false)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            OUString const id(CheckIdAttrReferenced(xAttrs));
+            if (id == "idValidSigLnImg")
+            {
+                m_Mode = Mode::ValidSignatureLineImage;
+            }
+            else if (id == "idInvalidSigLnImg")
+            {
+                m_Mode = Mode::InvalidSignatureLineImage;
+            }
+        }
+
+        virtual void EndElement() override
+        {
+            switch (m_Mode)
+            {
+                case Mode::ValidSignatureLineImage:
+                    if (m_isReferenced)
+                    {
+                        m_rParser.m_pXSecController->setValidSignatureImage(m_Value);
+                    }
+                    else
+                    {
+                        SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineValidImage");
+                    }
+                    break;
+                case Mode::InvalidSignatureLineImage:
+                    if (m_isReferenced)
+                    {
+                        m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value);
+                    }
+                    else
+                    {
+                        SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineInvalidImage");
+                    }
+                    break;
+                case Mode::Default:
+                    break;
+            }
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_Value += rChars;
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperties")
+            {
+                return std::make_unique<DsSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == "QualifyingProperties")
+            {
+                return std::make_unique<XadesQualifyingPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Manifest")
+            {
+                return std::make_unique<DsManifestContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsSignatureContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsSignatureContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+        {
+            OUString const ouIdAttr(m_rParser.HandleIdAttr(xAttrs));
+            m_rParser.m_rXMLSignatureHelper.StartVerifySignatureElement();
+            m_rParser.m_pXSecController->addSignature();
+            if (!ouIdAttr.isEmpty())
+            {
+                m_rParser.m_pXSecController->setId( ouIdAttr );
+            }
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_DS && rName == "SignedInfo")
+            {
+                return std::make_unique<DsSignedInfoContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureValue")
+            {
+                return std::make_unique<DsSignatureValueContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "KeyInfo")
+            {
+                return std::make_unique<DsKeyInfoContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Object")
+            {
+                return std::make_unique<DsObjectContext>(m_rParser, std::move(pOldNamespaceMap));
+            }
+            return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+        }
+};
+
 
 OOXMLSecParser::OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController)
-    : m_pXSecController(pXSecController)
-    ,m_bInDigestValue(false)
-    ,m_bInSignatureValue(false)
-    ,m_bInX509Certificate(false)
-    ,m_bInMdssiValue(false)
-    ,m_bInSignatureComments(false)
-    ,m_bInX509IssuerName(false)
-    ,m_bInX509SerialNumber(false)
-    ,m_bInCertDigest(false)
-    ,m_bInValidSignatureImage(false)
-    ,m_bInInvalidSignatureImage(false)
-    ,m_bInSignatureLineId(false)
-    ,m_bReferenceUnresolved(false)
+    : m_pNamespaceMap(new SvXMLNamespaceMap)
+    , m_pXSecController(pXSecController)
     ,m_rXMLSignatureHelper(rXMLSignatureHelper)
 {
+    using namespace xmloff::token;
+    m_pNamespaceMap->Add( GetXMLToken(XML_XML), GetXMLToken(XML_N_XML), XML_NAMESPACE_XML );
+    m_pNamespaceMap->Add( "_ds", GetXMLToken(XML_N_DS), XML_NAMESPACE_DS );
+    m_pNamespaceMap->Add( "_xades132", GetXMLToken(XML_N_XADES132), XML_NAMESPACE_XADES132);
+    m_pNamespaceMap->Add( "_xades141", GetXMLToken(XML_N_XADES141), XML_NAMESPACE_XADES141);
+    m_pNamespaceMap->Add( "_dc", GetXMLToken(XML_N_DC), XML_NAMESPACE_DC );
+    m_pNamespaceMap->Add( "_mdssi", NS_MDSSI, XML_NAMESPACE_MDSSI );
+    m_pNamespaceMap->Add( "_msodigsig", "http://schemas.microsoft.com/office/2006/digsig", XML_NAMESPACE_MSODIGSIG );
+    m_pNamespaceMap->Add( "_office_libo",
+                         GetXMLToken(XML_N_LO_EXT), XML_NAMESPACE_LO_EXT);
 }
 
 OOXMLSecParser::~OOXMLSecParser()
 {
 }
 
+OUString OOXMLSecParser::HandleIdAttr(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs)
+{
+    OUString const aId = xAttrs->getValueByName("Id");
+    if (!aId.isEmpty())
+    {
+        m_pXSecController->collectToVerify(aId);
+    }
+    return aId;
+}
+
 void SAL_CALL OOXMLSecParser::startDocument()
 {
     if (m_xNextHandler.is())
@@ -51,231 +1260,69 @@ void SAL_CALL OOXMLSecParser::endDocument()
 
 void SAL_CALL OOXMLSecParser::startElement(const OUString& rName, const uno::Reference<xml::sax::XAttributeList>& xAttribs)
 {
-    OUString aId = xAttribs->getValueByName("Id");
-    if (!aId.isEmpty())
-        m_pXSecController->collectToVerify(aId);
+    assert(m_pNamespaceMap);
+    std::unique_ptr<SvXMLNamespaceMap> pRewindMap(
+        SvXMLImport::processNSAttributes(m_pNamespaceMap, nullptr, xAttribs));
 
-    if (rName == "Signature")
-    {
-        m_rXMLSignatureHelper.StartVerifySignatureElement();
-        m_pXSecController->addSignature();
-        if (!aId.isEmpty())
-            m_pXSecController->setId(aId);
-    }
-    else if (rName == "SignatureMethod")
-    {
-        OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
-        if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256
-            || ouAlgorithm == ALGO_ECDSASHA512)
-            m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
-    }
-    else if (rName == "Reference")
-    {
-        OUString aURI = xAttribs->getValueByName("URI");
-        if (aURI.startsWith("#"))
-            m_pXSecController->addReference(aURI.copy(1), xml::crypto::DigestID::SHA1, OUString());
-        else
-        {
-            m_aReferenceURI = aURI;
-            m_bReferenceUnresolved = true;
-        }
-    }
-    else if (rName == "Transform")
-    {
-        if (m_bReferenceUnresolved)
-        {
-            OUString aAlgorithm = xAttribs->getValueByName("Algorithm");
-            if (aAlgorithm == ALGO_RELATIONSHIP)
-            {
-                m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/false, /*nDigestID=*/xml::crypto::DigestID::SHA256);
-                m_bReferenceUnresolved = false;
-            }
-        }
-    }
-    else if (rName == "DigestValue" && !m_bInCertDigest)
-    {
-        m_aDigestValue.clear();
-        m_bInDigestValue = true;
-    }
-    else if (rName == "SignatureValue")
-    {
-        m_aSignatureValue.clear();
-        m_bInSignatureValue = true;
-    }
-    else if (rName == "X509Certificate")
-    {
-        m_aX509Certificate.clear();
-        m_bInX509Certificate = true;
-    }
-    else if (rName == "mdssi:Value")
-    {
-        m_aMdssiValue.clear();
-        m_bInMdssiValue = true;
-    }
-    else if (rName == "SignatureComments")
-    {
-        m_aSignatureComments.clear();
-        m_bInSignatureComments = true;
-    }
-    else if (rName == "X509IssuerName")
-    {
-        m_aX509IssuerName.clear();
-        m_bInX509IssuerName = true;
-    }
-    else if (rName == "X509SerialNumber")
-    {
-        m_aX509SerialNumber.clear();
-        m_bInX509SerialNumber = true;
-    }
-    else if (rName == "xd:CertDigest")
-    {
-        m_aCertDigest.clear();
-        m_bInCertDigest = true;
-    }
-    else if (rName == "Object")
+    OUString localName;
+    sal_uInt16 const nPrefix(m_pNamespaceMap->GetKeyByAttrName(rName, &localName));
+
+    std::unique_ptr<Context> pContext;
+
+    if (m_ContextStack.empty())
     {
-        OUString sId = xAttribs->getValueByName("Id");
-        if (sId == "idValidSigLnImg")
-        {
-            m_aValidSignatureImage.clear();
-            m_bInValidSignatureImage = true;
-        }
-        else if (sId == "idInvalidSigLnImg")
+        if (nPrefix == XML_NAMESPACE_DS
+            && localName == "Signature")
         {
-            m_aInvalidSignatureImage.clear();
-            m_bInInvalidSignatureImage = true;
+            pContext.reset(new DsSignatureContext(*this, std::move(pRewindMap)));
         }
         else
         {
-            SAL_INFO("xmlsecurity.ooxml", "Unknown 'Object' child element: " << rName);
+            throw css::xml::sax::SAXException(
+                "xmlsecurity: unexpected root element", nullptr,
+                css::uno::Any());
         }
     }
-    else if (rName == "SetupID")
-    {
-        m_aSignatureLineId.clear();
-        m_bInSignatureLineId = true;
-    }
     else
     {
-        SAL_INFO("xmlsecurity.ooxml", "Unknown xml element: " << rName);
+        pContext = m_ContextStack.top()->CreateChildContext(
+                std::move(pRewindMap), nPrefix, localName);
     }
 
+    m_ContextStack.push(std::move(pContext));
+    assert(!pRewindMap);
+
+    m_ContextStack.top()->StartElement(xAttribs);
+
     if (m_xNextHandler.is())
+    {
         m_xNextHandler->startElement(rName, xAttribs);
+    }
+
 }
 
 void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
 {
-    if (rName == "SignedInfo")
-        m_pXSecController->setReferenceCount();
-    else if (rName == "Reference")
-    {
-        if (m_bReferenceUnresolved)
-        {
-            // No transform algorithm found, assume binary.
-            m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/true, /*nDigestID=*/xml::crypto::DigestID::SHA256);
-            m_bReferenceUnresolved = false;
-        }
-        m_pXSecController->setDigestValue(xml::crypto::DigestID::SHA256, m_aDigestValue);
-    }
-    else if (rName == "DigestValue" && !m_bInCertDigest)
-        m_bInDigestValue = false;
-    else if (rName == "SignatureValue")
-    {
-        m_pXSecController->setSignatureValue(m_aSignatureValue);
-        m_bInSignatureValue = false;
-    }
-    else if (rName == "X509Data")
-    {
-        std::vector<std::pair<OUString, OUString>> X509IssuerSerials;
-        std::vector<OUString> X509Certificates;
-        if (!m_aX509Certificate.isEmpty())
-        {
-            X509Certificates.emplace_back(m_aX509Certificate);
-        }
-        if (!m_aX509IssuerName.isEmpty() && !m_aX509SerialNumber.isEmpty())
-        {
-            X509IssuerSerials.emplace_back(m_aX509IssuerName, m_aX509SerialNumber);
-        }
-        m_pXSecController->setX509Data(X509IssuerSerials, X509Certificates);
-    }
-    else if (rName == "X509Certificate")
-    {
-        m_bInX509Certificate = false;
-    }
-    else if (rName == "mdssi:Value")
-    {
-        m_pXSecController->setDate("", m_aMdssiValue);
-        m_bInMdssiValue = false;
-    }
-    else if (rName == "SignatureComments")
-    {
-        m_pXSecController->setDescription("", m_aSignatureComments);
-        m_bInSignatureComments = false;
-    }
-    else if (rName == "X509IssuerName")
-    {
-        m_bInX509IssuerName = false;
-    }
-    else if (rName == "X509SerialNumber")
-    {
-        m_bInX509SerialNumber = false;
-    }
-    else if (rName == "xd:Cert")
-    {
-        m_pXSecController->setX509CertDigest(m_aCertDigest, css::xml::crypto::DigestID::SHA1, m_aX509IssuerName, m_aX509SerialNumber);
-    }
-    else if (rName == "xd:CertDigest")
-    {
-        m_bInCertDigest = false;
-    }
-    else if (rName == "Object")
+    assert(!m_ContextStack.empty()); // this should be checked by sax parser?
+
+    m_ContextStack.top()->EndElement();
+
+    if (m_xNextHandler.is())
     {
-        if (m_bInValidSignatureImage)
-        {
-            m_pXSecController->setValidSignatureImage(m_aValidSignatureImage);
-            m_bInValidSignatureImage = false;
-        }
-        else if (m_bInInvalidSignatureImage)
-        {
-            m_pXSecController->setInvalidSignatureImage(m_aInvalidSignatureImage);
-            m_bInInvalidSignatureImage = false;
-        }
+        m_xNextHandler->endElement(rName);
     }
-    else if (rName == "SetupID")
+
+    if (m_ContextStack.top()->m_pOldNamespaceMap)
     {
-        m_pXSecController->setSignatureLineId(m_aSignatureLineId);
-        m_bInSignatureLineId = false;
+        m_pNamespaceMap = std::move(m_ContextStack.top()->m_pOldNamespaceMap);
     }
-
-    if (m_xNextHandler.is())
-        m_xNextHandler->endElement(rName);
+    m_ContextStack.pop();
 }
 
 void SAL_CALL OOXMLSecParser::characters(const OUString& rChars)
 {
-    if (m_bInDigestValue && !m_bInCertDigest)
-        m_aDigestValue += rChars;
-    else if (m_bInSignatureValue)
-        m_aSignatureValue += rChars;
-    else if (m_bInX509Certificate)
-        m_aX509Certificate += rChars;
-    else if (m_bInMdssiValue)
-        m_aMdssiValue += rChars;
-    else if (m_bInSignatureComments)
-        m_aSignatureComments += rChars;
-    else if (m_bInX509IssuerName)
-        m_aX509IssuerName += rChars;
-    else if (m_bInX509SerialNumber)
-        m_aX509SerialNumber += rChars;
-    else if (m_bInCertDigest)
-        m_aCertDigest += rChars;
-    else if (m_bInValidSignatureImage)
-        m_aValidSignatureImage += rChars;
-    else if (m_bInInvalidSignatureImage)
-        m_aInvalidSignatureImage += rChars;
-    else if (m_bInSignatureLineId)
-        m_aSignatureLineId += rChars;
+    assert(!m_ContextStack.empty()); // this should be checked by sax parser?
+    m_ContextStack.top()->Characters(rChars);
 
     if (m_xNextHandler.is())
         m_xNextHandler->characters(rChars);
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.hxx b/xmlsecurity/source/helper/ooxmlsecparser.hxx
index d3c199147255..21ff01ff26da 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.hxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.hxx
@@ -15,6 +15,10 @@
 
 #include <cppuhelper/implbase.hxx>
 
+#include <xmloff/nmspmap.hxx>
+
+#include <stack>
+
 class XSecController;
 class XMLSignatureHelper;
 
@@ -25,38 +29,58 @@ class OOXMLSecParser: public cppu::WeakImplHelper
     css::lang::XInitialization
     >
 {
+public:
+    class Context;
+private:
+    class UnknownContext;
+    class ReferencedContextImpl;
+    class DsX509CertificateContext;
+    class DsX509SerialNumberContext;
+    class DsX509IssuerNameContext;
+    class DsX509IssuerSerialContext;
+    class DsX509DataContext;
+    class DsKeyInfoContext;
+    class DsSignatureValueContext;
+    class DsDigestValueContext;
+    class DsDigestMethodContext;
+    class DsTransformContext;
+    class DsTransformsContext;
+    class DsReferenceContext;
+    class DsSignatureMethodContext;
+    class DsSignedInfoContext;
+    class XadesEncapsulatedX509CertificateContext;
+    class XadesCertificateValuesContext;
+    class XadesUnsignedSignaturePropertiesContext;
+    class XadesUnsignedPropertiesContext;
+    class XadesCertDigestContext;
+    class XadesCertContext;
+    class XadesSigningCertificateContext;
+    class XadesSigningTimeContext;
+    class XadesSignedSignaturePropertiesContext;
+    class XadesSignedPropertiesContext;
+    class XadesQualifyingPropertiesContext;
+    class MdssiValueContext;
+    class MdssiSignatureTimeContext;
+    class MsodigsigSetupIDContext;
+    class MsodigsigSignatureCommentsContext;
+    class MsodigsigSignatureInfoV1Context;
+    class DsSignaturePropertyContext;
+    class DsSignaturePropertiesContext;
+    class DsManifestContext;
+    class DsObjectContext;
+    class DsSignatureContext;
+    class DsigSignaturesContext;
+
+    std::stack<std::unique_ptr<Context>> m_ContextStack;
+    std::unique_ptr<SvXMLNamespaceMap> m_pNamespaceMap;
+
     XSecController* m_pXSecController;
     css::uno::Reference<css::xml::sax::XDocumentHandler> m_xNextHandler;
 
-    bool m_bInDigestValue;
-    OUString m_aDigestValue;
-    bool m_bInSignatureValue;
-    OUString m_aSignatureValue;
-    bool m_bInX509Certificate;
-    OUString m_aX509Certificate;
-    bool m_bInMdssiValue;
-    OUString m_aMdssiValue;
-    bool m_bInSignatureComments;
-    OUString m_aSignatureComments;
-    bool m_bInX509IssuerName;
-    OUString m_aX509IssuerName;
-    bool m_bInX509SerialNumber;
-    OUString m_aX509SerialNumber;
-    bool m_bInCertDigest;
-    OUString m_aCertDigest;
-    bool m_bInValidSignatureImage;
-    OUString m_aValidSignatureImage;
-    bool m_bInInvalidSignatureImage;
-    OUString m_aInvalidSignatureImage;
-    bool m_bInSignatureLineId;
-    OUString m_aSignatureLineId;
-
-    /// Last seen <Reference URI="...">.
-    OUString m_aReferenceURI;
-    /// Already called addStreamReference() for this reference.
-    bool m_bReferenceUnresolved;
     XMLSignatureHelper& m_rXMLSignatureHelper;
 
+    OUString HandleIdAttr(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs);
+
 public:
     explicit OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController);
     virtual ~OOXMLSecParser() override;
-- 
2.33.1