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