1458e3
From b970e561433f1cbeebd43c92c92c98c0468cc483 Mon Sep 17 00:00:00 2001
1458e3
From: Michael Stahl <michael.stahl@allotropia.de>
1458e3
Date: Fri, 19 Feb 2021 17:56:21 +0100
1458e3
Subject: [PATCH 5/6] CVE-2021-25633
1458e3
MIME-Version: 1.0
1458e3
Content-Type: text/plain; charset=UTF-8
1458e3
Content-Transfer-Encoding: 8bit
1458e3
1458e3
xmlsecurity: ignore elements in ds:Object that aren't signed
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111253
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
1458e3
(cherry picked from commit 2bfa00e6bf4b2a310a8b8f5060acec85b5f7a3ce)
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111909
1458e3
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
1458e3
(cherry picked from commit 94ce59dd02fcfcaa1eb4f195b45a9a2edbd58242)
1458e3
1458e3
Change-Id: I2e4411f0907b89e7ad6e0185cee8f12b600515e8
1458e3
1458e3
xmlsecurity: improve handling of multiple X509Data elements
1458e3
1458e3
Combine everything related to a certificate in a new struct X509Data.
1458e3
1458e3
The CertDigest is not actually written in the X509Data element but in
1458e3
xades:Cert, so try to find the matching entry in
1458e3
XSecController::setX509CertDigest().
1458e3
1458e3
There was a confusing interaction with PGP signatures, where ouGpgKeyID
1458e3
was used for import, but export wrote the value from ouCertDigest
1458e3
instead - this needed fixing.
1458e3
1458e3
The main point of this is enforcing a constraint from xmldsig-core 4.5.4:
1458e3
1458e3
  All certificates appearing in an X509Data element MUST relate to the
1458e3
  validation key by either containing it or being part of a certification
1458e3
  chain that terminates in a certificate containing the validation key.
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111254
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
1458e3
(cherry picked from commit 9e82509b09f5fe2eb77bcdb8fd193c71923abb67)
1458e3
1458e3
xmlsecurity: improve handling of multiple certificates per X509Data
1458e3
1458e3
It turns out that an X509Data element can contain an arbitrary number of
1458e3
each of its child elements.
1458e3
1458e3
How exactly certificates of an issuer chain may or should be distributed
1458e3
across multiple X509Data elements isn't terribly obvious.
1458e3
1458e3
One thing that is clear is that any element that refers to or contains
1458e3
one particular certificate has to be a child of the same X509Data
1458e3
element, although in no particular order, so try to match the 2 such
1458e3
elements that the parser supports in XSecController::setX509Data().
1458e3
1458e3
Presumably the only way it makes sense to have multiple signing
1458e3
certificates is if they all contain the same key but are signed by
1458e3
different CAs. This case isn't handled currently; CheckX509Data() will
1458e3
complain there's not a single chain and validation of the certificates
1458e3
will fail.
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111500
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
1458e3
(cherry picked from commit 5af5ea893bcb8a8eb472ac11133da10e5a604e66)
1458e3
1458e3
xmlsecurity: add EqualDistinguishedNames()
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111545
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
1458e3
(cherry picked from commit 1d3da3486d827dd5e7a3bf1c7a533f5aa9860e42)
1458e3
1458e3
xmlsecurity: avoid exception in DigitalSignaturesDialog::getCertificate()
1458e3
1458e3
Fallback to PGP if there's no X509 signing certificate because
1458e3
CheckX509Data() failed prevents the dialog from popping up.
1458e3
1458e3
To avoid confusing the user in this situation, the dialog should
1458e3
show no certificate, which is already the case.
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111664
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
1458e3
(cherry picked from commit 90b725675c2964f4a151d802d9afedd8bc2ae1a7)
1458e3
1458e3
xmlsecurity: fix crash in DocumentDigitalSignatures::isAuthorTrusted()
1458e3
1458e3
If the argument is null.
1458e3
1458e3
This function also should use EqualDistinguishedNames().
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111667
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
1458e3
(cherry picked from commit ca98e505cd69bf95d8ddb9387cf3f8e03ae4577d)
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111910
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
1458e3
(cherry picked from commit a1cf770c2d7ca3e153e0b1f01ddcc313bc2bed7f)
1458e3
1458e3
Change-Id: I9633a980b0c18d58dfce24fc59396a833498a77d
1458e3
---
1458e3
 include/svl/sigstruct.hxx                     |  32 +-
1458e3
 svl/source/crypto/cryptosign.cxx              |  16 +-
1458e3
 sw/source/core/edit/edfcol.cxx                |   3 +-
1458e3
 xmlsecurity/inc/biginteger.hxx                |   3 +
1458e3
 xmlsecurity/inc/xmlsignaturehelper.hxx        |  12 +
1458e3
 xmlsecurity/inc/xsecctl.hxx                   |  15 +-
1458e3
 .../component/documentdigitalsignatures.cxx   |  54 +--
1458e3
 .../dialogs/digitalsignaturesdialog.cxx       |  15 +-
1458e3
 .../source/helper/documentsignaturehelper.cxx |  63 ++--
1458e3
 .../helper/documentsignaturemanager.cxx       |  12 +
1458e3
 .../source/helper/ooxmlsecexporter.cxx        |  23 +-
1458e3
 xmlsecurity/source/helper/ooxmlsecparser.cxx  |  22 +-
1458e3
 .../source/helper/pdfsignaturehelper.cxx      |   8 +-
1458e3
 .../source/helper/xmlsignaturehelper.cxx      | 161 +++++++++
1458e3
 xmlsecurity/source/helper/xsecctl.cxx         |  84 +++--
1458e3
 xmlsecurity/source/helper/xsecparser.cxx      | 334 ++++++++++++------
1458e3
 xmlsecurity/source/helper/xsecparser.hxx      |   1 +
1458e3
 xmlsecurity/source/helper/xsecsign.cxx        |  30 +-
1458e3
 xmlsecurity/source/helper/xsecverify.cxx      | 143 ++++++--
1458e3
 .../mscrypt/x509certificate_mscryptimpl.cxx   |  47 +++
1458e3
 .../mscrypt/xmlsignature_mscryptimpl.cxx      |   2 +
1458e3
 .../xmlsec/nss/x509certificate_nssimpl.cxx    |  25 ++
1458e3
 .../xmlsec/nss/xmlsignature_nssimpl.cxx       |   3 +
1458e3
 23 files changed, 853 insertions(+), 255 deletions(-)
1458e3
1458e3
diff --git a/include/svl/sigstruct.hxx b/include/svl/sigstruct.hxx
1458e3
index 7a0296fa9fae..f00cbce6e4b8 100644
1458e3
--- a/include/svl/sigstruct.hxx
1458e3
+++ b/include/svl/sigstruct.hxx
1458e3
@@ -89,9 +89,30 @@ struct SignatureInformation
1458e3
     sal_Int32 nSecurityId;
1458e3
     css::xml::crypto::SecurityOperationStatus nStatus;
1458e3
     SignatureReferenceInformations  vSignatureReferenceInfors;
1458e3
-    OUString ouX509IssuerName;
1458e3
-    OUString ouX509SerialNumber;
1458e3
-    OUString ouX509Certificate;
1458e3
+    struct X509CertInfo
1458e3
+    {
1458e3
+        OUString X509IssuerName;
1458e3
+        OUString X509SerialNumber;
1458e3
+        OUString X509Certificate;
1458e3
+        /// OOXML certificate SHA-256 digest, empty for ODF except when doing XAdES signature.
1458e3
+        OUString CertDigest;
1458e3
+        /// The certificate owner (aka subject).
1458e3
+        OUString X509Subject;
1458e3
+    };
1458e3
+    typedef std::vector<X509CertInfo> X509Data;
1458e3
+    // note: at parse time, it's unkown which one is the signing certificate;
1458e3
+    // ImplVerifySignatures() figures it out and puts it at the back
1458e3
+    std::vector<X509Data> X509Datas;
1458e3
+
1458e3
+    X509CertInfo const* GetSigningCertificate() const
1458e3
+    {
1458e3
+        if (X509Datas.empty())
1458e3
+        {
1458e3
+            return nullptr;
1458e3
+        }
1458e3
+        assert(!X509Datas.back().empty());
1458e3
+        return & X509Datas.back().back();
1458e3
+    }
1458e3
 
1458e3
     OUString ouGpgKeyID;
1458e3
     OUString ouGpgCertificate;
1458e3
@@ -124,8 +145,6 @@ struct SignatureInformation
1458e3
     OUString ouDescription;
1458e3
     /// The Id attribute of the <SignatureProperty> element that contains the <dc:description>.
1458e3
     OUString ouDescriptionPropertyId;
1458e3
-    /// OOXML certificate SHA-256 digest, empty for ODF except when doing XAdES signature.
1458e3
-    OUString ouCertDigest;
1458e3
     /// Valid and invalid signature line images
1458e3
     css::uno::Reference<css::graphic::XGraphic> aValidSignatureImage;
1458e3
     css::uno::Reference<css::graphic::XGraphic> aInvalidSignatureImage;
1458e3
@@ -140,9 +159,6 @@ struct SignatureInformation
1458e3
     /// For PDF: the byte range doesn't cover the whole document.
1458e3
     bool bPartialDocumentSignature;
1458e3
 
1458e3
-    /// The certificate owner (aka subject).
1458e3
-    OUString ouSubject;
1458e3
-
1458e3
     svl::crypto::SignatureMethodAlgorithm eAlgorithmID;
1458e3
 
1458e3
     SignatureInformation( sal_Int32 nId )
1458e3
diff --git a/svl/source/crypto/cryptosign.cxx b/svl/source/crypto/cryptosign.cxx
1458e3
index 5a3f0271c40d..1b882bb89deb 100644
1458e3
--- a/svl/source/crypto/cryptosign.cxx
1458e3
+++ b/svl/source/crypto/cryptosign.cxx
1458e3
@@ -2097,8 +2097,12 @@ bool Signing::Verify(const std::vector<unsigned char>& aData,
1458e3
             aDerCert[i] = pCertificate->derCert.data[i];
1458e3
         OUStringBuffer aBuffer;
1458e3
         comphelper::Base64::encode(aBuffer, aDerCert);
1458e3
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
1458e3
-        rInformation.ouSubject = OUString(pCertificate->subjectName, PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
1458e3
+        SignatureInformation::X509Data temp;
1458e3
+        temp.emplace_back();
1458e3
+        temp.back().X509Certificate = aBuffer.makeStringAndClear();
1458e3
+        temp.back().X509Subject = OUString(pCertificate->subjectName, PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
1458e3
+        rInformation.X509Datas.clear();
1458e3
+        rInformation.X509Datas.emplace_back(temp);
1458e3
     }
1458e3
 
1458e3
     PRTime nSigningTime;
1458e3
@@ -2277,8 +2281,12 @@ bool Signing::Verify(const std::vector<unsigned char>& aData,
1458e3
             aDerCert[i] = pSignerCertContext->pbCertEncoded[i];
1458e3
         OUStringBuffer aBuffer;
1458e3
         comphelper::Base64::encode(aBuffer, aDerCert);
1458e3
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
1458e3
-        rInformation.ouSubject = GetSubjectName(pSignerCertContext);
1458e3
+        SignatureInformation::X509Data temp;
1458e3
+        temp.emplace_back();
1458e3
+        temp.back().X509Certificate = aBuffer.makeStringAndClear();
1458e3
+        temp.back().X509Subject = GetSubjectName(pSignerCertContext);
1458e3
+        rInformation.X509Datas.clear();
1458e3
+        rInformation.X509Datas.emplace_back(temp);
1458e3
     }
1458e3
 
1458e3
     if (bNonDetached)
1458e3
diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx
1458e3
index 2b49ee16ecc8..abbed5e40e94 100644
1458e3
--- a/sw/source/core/edit/edfcol.cxx
1458e3
+++ b/sw/source/core/edit/edfcol.cxx
1458e3
@@ -411,7 +411,8 @@ std::pair<bool, OUString> lcl_MakeParagraphSignatureFieldText(const SignatureDes
1458e3
             valid = valid
1458e3
                     && aInfo.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
1458e3
 
1458e3
-            msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.ouSubject + ", " +
1458e3
+            assert(aInfo.GetSigningCertificate()); // it was valid
1458e3
+            msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.GetSigningCertificate()->X509Subject + ", " +
1458e3
                 aDescr.msDate;
1458e3
             msg += (!aDescr.msUsage.isEmpty() ? (" (" + aDescr.msUsage + "): ") : OUString(": "));
1458e3
             msg += (valid ? SwResId(STR_VALID) : SwResId(STR_INVALID));
1458e3
diff --git a/xmlsecurity/inc/biginteger.hxx b/xmlsecurity/inc/biginteger.hxx
1458e3
index d07ecf45d8af..8b4d8a9143b5 100644
1458e3
--- a/xmlsecurity/inc/biginteger.hxx
1458e3
+++ b/xmlsecurity/inc/biginteger.hxx
1458e3
@@ -31,6 +31,9 @@ namespace xmlsecurity
1458e3
 {
1458e3
 XSECXMLSEC_DLLPUBLIC OUString bigIntegerToNumericString( const css::uno::Sequence< sal_Int8 >& serial );
1458e3
 XSECXMLSEC_DLLPUBLIC css::uno::Sequence< sal_Int8 > numericStringToBigInteger ( const OUString& serialNumber );
1458e3
+
1458e3
+XSECXMLSEC_DLLPUBLIC bool EqualDistinguishedNames(OUString const& rName1,
1458e3
+                                                  OUString const& rName2);
1458e3
 }
1458e3
 
1458e3
 #endif
1458e3
diff --git a/xmlsecurity/inc/xmlsignaturehelper.hxx b/xmlsecurity/inc/xmlsignaturehelper.hxx
1458e3
index 0fcbd665251f..2456ddd437ec 100644
1458e3
--- a/xmlsecurity/inc/xmlsignaturehelper.hxx
1458e3
+++ b/xmlsecurity/inc/xmlsignaturehelper.hxx
1458e3
@@ -28,6 +28,9 @@
1458e3
 #include "xmlsignaturehelper.hxx"
1458e3
 #include "xsecctl.hxx"
1458e3
 
1458e3
+#include <com/sun/star/security/XCertificate.hpp>
1458e3
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
1458e3
+
1458e3
 class DateTime;
1458e3
 class UriBindingHelper;
1458e3
 
1458e3
@@ -93,6 +96,15 @@ public:
1458e3
                 // After signing/verifying, get information about signatures
1458e3
     SignatureInformation  GetSignatureInformation( sal_Int32 nSecurityId ) const;
1458e3
     SignatureInformations GetSignatureInformations() const;
1458e3
+    /// ImplVerifySignature calls this to figure out which X509Data is the
1458e3
+    /// signing certificate and update the internal state with the result.
1458e3
+    /// @return
1458e3
+    ///    A sequence with the signing certificate at the back on success.
1458e3
+    ///    An empty sequence on failure.
1458e3
+    std::vector<css::uno::Reference<css::security::XCertificate>>
1458e3
+    CheckAndUpdateSignatureInformation(
1458e3
+        css::uno::Reference<css::xml::crypto::XSecurityEnvironment> const& xSecEnv,
1458e3
+        SignatureInformation const& rInfo);
1458e3
 
1458e3
                 // See XSecController for documentation
1458e3
     void        StartMission(const css::uno::Reference<css::xml::crypto::XXMLSecurityContext>& xSecurityContext);
1458e3
diff --git a/xmlsecurity/inc/xsecctl.hxx b/xmlsecurity/inc/xsecctl.hxx
1458e3
index 7baa219fb13c..7ce35cea22bf 100644
1458e3
--- a/xmlsecurity/inc/xsecctl.hxx
1458e3
+++ b/xmlsecurity/inc/xsecctl.hxx
1458e3
@@ -252,6 +252,7 @@ private:
1458e3
     /// Sets algorithm from <SignatureMethod Algorithm="...">.
1458e3
     void setSignatureMethod(svl::crypto::SignatureMethodAlgorithm eAlgorithmID);
1458e3
     void switchGpgSignature();
1458e3
+    bool haveReferenceForId(OUString const& rId) const;
1458e3
     void addReference(
1458e3
         const OUString& ouUri,
1458e3
         sal_Int32 nDigestID,
1458e3
@@ -262,9 +263,13 @@ private:
1458e3
         sal_Int32 nDigestID );
1458e3
     void setReferenceCount() const;
1458e3
 
1458e3
-    void setX509IssuerName( OUString const & ouX509IssuerName );
1458e3
-    void setX509SerialNumber( OUString const & ouX509SerialNumber );
1458e3
-    void setX509Certificate( OUString const & ouX509Certificate );
1458e3
+    void setX509Data(
1458e3
+        std::vector<std::pair<OUString, OUString>> & rX509IssuerSerials,
1458e3
+        std::vector<OUString> const& rX509Certificates);
1458e3
+    void setX509CertDigest(
1458e3
+        OUString const& rCertDigest, sal_Int32 const nReferenceDigestID,
1458e3
+        OUString const& rX509IssuerName, OUString const& rX509SerialNumber);
1458e3
+
1458e3
     void setSignatureValue( OUString const & ouSignatureValue );
1458e3
     void setDigestValue( sal_Int32 nDigestID, OUString const & ouDigestValue );
1458e3
     void setGpgKeyID( OUString const & ouKeyID );
1458e3
@@ -273,7 +278,6 @@ private:
1458e3
 
1458e3
     void setDate(OUString const& rId, OUString const& ouDate);
1458e3
     void setDescription(OUString const& rId, OUString const& rDescription);
1458e3
-    void setCertDigest(const OUString& rCertDigest);
1458e3
     void setValidSignatureImage(const OUString& rValidSigImg);
1458e3
     void setInvalidSignatureImage(const OUString& rInvalidSigImg);
1458e3
     void setSignatureLineId(const OUString& rSignatureLineId);
1458e3
@@ -302,6 +306,9 @@ public:
1458e3
 
1458e3
     SignatureInformation    getSignatureInformation( sal_Int32 nSecurityId ) const;
1458e3
     SignatureInformations   getSignatureInformations() const;
1458e3
+    /// only verify can figure out which X509Data is the signing certificate
1458e3
+    void UpdateSignatureInformation(sal_Int32 nSecurityId,
1458e3
+            std::vector<SignatureInformation::X509Data> const& rDatas);
1458e3
 
1458e3
     static void exportSignature(
1458e3
         const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler,
1458e3
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx
1458e3
index 52cb938a8e0a..8a5bf37a0432 100644
1458e3
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
1458e3
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
1458e3
@@ -510,30 +510,36 @@ DocumentDigitalSignatures::ImplVerifySignatures(
1458e3
         const SignatureInformation& rInfo = aSignInfos[n];
1458e3
         css::security::DocumentSignatureInformation& rSigInfo = arInfos[n];
1458e3
 
1458e3
-        if (rInfo.ouGpgCertificate.isEmpty()) // X.509
1458e3
+        if (!rInfo.X509Datas.empty()) // X.509
1458e3
         {
1458e3
-            if (!rInfo.ouX509Certificate.isEmpty())
1458e3
-                rSigInfo.Signer = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
1458e3
-            if (!rSigInfo.Signer.is())
1458e3
-                rSigInfo.Signer = xSecEnv->getCertificate(
1458e3
-                    rInfo.ouX509IssuerName,
1458e3
-                    xmlsecurity::numericStringToBigInteger(rInfo.ouX509SerialNumber));
1458e3
-
1458e3
-            // On Windows checking the certificate path is buggy. It does name matching (issuer, subject name)
1458e3
-            // to find the parent certificate. It does not take into account that there can be several certificates
1458e3
-            // with the same subject name.
1458e3
-            try
1458e3
+            std::vector<uno::Reference<XCertificate>> certs(
1458e3
+                rSignatureHelper.CheckAndUpdateSignatureInformation(
1458e3
+                    xSecEnv, rInfo));
1458e3
+            if (certs.empty())
1458e3
             {
1458e3
-                rSigInfo.CertificateStatus = xSecEnv->verifyCertificate(
1458e3
-                    rSigInfo.Signer, Sequence<Reference<css::security::XCertificate>>());
1458e3
+                rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
1458e3
             }
1458e3
-            catch (SecurityException&)
1458e3
+            else
1458e3
             {
1458e3
-                OSL_FAIL("Verification of certificate failed");
1458e3
-                rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
1458e3
+                rSigInfo.Signer = certs.back();
1458e3
+                // get only intermediates
1458e3
+                certs.pop_back();
1458e3
+            // On Windows checking the certificate path is buggy. It does name matching (issuer, subject name)
1458e3
+            // to find the parent certificate. It does not take into account that there can be several certificates
1458e3
+            // with the same subject name.
1458e3
+                try
1458e3
+                {
1458e3
+                    rSigInfo.CertificateStatus = xSecEnv->verifyCertificate(
1458e3
+                        rSigInfo.Signer, comphelper::containerToSequence(certs));
1458e3
+                }
1458e3
+                catch (SecurityException&)
1458e3
+                {
1458e3
+                    SAL_WARN("xmlsecurity.comp", "Verification of certificate failed");
1458e3
+                    rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
1458e3
+                }
1458e3
             }
1458e3
         }
1458e3
-        else if (xGpgSecEnv.is()) // GPG
1458e3
+        else if (!rInfo.ouGpgCertificate.isEmpty() && xGpgSecEnv.is()) // GPG
1458e3
         {
1458e3
             // TODO not ideal to retrieve cert by keyID, might
1458e3
             // collide, or PGPKeyID format might change - can't we
1458e3
@@ -619,15 +625,19 @@ void DocumentDigitalSignatures::showCertificate(
1458e3
 }
1458e3
 
1458e3
 sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
1458e3
-    const Reference< css::security::XCertificate >& Author )
1458e3
+    const Reference<css::security::XCertificate>& xAuthor)
1458e3
 {
1458e3
-    OUString sSerialNum = xmlsecurity::bigIntegerToNumericString( Author->getSerialNumber() );
1458e3
+    if (!xAuthor.is())
1458e3
+    {
1458e3
+        return false;
1458e3
+    }
1458e3
+    OUString sSerialNum = xmlsecurity::bigIntegerToNumericString(xAuthor->getSerialNumber());
1458e3
 
1458e3
     Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = SvtSecurityOptions().GetTrustedAuthors();
1458e3
 
1458e3
     return std::any_of(aTrustedAuthors.begin(), aTrustedAuthors.end(),
1458e3
-        [&Author, &sSerialNum](const SvtSecurityOptions::Certificate& rAuthor) {
1458e3
-            return ( rAuthor[0] == Author->getIssuerName() )
1458e3
+        [&xAuthor, &sSerialNum](const SvtSecurityOptions::Certificate& rAuthor) {
1458e3
+            return xmlsecurity::EqualDistinguishedNames(rAuthor[0], xAuthor->getIssuerName())
1458e3
                 && ( rAuthor[1] == sSerialNum );
1458e3
         });
1458e3
 }
1458e3
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
1458e3
index ef67c7167c04..18ccaf2d2166 100644
1458e3
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
1458e3
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
1458e3
@@ -588,7 +588,7 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
1458e3
                 if (!rInfo.ouGpgCertificate.isEmpty())
1458e3
                     aType = "OpenPGP";
1458e3
                 // XML based: XAdES or not.
1458e3
-                else if (!rInfo.ouCertDigest.isEmpty())
1458e3
+                else if (rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->CertDigest.isEmpty())
1458e3
                     aType = "XAdES";
1458e3
                 else
1458e3
                     aType = "XML-DSig";
1458e3
@@ -700,8 +700,8 @@ uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(c
1458e3
     uno::Reference<security::XCertificate> xCert;
1458e3
 
1458e3
     //First we try to get the certificate which is embedded in the XML Signature
1458e3
-    if (xSecEnv.is() && !rInfo.ouX509Certificate.isEmpty())
1458e3
-        xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
1458e3
+    if (xSecEnv.is() && rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->X509Certificate.isEmpty())
1458e3
+        xCert = xSecEnv->createCertificateFromAscii(rInfo.GetSigningCertificate()->X509Certificate);
1458e3
     else {
1458e3
         //There must be an embedded certificate because we use it to get the
1458e3
         //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
1458e3
@@ -713,9 +713,12 @@ uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(c
1458e3
     }
1458e3
 
1458e3
     //In case there is no embedded certificate we try to get it from a local store
1458e3
-    if (!xCert.is() && xSecEnv.is())
1458e3
-        xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
1458e3
-    if (!xCert.is() && xGpgSecEnv.is())
1458e3
+    if (!xCert.is() && xSecEnv.is() && rInfo.GetSigningCertificate())
1458e3
+    {
1458e3
+        xCert = xSecEnv->getCertificate(rInfo.GetSigningCertificate()->X509IssuerName,
1458e3
+            xmlsecurity::numericStringToBigInteger(rInfo.GetSigningCertificate()->X509SerialNumber));
1458e3
+    }
1458e3
+    if (!xCert.is() && xGpgSecEnv.is() && !rInfo.ouGpgKeyID.isEmpty())
1458e3
         xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger("") );
1458e3
 
1458e3
     SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found and can't be created!" );
1458e3
diff --git a/xmlsecurity/source/helper/documentsignaturehelper.cxx b/xmlsecurity/source/helper/documentsignaturehelper.cxx
1458e3
index 482ae6cc4126..ddff308ee52f 100644
1458e3
--- a/xmlsecurity/source/helper/documentsignaturehelper.cxx
1458e3
+++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx
1458e3
@@ -492,6 +492,29 @@ void DocumentSignatureHelper::writeDigestMethod(
1458e3
     xDocumentHandler->endElement("DigestMethod");
1458e3
 }
1458e3
 
1458e3
+static void WriteXadesCert(
1458e3
+    uno::Reference<xml::sax::XDocumentHandler> const& xDocumentHandler,
1458e3
+    SignatureInformation::X509CertInfo const& rCertInfo)
1458e3
+{
1458e3
+    xDocumentHandler->startElement("xd:Cert", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+    xDocumentHandler->startElement("xd:CertDigest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+    DocumentSignatureHelper::writeDigestMethod(xDocumentHandler);
1458e3
+    xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+    assert(!rCertInfo.CertDigest.isEmpty());
1458e3
+    xDocumentHandler->characters(rCertInfo.CertDigest);
1458e3
+    xDocumentHandler->endElement("DigestValue");
1458e3
+    xDocumentHandler->endElement("xd:CertDigest");
1458e3
+    xDocumentHandler->startElement("xd:IssuerSerial", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+    xDocumentHandler->startElement("X509IssuerName", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+    xDocumentHandler->characters(rCertInfo.X509IssuerName);
1458e3
+    xDocumentHandler->endElement("X509IssuerName");
1458e3
+    xDocumentHandler->startElement("X509SerialNumber", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+    xDocumentHandler->characters(rCertInfo.X509SerialNumber);
1458e3
+    xDocumentHandler->endElement("X509SerialNumber");
1458e3
+    xDocumentHandler->endElement("xd:IssuerSerial");
1458e3
+    xDocumentHandler->endElement("xd:Cert");
1458e3
+}
1458e3
+
1458e3
 void DocumentSignatureHelper::writeSignedProperties(
1458e3
     const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
1458e3
     const SignatureInformation& signatureInfo,
1458e3
@@ -508,26 +531,26 @@ void DocumentSignatureHelper::writeSignedProperties(
1458e3
     xDocumentHandler->characters(sDate);
1458e3
     xDocumentHandler->endElement("xd:SigningTime");
1458e3
     xDocumentHandler->startElement("xd:SigningCertificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    xDocumentHandler->startElement("xd:Cert", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    xDocumentHandler->startElement("xd:CertDigest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    writeDigestMethod(xDocumentHandler);
1458e3
-
1458e3
-    xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    // TODO: this is empty for gpg signatures currently
1458e3
-    //assert(!signatureInfo.ouCertDigest.isEmpty());
1458e3
-    xDocumentHandler->characters(signatureInfo.ouCertDigest);
1458e3
-    xDocumentHandler->endElement("DigestValue");
1458e3
-
1458e3
-    xDocumentHandler->endElement("xd:CertDigest");
1458e3
-    xDocumentHandler->startElement("xd:IssuerSerial", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    xDocumentHandler->startElement("X509IssuerName", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    xDocumentHandler->characters(signatureInfo.ouX509IssuerName);
1458e3
-    xDocumentHandler->endElement("X509IssuerName");
1458e3
-    xDocumentHandler->startElement("X509SerialNumber", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    xDocumentHandler->characters(signatureInfo.ouX509SerialNumber);
1458e3
-    xDocumentHandler->endElement("X509SerialNumber");
1458e3
-    xDocumentHandler->endElement("xd:IssuerSerial");
1458e3
-    xDocumentHandler->endElement("xd:Cert");
1458e3
+    assert(signatureInfo.GetSigningCertificate() || !signatureInfo.ouGpgKeyID.isEmpty());
1458e3
+    if (signatureInfo.GetSigningCertificate())
1458e3
+    {
1458e3
+        // how should this deal with multiple X509Data elements?
1458e3
+        // for now, let's write all of the certificates ...
1458e3
+        for (auto const& rData : signatureInfo.X509Datas)
1458e3
+        {
1458e3
+            for (auto const& it : rData)
1458e3
+            {
1458e3
+                WriteXadesCert(xDocumentHandler, it);
1458e3
+            }
1458e3
+        }
1458e3
+    }
1458e3
+    else
1458e3
+    {
1458e3
+        // for PGP, write empty mandatory X509IssuerName, X509SerialNumber
1458e3
+        SignatureInformation::X509CertInfo temp;
1458e3
+        temp.CertDigest = signatureInfo.ouGpgKeyID;
1458e3
+        WriteXadesCert(xDocumentHandler, temp);
1458e3
+    }
1458e3
     xDocumentHandler->endElement("xd:SigningCertificate");
1458e3
     xDocumentHandler->startElement("xd:SignaturePolicyIdentifier", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
     xDocumentHandler->startElement("xd:SignaturePolicyImplied", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx
1458e3
index a0e674c3bd1b..aa08dc5c499e 100644
1458e3
--- a/xmlsecurity/source/helper/documentsignaturemanager.cxx
1458e3
+++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx
1458e3
@@ -585,6 +585,18 @@ void DocumentSignatureManager::read(bool bUseTempStream, bool bCacheLastSignatur
1458e3
                                                             bCacheLastSignature);
1458e3
         maSignatureHelper.EndMission();
1458e3
 
1458e3
+        // this parses the XML independently from ImplVerifySignatures() - check
1458e3
+        // certificates here too ...
1458e3
+        for (auto const& it : maSignatureHelper.GetSignatureInformations())
1458e3
+        {
1458e3
+            if (!it.X509Datas.empty())
1458e3
+            {
1458e3
+                uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(
1458e3
+                    getSecurityEnvironment());
1458e3
+                getSignatureHelper().CheckAndUpdateSignatureInformation(xSecEnv, it);
1458e3
+            }
1458e3
+        }
1458e3
+
1458e3
         maCurrentSignatureInformations = maSignatureHelper.GetSignatureInformations();
1458e3
     }
1458e3
     else
1458e3
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
1458e3
index cf87d6e1ad17..cae2ef3f5b16 100644
1458e3
--- a/xmlsecurity/source/helper/ooxmlsecexporter.cxx
1458e3
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
1458e3
@@ -194,12 +194,23 @@ void OOXMLSecExporter::Impl::writeSignatureValue()
1458e3
 
1458e3
 void OOXMLSecExporter::Impl::writeKeyInfo()
1458e3
 {
1458e3
-    m_xDocumentHandler->startElement("KeyInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    m_xDocumentHandler->startElement("X509Data", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    m_xDocumentHandler->startElement("X509Certificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
-    m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
1458e3
-    m_xDocumentHandler->endElement("X509Certificate");
1458e3
-    m_xDocumentHandler->endElement("X509Data");
1458e3
+    m_xDocumentHandler->startElement(
1458e3
+        "KeyInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+    assert(m_rInformation.GetSigningCertificate());
1458e3
+    for (auto const& rData : m_rInformation.X509Datas)
1458e3
+    {
1458e3
+        m_xDocumentHandler->startElement(
1458e3
+            "X509Data", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+        for (auto const& it : rData)
1458e3
+        {
1458e3
+            m_xDocumentHandler->startElement(
1458e3
+                "X509Certificate",
1458e3
+                uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
1458e3
+            m_xDocumentHandler->characters(it.X509Certificate);
1458e3
+            m_xDocumentHandler->endElement("X509Certificate");
1458e3
+        }
1458e3
+        m_xDocumentHandler->endElement("X509Data");
1458e3
+    }
1458e3
     m_xDocumentHandler->endElement("KeyInfo");
1458e3
 }
1458e3
 
1458e3
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx b/xmlsecurity/source/helper/ooxmlsecparser.cxx
1458e3
index a200de60c07a..a25872fc057d 100644
1458e3
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
1458e3
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
1458e3
@@ -185,9 +185,22 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
1458e3
         m_pXSecController->setSignatureValue(m_aSignatureValue);
1458e3
         m_bInSignatureValue = false;
1458e3
     }
1458e3
+    else if (rName == "X509Data")
1458e3
+    {
1458e3
+        std::vector<std::pair<OUString, OUString>> X509IssuerSerials;
1458e3
+        std::vector<OUString> X509Certificates;
1458e3
+        if (!m_aX509Certificate.isEmpty())
1458e3
+        {
1458e3
+            X509Certificates.emplace_back(m_aX509Certificate);
1458e3
+        }
1458e3
+        if (!m_aX509IssuerName.isEmpty() && !m_aX509SerialNumber.isEmpty())
1458e3
+        {
1458e3
+            X509IssuerSerials.emplace_back(m_aX509IssuerName, m_aX509SerialNumber);
1458e3
+        }
1458e3
+        m_pXSecController->setX509Data(X509IssuerSerials, X509Certificates);
1458e3
+    }
1458e3
     else if (rName == "X509Certificate")
1458e3
     {
1458e3
-        m_pXSecController->setX509Certificate(m_aX509Certificate);
1458e3
         m_bInX509Certificate = false;
1458e3
     }
1458e3
     else if (rName == "mdssi:Value")
1458e3
@@ -202,17 +215,18 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
1458e3
     }
1458e3
     else if (rName == "X509IssuerName")
1458e3
     {
1458e3
-        m_pXSecController->setX509IssuerName(m_aX509IssuerName);
1458e3
         m_bInX509IssuerName = false;
1458e3
     }
1458e3
     else if (rName == "X509SerialNumber")
1458e3
     {
1458e3
-        m_pXSecController->setX509SerialNumber(m_aX509SerialNumber);
1458e3
         m_bInX509SerialNumber = false;
1458e3
     }
1458e3
+    else if (rName == "xd:Cert")
1458e3
+    {
1458e3
+        m_pXSecController->setX509CertDigest(m_aCertDigest, css::xml::crypto::DigestID::SHA1, m_aX509IssuerName, m_aX509SerialNumber);
1458e3
+    }
1458e3
     else if (rName == "xd:CertDigest")
1458e3
     {
1458e3
-        m_pXSecController->setCertDigest(m_aCertDigest);
1458e3
         m_bInCertDigest = false;
1458e3
     }
1458e3
     else if (rName == "Object")
1458e3
diff --git a/xmlsecurity/source/helper/pdfsignaturehelper.cxx b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
1458e3
index f10f29c61840..8a90b73901db 100644
1458e3
--- a/xmlsecurity/source/helper/pdfsignaturehelper.cxx
1458e3
+++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
1458e3
@@ -82,8 +82,12 @@ PDFSignatureHelper::GetDocumentSignatureInformations(
1458e3
         security::DocumentSignatureInformation& rExternal = aRet[i];
1458e3
         rExternal.SignatureIsValid
1458e3
             = rInternal.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
1458e3
-        if (!rInternal.ouX509Certificate.isEmpty())
1458e3
-            rExternal.Signer = xSecEnv->createCertificateFromAscii(rInternal.ouX509Certificate);
1458e3
+        if (rInternal.GetSigningCertificate()
1458e3
+            && !rInternal.GetSigningCertificate()->X509Certificate.isEmpty())
1458e3
+        {
1458e3
+            rExternal.Signer = xSecEnv->createCertificateFromAscii(
1458e3
+                rInternal.GetSigningCertificate()->X509Certificate);
1458e3
+        }
1458e3
         rExternal.PartialDocumentSignature = rInternal.bPartialDocumentSignature;
1458e3
 
1458e3
         // Verify certificate.
1458e3
diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
1458e3
index 22c056e70da1..bcb79039e342 100644
1458e3
--- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx
1458e3
+++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
1458e3
@@ -21,6 +21,7 @@
1458e3
 #include <xmlsignaturehelper.hxx>
1458e3
 #include <documentsignaturehelper.hxx>
1458e3
 #include <xsecctl.hxx>
1458e3
+#include <biginteger.hxx>
1458e3
 
1458e3
 #include <xmlsignaturehelper2.hxx>
1458e3
 
1458e3
@@ -45,6 +46,8 @@
1458e3
 #include <tools/diagnose_ex.h>
1458e3
 #include <sal/log.hxx>
1458e3
 
1458e3
+#include <optional>
1458e3
+
1458e3
 #define NS_DOCUMENTSIGNATURES   "http://openoffice.org/2004/documentsignatures"
1458e3
 #define NS_DOCUMENTSIGNATURES_ODF_1_2 "urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0"
1458e3
 #define OOXML_SIGNATURE_ORIGIN "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin"
1458e3
@@ -547,4 +550,162 @@ void XMLSignatureHelper::CreateAndWriteOOXMLSignature(const uno::Reference
1458e3
     xSaxWriter->endDocument();
1458e3
 }
1458e3
 
1458e3
+/** check this constraint from xmldsig-core 4.5.4:
1458e3
+
1458e3
+  All certificates appearing in an X509Data element MUST relate to the
1458e3
+  validation key by either containing it or being part of a certification
1458e3
+  chain that terminates in a certificate containing the validation key.
1458e3
+ */
1458e3
+static auto CheckX509Data(
1458e3
+    uno::Reference<xml::crypto::XSecurityEnvironment> const& xSecEnv,
1458e3
+    std::vector<SignatureInformation::X509CertInfo> const& rX509CertInfos,
1458e3
+    std::vector<uno::Reference<security::XCertificate>> & rCerts,
1458e3
+    std::vector<SignatureInformation::X509CertInfo> & rSorted) -> bool
1458e3
+{
1458e3
+    assert(rCerts.empty());
1458e3
+    assert(rSorted.empty());
1458e3
+    if (rX509CertInfos.empty())
1458e3
+    {
1458e3
+        SAL_WARN("xmlsecurity.comp", "no X509Data");
1458e3
+        return false;
1458e3
+    }
1458e3
+    std::vector<uno::Reference<security::XCertificate>> certs;
1458e3
+    for (SignatureInformation::X509CertInfo const& it : rX509CertInfos)
1458e3
+    {
1458e3
+        if (!it.X509Certificate.isEmpty())
1458e3
+        {
1458e3
+            certs.emplace_back(xSecEnv->createCertificateFromAscii(it.X509Certificate));
1458e3
+        }
1458e3
+        else
1458e3
+        {
1458e3
+            certs.emplace_back(xSecEnv->getCertificate(
1458e3
+                it.X509IssuerName,
1458e3
+                xmlsecurity::numericStringToBigInteger(it.X509SerialNumber)));
1458e3
+        }
1458e3
+        if (!certs.back().is())
1458e3
+        {
1458e3
+            SAL_WARN("xmlsecurity.comp", "X509Data cannot be parsed");
1458e3
+            return false;
1458e3
+        }
1458e3
+    }
1458e3
+
1458e3
+    // first, search one whose issuer isn't in the list, or a self-signed one
1458e3
+    std::optional<size_t> start;
1458e3
+    for (size_t i = 0; i < certs.size(); ++i)
1458e3
+    {
1458e3
+        for (size_t j = 0; ; ++j)
1458e3
+        {
1458e3
+            if (j == certs.size())
1458e3
+            {
1458e3
+                if (start)
1458e3
+                {
1458e3
+                    SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate has no issuer but already have start of chain: " << certs[i]->getSubjectName());
1458e3
+                    return false;
1458e3
+                }
1458e3
+                start = i; // issuer isn't in the list
1458e3
+                break;
1458e3
+            }
1458e3
+            if (xmlsecurity::EqualDistinguishedNames(certs[i]->getIssuerName(), certs[j]->getSubjectName()))
1458e3
+            {
1458e3
+                if (i == j) // self signed
1458e3
+                {
1458e3
+                    if (start)
1458e3
+                    {
1458e3
+                        SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate is self-signed but already have start of chain: " << certs[i]->getSubjectName());
1458e3
+                        return false;
1458e3
+                    }
1458e3
+                    start = i;
1458e3
+                }
1458e3
+                break;
1458e3
+            }
1458e3
+        }
1458e3
+    }
1458e3
+    std::vector<size_t> chain;
1458e3
+    if (!start)
1458e3
+    {
1458e3
+        // this can only be a cycle?
1458e3
+        SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: cycle detected");
1458e3
+        return false;
1458e3
+    }
1458e3
+    chain.emplace_back(*start);
1458e3
+
1458e3
+    // second, check that there is a chain, no tree or cycle...
1458e3
+    for (size_t i = 0; i < certs.size(); ++i)
1458e3
+    {
1458e3
+        assert(chain.size() == i + 1);
1458e3
+        for (size_t j = 0; j < certs.size(); ++j)
1458e3
+        {
1458e3
+            if (chain[i] != j)
1458e3
+            {
1458e3
+                if (xmlsecurity::EqualDistinguishedNames(
1458e3
+                        certs[chain[i]]->getSubjectName(), certs[j]->getIssuerName()))
1458e3
+                {
1458e3
+                    if (chain.size() != i + 1) // already found issuee?
1458e3
+                    {
1458e3
+                        SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate issued 2 others: " << certs[chain[i]]->getSubjectName());
1458e3
+                        return false;
1458e3
+                    }
1458e3
+                    chain.emplace_back(j);
1458e3
+                }
1458e3
+            }
1458e3
+        }
1458e3
+        if (i == certs.size() - 1)
1458e3
+        {   // last one: must be a leaf
1458e3
+            if (chain.size() != i + 1)
1458e3
+            {
1458e3
+                SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate in cycle: " << certs[chain[i]]->getSubjectName());
1458e3
+                return false;
1458e3
+            }
1458e3
+        }
1458e3
+        else if (chain.size() != i + 2)
1458e3
+        {   // not issuer of another?
1458e3
+            SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate issued 0 others: " << certs[chain[i]]->getSubjectName());
1458e3
+            return false;
1458e3
+        }
1458e3
+    }
1458e3
+
1458e3
+    // success
1458e3
+    assert(chain.size() == rX509CertInfos.size());
1458e3
+    for (auto const& it : chain)
1458e3
+    {
1458e3
+        rSorted.emplace_back(rX509CertInfos[it]);
1458e3
+        rCerts.emplace_back(certs[it]);
1458e3
+    }
1458e3
+    return true;
1458e3
+}
1458e3
+
1458e3
+std::vector<uno::Reference<security::XCertificate>>
1458e3
+XMLSignatureHelper::CheckAndUpdateSignatureInformation(
1458e3
+    uno::Reference<xml::crypto::XSecurityEnvironment> const& xSecEnv,
1458e3
+    SignatureInformation const& rInfo)
1458e3
+{
1458e3
+    // if the check fails, it's not possible to determine which X509Data
1458e3
+    // contained the signing certificate - the UI cannot display something
1458e3
+    // useful in this case, so prevent anything misleading by clearing the
1458e3
+    // X509Datas.
1458e3
+
1458e3
+    std::vector<uno::Reference<security::XCertificate>> certs;
1458e3
+    std::vector<SignatureInformation::X509Data> datas;
1458e3
+    // TODO: for now, just merge all X509Datas together for checking...
1458e3
+    // (this will probably break round-trip of signature with multiple X509Data,
1458e3
+    // no idea if that is a problem)
1458e3
+    SignatureInformation::X509Data temp;
1458e3
+    SignatureInformation::X509Data tempResult;
1458e3
+    for (auto const& rData : rInfo.X509Datas)
1458e3
+    {
1458e3
+        for (auto const& it : rData)
1458e3
+        {
1458e3
+            temp.emplace_back(it);
1458e3
+        }
1458e3
+    }
1458e3
+    if (CheckX509Data(xSecEnv, temp, certs, tempResult))
1458e3
+    {
1458e3
+        datas.emplace_back(tempResult);
1458e3
+    }
1458e3
+
1458e3
+    // rInfo is a copy, update the original
1458e3
+    mpXSecController->UpdateSignatureInformation(rInfo.nSecurityId, datas);
1458e3
+    return certs;
1458e3
+}
1458e3
+
1458e3
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1458e3
diff --git a/xmlsecurity/source/helper/xsecctl.cxx b/xmlsecurity/source/helper/xsecctl.cxx
1458e3
index 8d5ea68c768b..0901d05dbdbd 100644
1458e3
--- a/xmlsecurity/source/helper/xsecctl.cxx
1458e3
+++ b/xmlsecurity/source/helper/xsecctl.cxx
1458e3
@@ -737,8 +737,8 @@ void XSecController::exportSignature(
1458e3
                     /* Write keyid element */
1458e3
                     xDocumentHandler->startElement(
1458e3
                         "PGPKeyID",
1458e3
-                        cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
1458e3
-                    xDocumentHandler->characters( signatureInfo.ouCertDigest );
1458e3
+                        css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
1458e3
+                    xDocumentHandler->characters(signatureInfo.ouGpgKeyID);
1458e3
                     xDocumentHandler->endElement( "PGPKeyID" );
1458e3
 
1458e3
                     /* Write PGPKeyPacket element */
1458e3
@@ -762,43 +762,50 @@ void XSecController::exportSignature(
1458e3
             }
1458e3
             else
1458e3
             {
1458e3
-                /* Write X509Data element */
1458e3
-                xDocumentHandler->startElement(
1458e3
-                    "X509Data",
1458e3
-                    cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
1458e3
+                assert(signatureInfo.GetSigningCertificate());
1458e3
+                for (auto const& rData : signatureInfo.X509Datas)
1458e3
                 {
1458e3
-                    /* Write X509IssuerSerial element */
1458e3
+                    /* Write X509Data element */
1458e3
                     xDocumentHandler->startElement(
1458e3
-                        "X509IssuerSerial",
1458e3
-                        cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
1458e3
-                    {
1458e3
-                        /* Write X509IssuerName element */
1458e3
-                        xDocumentHandler->startElement(
1458e3
-                            "X509IssuerName",
1458e3
-                            cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
1458e3
-                        xDocumentHandler->characters( signatureInfo.ouX509IssuerName );
1458e3
-                        xDocumentHandler->endElement( "X509IssuerName" );
1458e3
-
1458e3
-                        /* Write X509SerialNumber element */
1458e3
-                        xDocumentHandler->startElement(
1458e3
-                            "X509SerialNumber",
1458e3
-                            cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
1458e3
-                        xDocumentHandler->characters( signatureInfo.ouX509SerialNumber );
1458e3
-                        xDocumentHandler->endElement( "X509SerialNumber" );
1458e3
-                    }
1458e3
-                    xDocumentHandler->endElement( "X509IssuerSerial" );
1458e3
-
1458e3
-                    /* Write X509Certificate element */
1458e3
-                    if (!signatureInfo.ouX509Certificate.isEmpty())
1458e3
+                        "X509Data",
1458e3
+                        css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
1458e3
                     {
1458e3
-                        xDocumentHandler->startElement(
1458e3
-                            "X509Certificate",
1458e3
-                            cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
1458e3
-                        xDocumentHandler->characters( signatureInfo.ouX509Certificate );
1458e3
-                        xDocumentHandler->endElement( "X509Certificate" );
1458e3
+                        for (auto const& it : rData)
1458e3
+                        {
1458e3
+                            /* Write X509IssuerSerial element */
1458e3
+                            xDocumentHandler->startElement(
1458e3
+                                "X509IssuerSerial",
1458e3
+                                css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
1458e3
+                            {
1458e3
+                                /* Write X509IssuerName element */
1458e3
+                                xDocumentHandler->startElement(
1458e3
+                                    "X509IssuerName",
1458e3
+                                    css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
1458e3
+                                xDocumentHandler->characters(it.X509IssuerName);
1458e3
+                                xDocumentHandler->endElement( "X509IssuerName" );
1458e3
+
1458e3
+                                /* Write X509SerialNumber element */
1458e3
+                                xDocumentHandler->startElement(
1458e3
+                                    "X509SerialNumber",
1458e3
+                                    css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
1458e3
+                                xDocumentHandler->characters(it.X509SerialNumber);
1458e3
+                                xDocumentHandler->endElement( "X509SerialNumber" );
1458e3
+                            }
1458e3
+                            xDocumentHandler->endElement( "X509IssuerSerial" );
1458e3
+
1458e3
+                            /* Write X509Certificate element */
1458e3
+                            if (!it.X509Certificate.isEmpty())
1458e3
+                            {
1458e3
+                                xDocumentHandler->startElement(
1458e3
+                                    "X509Certificate",
1458e3
+                                    css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
1458e3
+                                xDocumentHandler->characters(it.X509Certificate);
1458e3
+                                xDocumentHandler->endElement( "X509Certificate" );
1458e3
+                            }
1458e3
+                        }
1458e3
                     }
1458e3
+                    xDocumentHandler->endElement( "X509Data" );
1458e3
                 }
1458e3
-                xDocumentHandler->endElement( "X509Data" );
1458e3
             }
1458e3
         }
1458e3
         xDocumentHandler->endElement( "KeyInfo" );
1458e3
@@ -917,6 +924,15 @@ void XSecController::exportOOXMLSignature(const uno::Reference<embed::XStorage>&
1458e3
     aExporter.writeSignature();
1458e3
 }
1458e3
 
1458e3
+void XSecController::UpdateSignatureInformation(sal_Int32 const nSecurityId,
1458e3
+    std::vector<SignatureInformation::X509Data> const& rDatas)
1458e3
+{
1458e3
+    SignatureInformation aInf( 0 );
1458e3
+    int const nIndex = findSignatureInfor(nSecurityId);
1458e3
+    assert(nIndex != -1); // nothing should touch this between parsing and verify
1458e3
+    m_vInternalSignatureInformations[nIndex].signatureInfor.X509Datas = rDatas;
1458e3
+}
1458e3
+
1458e3
 SignatureInformation XSecController::getSignatureInformation( sal_Int32 nSecurityId ) const
1458e3
 {
1458e3
     SignatureInformation aInf( 0 );
1458e3
diff --git a/xmlsecurity/source/helper/xsecparser.cxx b/xmlsecurity/source/helper/xsecparser.cxx
1458e3
index 9cc9312b4d9f..595a02ed687d 100644
1458e3
--- a/xmlsecurity/source/helper/xsecparser.cxx
1458e3
+++ b/xmlsecurity/source/helper/xsecparser.cxx
1458e3
@@ -99,6 +99,42 @@ auto XSecParser::Context::CreateChildContext(
1458e3
     return std::make_unique<UnknownContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
 }
1458e3
 
1458e3
+/**
1458e3
+note: anything in ds:Object should be trusted *only* if there is a ds:Reference
1458e3
+      to it so it is signed (exception: the xades:EncapsulatedX509Certificate).
1458e3
+      ds:SignedInfo precedes all ds:Object.
1458e3
+
1458e3
+      There may be multiple ds:Signature for purpose of counter-signatures
1458e3
+      but the way XAdES describes these, only the ds:SignatureValue element
1458e3
+      would be referenced, so requiring a ds:Reference for anything in
1458e3
+      ds:Object shouldn't cause issues.
1458e3
+ */
1458e3
+class XSecParser::ReferencedContextImpl
1458e3
+    : public XSecParser::Context
1458e3
+{
1458e3
+    protected:
1458e3
+        bool m_isReferenced;
1458e3
+
1458e3
+    public:
1458e3
+        ReferencedContextImpl(XSecParser & rParser,
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+            , m_isReferenced(isReferenced)
1458e3
+        {
1458e3
+        }
1458e3
+
1458e3
+        OUString CheckIdAttrReferenced(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs)
1458e3
+        {
1458e3
+            OUString const id(m_rParser.HandleIdAttr(xAttrs));
1458e3
+            if (!id.isEmpty() && m_rParser.m_pXSecController->haveReferenceForId(id))
1458e3
+            {
1458e3
+                m_isReferenced = true;
1458e3
+            }
1458e3
+            return id;
1458e3
+        }
1458e3
+};
1458e3
+
1458e3
 class XSecParser::LoPGPOwnerContext
1458e3
     : public XSecParser::Context
1458e3
 {
1458e3
@@ -211,23 +247,20 @@ class XSecParser::DsX509CertificateContext
1458e3
     : public XSecParser::Context
1458e3
 {
1458e3
     private:
1458e3
-        OUString m_Value;
1458e3
+        OUString & m_rValue;
1458e3
 
1458e3
     public:
1458e3
         DsX509CertificateContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                OUString & rValue)
1458e3
             : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+            , m_rValue(rValue)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
-        virtual void EndElement() override
1458e3
-        {
1458e3
-            m_rParser.m_pXSecController->setX509Certificate(m_Value);
1458e3
-        }
1458e3
-
1458e3
         virtual void Characters(OUString const& rChars) override
1458e3
         {
1458e3
-            m_Value += rChars;
1458e3
+            m_rValue += rChars;
1458e3
         }
1458e3
 };
1458e3
 
1458e3
@@ -235,23 +268,20 @@ class XSecParser::DsX509SerialNumberContext
1458e3
     : public XSecParser::Context
1458e3
 {
1458e3
     private:
1458e3
-        OUString m_Value;
1458e3
+        OUString & m_rValue;
1458e3
 
1458e3
     public:
1458e3
         DsX509SerialNumberContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                OUString & rValue)
1458e3
             : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+            , m_rValue(rValue)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
-        virtual void EndElement() override
1458e3
-        {
1458e3
-            m_rParser.m_pXSecController->setX509SerialNumber(m_Value);
1458e3
-        }
1458e3
-
1458e3
         virtual void Characters(OUString const& rChars) override
1458e3
         {
1458e3
-            m_Value += rChars;
1458e3
+            m_rValue += rChars;
1458e3
         }
1458e3
 };
1458e3
 
1458e3
@@ -259,33 +289,37 @@ class XSecParser::DsX509IssuerNameContext
1458e3
     : public XSecParser::Context
1458e3
 {
1458e3
     private:
1458e3
-        OUString m_Value;
1458e3
+        OUString & m_rValue;
1458e3
 
1458e3
     public:
1458e3
         DsX509IssuerNameContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                OUString & rValue)
1458e3
             : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+            , m_rValue(rValue)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
-        virtual void EndElement() override
1458e3
-        {
1458e3
-            m_rParser.m_pXSecController->setX509IssuerName(m_Value);
1458e3
-        }
1458e3
-
1458e3
         virtual void Characters(OUString const& rChars) override
1458e3
         {
1458e3
-            m_Value += rChars;
1458e3
+            m_rValue += rChars;
1458e3
         }
1458e3
 };
1458e3
 
1458e3
 class XSecParser::DsX509IssuerSerialContext
1458e3
     : public XSecParser::Context
1458e3
 {
1458e3
+    private:
1458e3
+        OUString & m_rX509IssuerName;
1458e3
+        OUString & m_rX509SerialNumber;
1458e3
+
1458e3
     public:
1458e3
         DsX509IssuerSerialContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                OUString & rIssuerName, OUString & rSerialNumber)
1458e3
             : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+            , m_rX509IssuerName(rIssuerName)
1458e3
+            , m_rX509SerialNumber(rSerialNumber)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
@@ -295,20 +329,27 @@ class XSecParser::DsX509IssuerSerialContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerName")
1458e3
             {
1458e3
-                return std::make_unique<DsX509IssuerNameContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<DsX509IssuerNameContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509IssuerName);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509SerialNumber")
1458e3
             {
1458e3
-                return std::make_unique<DsX509SerialNumberContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<DsX509SerialNumberContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509SerialNumber);
1458e3
             }
1458e3
             // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
         }
1458e3
 };
1458e3
 
1458e3
+/// can't be sure what is supposed to happen here because the spec is clear as mud
1458e3
 class XSecParser::DsX509DataContext
1458e3
     : public XSecParser::Context
1458e3
 {
1458e3
+    private:
1458e3
+        // sigh... "No ordering is implied by the above constraints."
1458e3
+        // so store the ball of mud in vectors and try to figure it out later.
1458e3
+        std::vector<std::pair<OUString, OUString>> m_X509IssuerSerials;
1458e3
+        std::vector<OUString> m_X509Certificates;
1458e3
+
1458e3
     public:
1458e3
         DsX509DataContext(XSecParser & rParser,
1458e3
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
@@ -316,17 +357,24 @@ class XSecParser::DsX509DataContext
1458e3
         {
1458e3
         }
1458e3
 
1458e3
+        virtual void EndElement() override
1458e3
+        {
1458e3
+            m_rParser.m_pXSecController->setX509Data(m_X509IssuerSerials, m_X509Certificates);
1458e3
+        }
1458e3
+
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
             std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
             sal_uInt16 const nNamespace, OUString const& rName) override
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerSerial")
1458e3
             {
1458e3
-                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                m_X509IssuerSerials.emplace_back();
1458e3
+                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerSerials.back().first, m_X509IssuerSerials.back().second);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509Certificate")
1458e3
             {
1458e3
-                return std::make_unique<DsX509CertificateContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                m_X509Certificates.emplace_back();
1458e3
+                return std::make_unique<DsX509CertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_X509Certificates.back());
1458e3
             }
1458e3
             // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
@@ -791,21 +839,29 @@ class XSecParser::XadesUnsignedPropertiesContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::LoSignatureLineIdContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     private:
1458e3
         OUString m_Value;
1458e3
 
1458e3
     public:
1458e3
         LoSignatureLineIdContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void EndElement() override
1458e3
         {
1458e3
-            m_rParser.m_pXSecController->setSignatureLineId(m_Value);
1458e3
+            if (m_isReferenced)
1458e3
+            {
1458e3
+                m_rParser.m_pXSecController->setSignatureLineId(m_Value);
1458e3
+            }
1458e3
+            else
1458e3
+            {
1458e3
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineId");
1458e3
+            }
1458e3
         }
1458e3
 
1458e3
         virtual void Characters(OUString const& rChars) override
1458e3
@@ -815,21 +871,29 @@ class XSecParser::LoSignatureLineIdContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::LoSignatureLineValidImageContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     private:
1458e3
         OUString m_Value;
1458e3
 
1458e3
     public:
1458e3
         LoSignatureLineValidImageContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void EndElement() override
1458e3
         {
1458e3
-            m_rParser.m_pXSecController->setValidSignatureImage(m_Value);
1458e3
+            if (m_isReferenced)
1458e3
+            {
1458e3
+                m_rParser.m_pXSecController->setValidSignatureImage(m_Value);
1458e3
+            }
1458e3
+            else
1458e3
+            {
1458e3
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineValidImage");
1458e3
+            }
1458e3
         }
1458e3
 
1458e3
         virtual void Characters(OUString const& rChars) override
1458e3
@@ -839,21 +903,29 @@ class XSecParser::LoSignatureLineValidImageContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::LoSignatureLineInvalidImageContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     private:
1458e3
         OUString m_Value;
1458e3
 
1458e3
     public:
1458e3
         LoSignatureLineInvalidImageContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void EndElement() override
1458e3
         {
1458e3
-            m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value);
1458e3
+            if (m_isReferenced)
1458e3
+            {
1458e3
+                m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value);
1458e3
+            }
1458e3
+            else
1458e3
+            {
1458e3
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineInvalidImage");
1458e3
+            }
1458e3
         }
1458e3
 
1458e3
         virtual void Characters(OUString const& rChars) override
1458e3
@@ -863,12 +935,13 @@ class XSecParser::LoSignatureLineInvalidImageContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::LoSignatureLineContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     public:
1458e3
         LoSignatureLineContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
@@ -878,15 +951,15 @@ class XSecParser::LoSignatureLineContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLineId")
1458e3
             {
1458e3
-                return std::make_unique<LoSignatureLineIdContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<LoSignatureLineIdContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLineValidImage")
1458e3
             {
1458e3
-                return std::make_unique<LoSignatureLineValidImageContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<LoSignatureLineValidImageContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLineInvalidImage")
1458e3
             {
1458e3
-                return std::make_unique<LoSignatureLineInvalidImageContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<LoSignatureLineInvalidImageContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
         }
1458e3
@@ -896,70 +969,88 @@ class XSecParser::XadesCertDigestContext
1458e3
     : public XSecParser::Context
1458e3
 {
1458e3
     private:
1458e3
-        OUString m_Value;
1458e3
-        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
1458e3
+        OUString & m_rDigestValue;
1458e3
+        sal_Int32 & m_rReferenceDigestID;
1458e3
 
1458e3
     public:
1458e3
         XadesCertDigestContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                OUString & rDigestValue, sal_Int32 & rReferenceDigestID)
1458e3
             : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+            , m_rDigestValue(rDigestValue)
1458e3
+            , m_rReferenceDigestID(rReferenceDigestID)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
-        virtual void EndElement() override
1458e3
-        {
1458e3
-            m_rParser.m_pXSecController->setCertDigest(m_Value/* FIXME , m_nReferenceDigestID*/);
1458e3
-        }
1458e3
-
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
             std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
             sal_uInt16 const nNamespace, OUString const& rName) override
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
1458e3
             {
1458e3
-                return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_nReferenceDigestID);
1458e3
+                return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_rReferenceDigestID);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
1458e3
             {
1458e3
-                return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_Value);
1458e3
+                return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_rDigestValue);
1458e3
             }
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
         }
1458e3
 };
1458e3
 
1458e3
 class XSecParser::XadesCertContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
+    private:
1458e3
+        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
1458e3
+        OUString m_CertDigest;
1458e3
+        OUString m_X509IssuerName;
1458e3
+        OUString m_X509SerialNumber;
1458e3
+
1458e3
     public:
1458e3
         XadesCertContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
+        virtual void EndElement() override
1458e3
+        {
1458e3
+            if (m_isReferenced)
1458e3
+            {
1458e3
+                m_rParser.m_pXSecController->setX509CertDigest(m_CertDigest, m_nReferenceDigestID, m_X509IssuerName, m_X509SerialNumber);
1458e3
+            }
1458e3
+            else
1458e3
+            {
1458e3
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned xades:Cert");
1458e3
+            }
1458e3
+        }
1458e3
+
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
             std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
             sal_uInt16 const nNamespace, OUString const& rName) override
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "CertDigest")
1458e3
             {
1458e3
-                return std::make_unique<XadesCertDigestContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<XadesCertDigestContext>(m_rParser, std::move(pOldNamespaceMap), m_CertDigest, m_nReferenceDigestID);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "IssuerSerial")
1458e3
             {
1458e3
-                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber);
1458e3
             }
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
         }
1458e3
 };
1458e3
 
1458e3
 class XSecParser::XadesSigningCertificateContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     public:
1458e3
         XadesSigningCertificateContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
@@ -969,28 +1060,36 @@ class XSecParser::XadesSigningCertificateContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "Cert")
1458e3
             {
1458e3
-                return std::make_unique<XadesCertContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<XadesCertContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
         }
1458e3
 };
1458e3
 
1458e3
 class XSecParser::XadesSigningTimeContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     private:
1458e3
         OUString m_Value;
1458e3
 
1458e3
     public:
1458e3
         XadesSigningTimeContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void EndElement() override
1458e3
         {
1458e3
-            m_rParser.m_pXSecController->setDate("", m_Value);
1458e3
+            if (m_isReferenced)
1458e3
+            {
1458e3
+                m_rParser.m_pXSecController->setDate("", m_Value);
1458e3
+            }
1458e3
+            else
1458e3
+            {
1458e3
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SigningTime");
1458e3
+            }
1458e3
         }
1458e3
 
1458e3
         virtual void Characters(OUString const& rChars) override
1458e3
@@ -1000,19 +1099,20 @@ class XSecParser::XadesSigningTimeContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::XadesSignedSignaturePropertiesContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     public:
1458e3
         XadesSignedSignaturePropertiesContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void StartElement(
1458e3
             css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
1458e3
         {
1458e3
-            m_rParser.HandleIdAttr(xAttrs);
1458e3
+            CheckIdAttrReferenced(xAttrs);
1458e3
         }
1458e3
 
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
@@ -1021,15 +1121,15 @@ class XSecParser::XadesSignedSignaturePropertiesContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningTime")
1458e3
             {
1458e3
-                return std::make_unique<XadesSigningTimeContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<XadesSigningTimeContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningCertificate")
1458e3
             {
1458e3
-                return std::make_unique<XadesSigningCertificateContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<XadesSigningCertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLine")
1458e3
             {
1458e3
-                return std::make_unique<LoSignatureLineContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<LoSignatureLineContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             // missing: xades:SignaturePolicyIdentifier, xades:SignatureProductionPlace, xades:SignerRole
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
@@ -1037,19 +1137,20 @@ class XSecParser::XadesSignedSignaturePropertiesContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::XadesSignedPropertiesContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     public:
1458e3
         XadesSignedPropertiesContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void StartElement(
1458e3
             css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
1458e3
         {
1458e3
-            m_rParser.HandleIdAttr(xAttrs);
1458e3
+            CheckIdAttrReferenced(xAttrs);
1458e3
         }
1458e3
 
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
@@ -1058,7 +1159,7 @@ class XSecParser::XadesSignedPropertiesContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedSignatureProperties")
1458e3
             {
1458e3
-                return std::make_unique<XadesSignedSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<XadesSignedSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             // missing: xades:SignedDataObjectProperties
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
@@ -1066,19 +1167,20 @@ class XSecParser::XadesSignedPropertiesContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::XadesQualifyingPropertiesContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     public:
1458e3
         XadesQualifyingPropertiesContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void StartElement(
1458e3
             css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
1458e3
         {
1458e3
-            m_rParser.HandleIdAttr(xAttrs);
1458e3
+            CheckIdAttrReferenced(xAttrs);
1458e3
         }
1458e3
 
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
@@ -1087,7 +1189,7 @@ class XSecParser::XadesQualifyingPropertiesContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedProperties")
1458e3
             {
1458e3
-                return std::make_unique<XadesSignedPropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<XadesSignedPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "UnsignedProperties")
1458e3
             {
1458e3
@@ -1140,7 +1242,7 @@ class XSecParser::DcDescriptionContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::DsSignaturePropertyContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     private:
1458e3
         enum class SignatureProperty { Unknown, Date, Description };
1458e3
@@ -1150,30 +1252,38 @@ class XSecParser::DsSignaturePropertyContext
1458e3
 
1458e3
     public:
1458e3
         DsSignaturePropertyContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void StartElement(
1458e3
             css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
1458e3
         {
1458e3
-            m_Id = m_rParser.HandleIdAttr(xAttrs);
1458e3
+            m_Id = CheckIdAttrReferenced(xAttrs);
1458e3
         }
1458e3
 
1458e3
         virtual void EndElement() override
1458e3
         {
1458e3
-            switch (m_Property)
1458e3
+            if (m_isReferenced)
1458e3
+            {
1458e3
+                switch (m_Property)
1458e3
+                {
1458e3
+                    case SignatureProperty::Unknown:
1458e3
+                        SAL_INFO("xmlsecurity.helper", "Unknown property in ds:Object ignored");
1458e3
+                        break;
1458e3
+                    case SignatureProperty::Date:
1458e3
+                        m_rParser.m_pXSecController->setDate(m_Id, m_Value);
1458e3
+                        break;
1458e3
+                    case SignatureProperty::Description:
1458e3
+                        m_rParser.m_pXSecController->setDescription(m_Id, m_Value);
1458e3
+                        break;
1458e3
+                }
1458e3
+            }
1458e3
+            else
1458e3
             {
1458e3
-                case SignatureProperty::Unknown:
1458e3
-                    SAL_INFO("xmlsecurity.helper", "Unknown property in ds:Object ignored");
1458e3
-                    break;
1458e3
-                case SignatureProperty::Date:
1458e3
-                    m_rParser.m_pXSecController->setDate(m_Id, m_Value);
1458e3
-                    break;
1458e3
-                case SignatureProperty::Description:
1458e3
-                    m_rParser.m_pXSecController->setDescription(m_Id, m_Value);
1458e3
-                    break;
1458e3
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureProperty");
1458e3
             }
1458e3
         }
1458e3
 
1458e3
@@ -1196,19 +1306,20 @@ class XSecParser::DsSignaturePropertyContext
1458e3
 };
1458e3
 
1458e3
 class XSecParser::DsSignaturePropertiesContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     public:
1458e3
         DsSignaturePropertiesContext(XSecParser & rParser,
1458e3
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
1458e3
+                bool const isReferenced)
1458e3
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void StartElement(
1458e3
             css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
1458e3
         {
1458e3
-            m_rParser.HandleIdAttr(xAttrs);
1458e3
+            CheckIdAttrReferenced(xAttrs);
1458e3
         }
1458e3
 
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
@@ -1217,26 +1328,27 @@ class XSecParser::DsSignaturePropertiesContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperty")
1458e3
             {
1458e3
-                return std::make_unique<DsSignaturePropertyContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<DsSignaturePropertyContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
         }
1458e3
 };
1458e3
 
1458e3
 class XSecParser::DsObjectContext
1458e3
-    : public XSecParser::Context
1458e3
+    : public XSecParser::ReferencedContextImpl
1458e3
 {
1458e3
     public:
1458e3
         DsObjectContext(XSecParser & rParser,
1458e3
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
1458e3
-            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
1458e3
+            // init with "false" here - the Signature element can't be referenced by its child
1458e3
+            : XSecParser::ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), false)
1458e3
         {
1458e3
         }
1458e3
 
1458e3
         virtual void StartElement(
1458e3
             css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
1458e3
         {
1458e3
-            m_rParser.HandleIdAttr(xAttrs);
1458e3
+            CheckIdAttrReferenced(xAttrs);
1458e3
         }
1458e3
 
1458e3
         virtual std::unique_ptr<Context> CreateChildContext(
1458e3
@@ -1245,11 +1357,11 @@ class XSecParser::DsObjectContext
1458e3
         {
1458e3
             if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperties")
1458e3
             {
1458e3
-                return std::make_unique<DsSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<DsSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "QualifyingProperties")
1458e3
             {
1458e3
-                return std::make_unique<XadesQualifyingPropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
1458e3
+                return std::make_unique<XadesQualifyingPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
1458e3
             }
1458e3
             // missing: ds:Manifest
1458e3
             return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
1458e3
diff --git a/xmlsecurity/source/helper/xsecparser.hxx b/xmlsecurity/source/helper/xsecparser.hxx
1458e3
index 7a0eb08bca28..7674bf28b84d 100644
1458e3
--- a/xmlsecurity/source/helper/xsecparser.hxx
1458e3
+++ b/xmlsecurity/source/helper/xsecparser.hxx
1458e3
@@ -56,6 +56,7 @@ public:
1458e3
     class Context;
1458e3
 private:
1458e3
     class UnknownContext;
1458e3
+    class ReferencedContextImpl;
1458e3
     class LoPGPOwnerContext;
1458e3
     class DsPGPKeyPacketContext;
1458e3
     class DsPGPKeyIDContext;
1458e3
diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx
1458e3
index 5ed23281f083..38a420a370aa 100644
1458e3
--- a/xmlsecurity/source/helper/xsecsign.cxx
1458e3
+++ b/xmlsecurity/source/helper/xsecsign.cxx
1458e3
@@ -197,6 +197,7 @@ void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, boo
1458e3
     }
1458e3
 }
1458e3
 
1458e3
+// note: this is called when creating a new signature from scratch
1458e3
 void XSecController::setX509Certificate(
1458e3
     sal_Int32 nSecurityId,
1458e3
     const OUString& ouX509IssuerName,
1458e3
@@ -210,10 +211,13 @@ void XSecController::setX509Certificate(
1458e3
     if ( index == -1 )
1458e3
     {
1458e3
         InternalSignatureInformation isi(nSecurityId, nullptr);
1458e3
-        isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
1458e3
-        isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
1458e3
-        isi.signatureInfor.ouX509Certificate = ouX509Cert;
1458e3
-        isi.signatureInfor.ouCertDigest = ouX509CertDigest;
1458e3
+        isi.signatureInfor.X509Datas.clear();
1458e3
+        isi.signatureInfor.X509Datas.emplace_back();
1458e3
+        isi.signatureInfor.X509Datas.back().emplace_back();
1458e3
+        isi.signatureInfor.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
1458e3
+        isi.signatureInfor.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
1458e3
+        isi.signatureInfor.X509Datas.back().back().X509Certificate = ouX509Cert;
1458e3
+        isi.signatureInfor.X509Datas.back().back().CertDigest = ouX509CertDigest;
1458e3
         isi.signatureInfor.eAlgorithmID = eAlgorithmID;
1458e3
         m_vInternalSignatureInformations.push_back( isi );
1458e3
     }
1458e3
@@ -221,16 +225,19 @@ void XSecController::setX509Certificate(
1458e3
     {
1458e3
         SignatureInformation &si
1458e3
             = m_vInternalSignatureInformations[index].signatureInfor;
1458e3
-        si.ouX509IssuerName = ouX509IssuerName;
1458e3
-        si.ouX509SerialNumber = ouX509SerialNumber;
1458e3
-        si.ouX509Certificate = ouX509Cert;
1458e3
-        si.ouCertDigest = ouX509CertDigest;
1458e3
+        si.X509Datas.clear();
1458e3
+        si.X509Datas.emplace_back();
1458e3
+        si.X509Datas.back().emplace_back();
1458e3
+        si.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
1458e3
+        si.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
1458e3
+        si.X509Datas.back().back().X509Certificate = ouX509Cert;
1458e3
+        si.X509Datas.back().back().CertDigest = ouX509CertDigest;
1458e3
     }
1458e3
 }
1458e3
 
1458e3
 void XSecController::setGpgCertificate(
1458e3
         sal_Int32 nSecurityId,
1458e3
-        const OUString& ouCertDigest,
1458e3
+        const OUString& ouKeyDigest,
1458e3
         const OUString& ouCert,
1458e3
         const OUString& ouOwner)
1458e3
 {
1458e3
@@ -241,16 +248,17 @@ void XSecController::setGpgCertificate(
1458e3
         InternalSignatureInformation isi(nSecurityId, nullptr);
1458e3
         isi.signatureInfor.ouGpgCertificate = ouCert;
1458e3
         isi.signatureInfor.ouGpgOwner = ouOwner;
1458e3
-        isi.signatureInfor.ouCertDigest = ouCertDigest;
1458e3
+        isi.signatureInfor.ouGpgKeyID = ouKeyDigest;
1458e3
         m_vInternalSignatureInformations.push_back( isi );
1458e3
     }
1458e3
     else
1458e3
     {
1458e3
         SignatureInformation &si
1458e3
             = m_vInternalSignatureInformations[index].signatureInfor;
1458e3
+        si.X509Datas.clear(); // it is a PGP signature now
1458e3
         si.ouGpgCertificate = ouCert;
1458e3
         si.ouGpgOwner = ouOwner;
1458e3
-        si.ouCertDigest = ouCertDigest;
1458e3
+        si.ouGpgKeyID = ouKeyDigest;
1458e3
     }
1458e3
 }
1458e3
 
1458e3
diff --git a/xmlsecurity/source/helper/xsecverify.cxx b/xmlsecurity/source/helper/xsecverify.cxx
1458e3
index 5f5840334254..1f0445c35c14 100644
1458e3
--- a/xmlsecurity/source/helper/xsecverify.cxx
1458e3
+++ b/xmlsecurity/source/helper/xsecverify.cxx
1458e3
@@ -22,6 +22,7 @@
1458e3
 #include <xsecctl.hxx>
1458e3
 #include "xsecparser.hxx"
1458e3
 #include "ooxmlsecparser.hxx"
1458e3
+#include <biginteger.hxx>
1458e3
 #include <framework/signatureverifierimpl.hxx>
1458e3
 #include <framework/saxeventkeeperimpl.hxx>
1458e3
 #include <gpg/xmlsignature_gpgimpl.hxx>
1458e3
@@ -147,6 +148,25 @@ void XSecController::switchGpgSignature()
1458e3
 #endif
1458e3
 }
1458e3
 
1458e3
+bool XSecController::haveReferenceForId(OUString const& rId) const
1458e3
+{
1458e3
+    if (m_vInternalSignatureInformations.empty())
1458e3
+    {
1458e3
+        SAL_INFO("xmlsecurity.helper","XSecController::haveReferenceForId: no signature");
1458e3
+        return false;
1458e3
+    }
1458e3
+    InternalSignatureInformation const& rIsi(m_vInternalSignatureInformations.back());
1458e3
+    for (SignatureReferenceInformation const& rSri : rIsi.signatureInfor.vSignatureReferenceInfors)
1458e3
+    {
1458e3
+        if (rSri.nType == SignatureReferenceType::SAMEDOCUMENT
1458e3
+            && rSri.ouURI == rId) // ouUri has # stripped
1458e3
+        {
1458e3
+            return true;
1458e3
+        }
1458e3
+    }
1458e3
+    return false;
1458e3
+}
1458e3
+
1458e3
 void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID, const OUString& ouType )
1458e3
 {
1458e3
     if (m_vInternalSignatureInformations.empty())
1458e3
@@ -225,7 +245,9 @@ void XSecController::setReferenceCount() const
1458e3
     }
1458e3
 }
1458e3
 
1458e3
-void XSecController::setX509IssuerName( OUString const & ouX509IssuerName )
1458e3
+void XSecController::setX509Data(
1458e3
+        std::vector<std::pair<OUString, OUString>> & rX509IssuerSerials,
1458e3
+        std::vector<OUString> const& rX509Certificates)
1458e3
 {
1458e3
     if (m_vInternalSignatureInformations.empty())
1458e3
     {
1458e3
@@ -233,29 +255,52 @@ void XSecController::setX509IssuerName( OUString const & ouX509IssuerName )
1458e3
         return;
1458e3
     }
1458e3
     InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
1458e3
-    isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
1458e3
-}
1458e3
-
1458e3
-void XSecController::setX509SerialNumber( OUString const & ouX509SerialNumber )
1458e3
-{
1458e3
-    if (m_vInternalSignatureInformations.empty())
1458e3
+    SignatureInformation::X509Data data;
1458e3
+    // due to the excessive flexibility of the spec it's possible that there
1458e3
+    // is both a reference to a cert and the cert itself in one X509Data
1458e3
+    for (OUString const& it : rX509Certificates)
1458e3
     {
1458e3
-        SAL_INFO("xmlsecurity.helper","XSecController::setX509SerialNumber: no signature");
1458e3
-        return;
1458e3
+        try
1458e3
+        {
1458e3
+            data.emplace_back();
1458e3
+            data.back().X509Certificate = it;
1458e3
+            uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(m_xSecurityContext->getSecurityEnvironment());
1458e3
+            uno::Reference<security::XCertificate> const xCert(xSecEnv->createCertificateFromAscii(it));
1458e3
+            if (!xCert.is())
1458e3
+            {
1458e3
+                SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
1458e3
+                continue; // will be handled in CheckX509Data
1458e3
+            }
1458e3
+            OUString const issuerName(xCert->getIssuerName());
1458e3
+            OUString const serialNumber(xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()));
1458e3
+            auto const iter = std::find_if(rX509IssuerSerials.begin(), rX509IssuerSerials.end(),
1458e3
+                [&](auto const& rX509IssuerSerial) {
1458e3
+                    return xmlsecurity::EqualDistinguishedNames(issuerName, rX509IssuerSerial.first)
1458e3
+                        && serialNumber == rX509IssuerSerial.second;
1458e3
+                });
1458e3
+            if (iter != rX509IssuerSerials.end())
1458e3
+            {
1458e3
+                data.back().X509IssuerName = iter->first;
1458e3
+                data.back().X509SerialNumber = iter->second;
1458e3
+                rX509IssuerSerials.erase(iter);
1458e3
+            }
1458e3
+        }
1458e3
+        catch (uno::Exception const&)
1458e3
+        {
1458e3
+            SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
1458e3
+        }
1458e3
     }
1458e3
-    InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
1458e3
-    isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
1458e3
-}
1458e3
-
1458e3
-void XSecController::setX509Certificate( OUString const & ouX509Certificate )
1458e3
-{
1458e3
-    if (m_vInternalSignatureInformations.empty())
1458e3
+    // now handle any that are left...
1458e3
+    for (auto const& it : rX509IssuerSerials)
1458e3
     {
1458e3
-        SAL_INFO("xmlsecurity.helper","XSecController::setX509Certificate: no signature");
1458e3
-        return;
1458e3
+        data.emplace_back();
1458e3
+        data.back().X509IssuerName = it.first;
1458e3
+        data.back().X509SerialNumber = it.second;
1458e3
+    }
1458e3
+    if (!data.empty())
1458e3
+    {
1458e3
+        isi.signatureInfor.X509Datas.push_back(data);
1458e3
     }
1458e3
-    InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
1458e3
-    isi.signatureInfor.ouX509Certificate = ouX509Certificate;
1458e3
 }
1458e3
 
1458e3
 void XSecController::setSignatureValue( OUString const & ouSignatureValue )
1458e3
@@ -365,13 +410,67 @@ void XSecController::setSignatureBytes(const uno::Sequence<sal_Int8>& rBytes)
1458e3
     rInformation.signatureInfor.aSignatureBytes = rBytes;
1458e3
 }
1458e3
 
1458e3
-void XSecController::setCertDigest(const OUString& rCertDigest)
1458e3
+void XSecController::setX509CertDigest(
1458e3
+    OUString const& rCertDigest, sal_Int32 const /*TODO nReferenceDigestID*/,
1458e3
+    OUString const& rX509IssuerName, OUString const& rX509SerialNumber)
1458e3
 {
1458e3
     if (m_vInternalSignatureInformations.empty())
1458e3
         return;
1458e3
 
1458e3
     InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
1458e3
-    rInformation.signatureInfor.ouCertDigest = rCertDigest;
1458e3
+    for (auto & rData : rInformation.signatureInfor.X509Datas)
1458e3
+    {
1458e3
+        for (auto & it : rData)
1458e3
+        {
1458e3
+            if (xmlsecurity::EqualDistinguishedNames(it.X509IssuerName, rX509IssuerName)
1458e3
+                && it.X509SerialNumber == rX509SerialNumber)
1458e3
+            {
1458e3
+                it.CertDigest = rCertDigest;
1458e3
+                return;
1458e3
+            }
1458e3
+        }
1458e3
+    }
1458e3
+    // fall-back: read the actual certificates
1458e3
+    for (auto & rData : rInformation.signatureInfor.X509Datas)
1458e3
+    {
1458e3
+        for (auto & it : rData)
1458e3
+        {
1458e3
+            if (!it.X509Certificate.isEmpty())
1458e3
+            {
1458e3
+                try
1458e3
+                {
1458e3
+                    uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(m_xSecurityContext->getSecurityEnvironment());
1458e3
+                    uno::Reference<security::XCertificate> const xCert(xSecEnv->createCertificateFromAscii(it.X509Certificate));
1458e3
+                    if (!xCert.is())
1458e3
+                    {
1458e3
+                        SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
1458e3
+                    }
1458e3
+                    else if (xmlsecurity::EqualDistinguishedNames(xCert->getIssuerName(),rX509IssuerName)
1458e3
+                        && xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()) == rX509SerialNumber)
1458e3
+                    {
1458e3
+                        it.CertDigest = rCertDigest;
1458e3
+                        // note: testInsertCertificate_PEM_DOCX requires these!
1458e3
+                        it.X509SerialNumber = rX509SerialNumber;
1458e3
+                        it.X509IssuerName = rX509IssuerName;
1458e3
+                        return;
1458e3
+                    }
1458e3
+                }
1458e3
+                catch (uno::Exception const&)
1458e3
+                {
1458e3
+                    SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
1458e3
+                }
1458e3
+            }
1458e3
+        }
1458e3
+    }
1458e3
+    if (!rInformation.signatureInfor.ouGpgCertificate.isEmpty())
1458e3
+    {
1458e3
+        SAL_INFO_IF(rCertDigest != rInformation.signatureInfor.ouGpgKeyID,
1458e3
+            "xmlsecurity.helper", "PGPKeyID vs CertDigest mismatch");
1458e3
+    }
1458e3
+    else
1458e3
+    {
1458e3
+        SAL_INFO("xmlsecurity.helper", "cannot find X509Data for CertDigest");
1458e3
+    }
1458e3
 }
1458e3
 
1458e3
 namespace {
1458e3
diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
1458e3
index 0e619b2802f8..244cd46ac564 100644
1458e3
--- a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
1458e3
+++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
1458e3
@@ -26,6 +26,7 @@
1458e3
 #include <cppuhelper/supportsservice.hxx>
1458e3
 #include "x509certificate_mscryptimpl.hxx"
1458e3
 #include <certificateextension_xmlsecimpl.hxx>
1458e3
+#include <biginteger.hxx>
1458e3
 #include "sanextension_mscryptimpl.hxx"
1458e3
 
1458e3
 #include "oid.hxx"
1458e3
@@ -649,4 +650,50 @@ Sequence<OUString> SAL_CALL X509Certificate_MSCryptImpl::getSupportedServiceName
1458e3
     return { OUString() };
1458e3
 }
1458e3
 
1458e3
+namespace xmlsecurity {
1458e3
+
1458e3
+static bool EncodeDistinguishedName(OUString const& rName, CERT_NAME_BLOB & rBlob)
1458e3
+{
1458e3
+    LPCWSTR pszError;
1458e3
+    if (!CertStrToNameW(X509_ASN_ENCODING,
1458e3
+            reinterpret_cast<LPCWSTR>(rName.getStr()), CERT_X500_NAME_STR,
1458e3
+            nullptr, nullptr, &rBlob.cbData, &pszError))
1458e3
+    {
1458e3
+        SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << reinterpret_cast<char16_t const*>(pszError));
1458e3
+        return false;
1458e3
+    }
1458e3
+    rBlob.pbData = new BYTE[rBlob.cbData];
1458e3
+    if (!CertStrToNameW(X509_ASN_ENCODING,
1458e3
+            reinterpret_cast<LPCWSTR>(rName.getStr()), CERT_X500_NAME_STR,
1458e3
+            nullptr, rBlob.pbData, &rBlob.cbData, &pszError))
1458e3
+    {
1458e3
+        SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << reinterpret_cast<char16_t const*>(pszError));
1458e3
+        return false;
1458e3
+    }
1458e3
+    return true;
1458e3
+}
1458e3
+
1458e3
+bool EqualDistinguishedNames(
1458e3
+        OUString const& rName1, OUString const& rName2)
1458e3
+{
1458e3
+    CERT_NAME_BLOB blob1;
1458e3
+    if (!EncodeDistinguishedName(rName1, blob1))
1458e3
+    {
1458e3
+        return false;
1458e3
+    }
1458e3
+    CERT_NAME_BLOB blob2;
1458e3
+    if (!EncodeDistinguishedName(rName2, blob2))
1458e3
+    {
1458e3
+        delete[] blob1.pbData;
1458e3
+        return false;
1458e3
+    }
1458e3
+    bool const ret(CertCompareCertificateName(X509_ASN_ENCODING,
1458e3
+            &blob1, &blob2) == TRUE);
1458e3
+    delete[] blob2.pbData;
1458e3
+    delete[] blob1.pbData;
1458e3
+    return ret;
1458e3
+}
1458e3
+
1458e3
+} // namespace xmlsecurity
1458e3
+
1458e3
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1458e3
diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
1458e3
index a0acd81786d7..db400e6f1ed9 100644
1458e3
--- a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
1458e3
+++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
1458e3
@@ -18,6 +18,7 @@
1458e3
  */
1458e3
 
1458e3
 #include <sal/config.h>
1458e3
+#include <sal/log.hxx>
1458e3
 #include <rtl/uuid.h>
1458e3
 
1458e3
 #include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
1458e3
@@ -250,6 +251,7 @@ SAL_CALL XMLSignature_MSCryptImpl::validate(
1458e3
                  ++nReferenceGood;
1458e3
         }
1458e3
     }
1458e3
+    SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
1458e3
 
1458e3
     if (rs == 0 && nReferenceCount == nReferenceGood)
1458e3
     {
1458e3
diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
1458e3
index 1a323d33f32f..d6143a81883c 100644
1458e3
--- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
1458e3
+++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
1458e3
@@ -31,6 +31,7 @@
1458e3
 #include <rtl/ref.hxx>
1458e3
 #include "x509certificate_nssimpl.hxx"
1458e3
 
1458e3
+#include <biginteger.hxx>
1458e3
 #include <certificateextension_xmlsecimpl.hxx>
1458e3
 
1458e3
 #include "sanextension_nssimpl.hxx"
1458e3
@@ -533,4 +534,28 @@ sal_Bool SAL_CALL X509Certificate_NssImpl::supportsService(const OUString& servi
1458e3
 /* XServiceInfo */
1458e3
 Sequence<OUString> SAL_CALL X509Certificate_NssImpl::getSupportedServiceNames() { return { OUString() }; }
1458e3
 
1458e3
+namespace xmlsecurity {
1458e3
+
1458e3
+bool EqualDistinguishedNames(
1458e3
+        OUString const& rName1, OUString const& rName2)
1458e3
+{
1458e3
+    CERTName *const pName1(CERT_AsciiToName(OUStringToOString(rName1, RTL_TEXTENCODING_UTF8).getStr()));
1458e3
+    if (pName1 == nullptr)
1458e3
+    {
1458e3
+        return false;
1458e3
+    }
1458e3
+    CERTName *const pName2(CERT_AsciiToName(OUStringToOString(rName2, RTL_TEXTENCODING_UTF8).getStr()));
1458e3
+    if (pName2 == nullptr)
1458e3
+    {
1458e3
+        CERT_DestroyName(pName1);
1458e3
+        return false;
1458e3
+    }
1458e3
+    bool const ret(CERT_CompareName(pName1, pName2) == SECEqual);
1458e3
+    CERT_DestroyName(pName2);
1458e3
+    CERT_DestroyName(pName1);
1458e3
+    return ret;
1458e3
+}
1458e3
+
1458e3
+} // namespace xmlsecurity
1458e3
+
1458e3
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1458e3
diff --git a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
1458e3
index c39f6cc72f76..827580bcc7d7 100644
1458e3
--- a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
1458e3
+++ b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
1458e3
@@ -26,6 +26,8 @@
1458e3
 #include "securityenvironment_nssimpl.hxx"
1458e3
 
1458e3
 #include <xmlsec-wrapper.h>
1458e3
+#include <sal/log.hxx>
1458e3
+
1458e3
 #include <com/sun/star/xml/crypto/XXMLSignature.hpp>
1458e3
 #include <memory>
1458e3
 
1458e3
@@ -257,6 +259,7 @@ SAL_CALL XMLSignature_NssImpl::validate(
1458e3
                     ++nReferenceGood;
1458e3
             }
1458e3
         }
1458e3
+        SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
1458e3
 
1458e3
         if (rs == 0 && pDsigCtx->status == xmlSecDSigStatusSucceeded && nReferenceCount == nReferenceGood)
1458e3
         {
1458e3
-- 
1458e3
2.32.0
1458e3