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