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