include/sfx2/objsh.hxx                                                         
   |    2 
 include/xmloff/xmlimp.hxx                                                      
   |    6 
 include/xmloff/xmlnmspe.hxx                                                    
   |    7 
 include/xmloff/xmltoken.hxx                                                    
   |   13 
 xmloff/source/core/xmlimp.cxx                                                  
   |   26 
 xmloff/source/core/xmltoken.cxx                                                
   |   13 
 xmloff/source/token/tokens.txt                                                 
   |   10 
 xmlsecurity/inc/biginteger.hxx                                                 
   |    3 
 xmlsecurity/inc/sigstruct.hxx                                                  
   |   38 
 xmlsecurity/inc/xmlsignaturehelper.hxx                                         
   |   14 
 xmlsecurity/inc/xsecctl.hxx                                                    
   |   33 
 
xmlsecurity/qa/unit/signing/data/02_doc_macros_signed_by_attacker_manipulated.odt
 |binary
 xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated.odt     
   |binary
 xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated2.odt    
   |binary
 
xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated_triple.odt
 |binary
 xmlsecurity/qa/unit/signing/signing.cxx                                        
   |   89 
 xmlsecurity/source/component/documentdigitalsignatures.cxx                     
   |   59 
 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx                         
   |   16 
 xmlsecurity/source/helper/documentsignaturehelper.cxx                          
   |   63 
 xmlsecurity/source/helper/documentsignaturemanager.cxx                         
   |   12 
 xmlsecurity/source/helper/ooxmlsecexporter.cxx                                 
   |  218 -
 xmlsecurity/source/helper/ooxmlsecparser.cxx                                   
   |   26 
 xmlsecurity/source/helper/pdfsignaturehelper.cxx                               
   |    8 
 xmlsecurity/source/helper/xmlsignaturehelper.cxx                               
   |  162 
 xmlsecurity/source/helper/xsecctl.cxx                                          
   |   84 
 xmlsecurity/source/helper/xsecparser.cxx                                       
   | 1675 ++++++++--
 xmlsecurity/source/helper/xsecparser.hxx                                       
   |  101 
 xmlsecurity/source/helper/xsecsign.cxx                                         
   |   34 
 xmlsecurity/source/helper/xsecverify.cxx                                       
   |  195 -
 xmlsecurity/source/pdfio/pdfdocument.cxx                                       
   |   14 
 xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx          
   |    4 
 xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx              
   |   47 
 xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx                 
   |    2 
 xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx                      
   |   25 
 xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx                         
   |    5 
 35 files changed, 2414 insertions(+), 590 deletions(-)

New commits:
commit 5bfc7f7011aaf7f3ecce3f758425009e64b509c2
Author:     Caolán McNamara <[email protected]>
AuthorDate: Thu Mar 11 20:23:31 2021 +0000
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Tue Nov 23 09:34:53 2021 +0100

    do same set error state as ReadAndVerifySignature does
    
    this function is nearly exactly the same as ReadAndVerifySignature
    except it doesn't set error-state on exception during parse
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112366
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112412
    (cherry picked from commit 52a23d595b820cab27d76d0e7c129f2757c762d6)
    
    (cherry picked from commit ff80b0f3126506b4baac67ce67e224a7c3a68c8d)
    
    Conflicts:
            xmlsecurity/source/helper/xmlsignaturehelper.cxx
    
    Change-Id: Ife881f639a11d3185920ca62cc2cd22812fae36d

diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx 
b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
index 0986ac0dbbc2..2c5d624410ec 100644
--- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
@@ -421,6 +421,7 @@ bool 
XMLSignatureHelper::ReadAndVerifySignatureStorageStream(const css::uno::Ref
     catch(const uno::Exception& rException)
     {
         SAL_WARN("xmlsecurity.helper", 
"XMLSignatureHelper::ReadAndVerifySignatureStorageStream: " << 
rException.Message);
+        mbError = true;
     }
 
     mpXSecController->releaseSignatureReader();
commit dbd992fb50450c992c4a88a279d7e8371d6da690
Author:     Caolán McNamara <[email protected]>
AuthorDate: Mon Feb 8 17:05:28 2021 +0000
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Tue Nov 23 09:34:53 2021 +0100

    default to CertificateValidity::INVALID
    
    so if CertGetCertificateChain fails we don't want validity to be
    css::security::CertificateValidity::VALID which is what the old default
    of 0 equates to
    
    notably
    
    commit 1e0bc66d16aee28ce8bd9582ea32178c63841902
    Date:   Thu Nov 5 16:55:26 2009 +0100
    
        jl137:  #103420# better logging
    
    turned the nss equivalent of SecurityEnvironment_NssImpl::verifyCertificate
    from 0 to CertificateValidity::INVALID like this change does
    
    Change-Id: I5350dbc22d1b9b378da2976d3b0abd728f1f4c27
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110561
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <[email protected]>
    (cherry picked from commit edeb164c1d8ab64116afee4e2140403a362a1358)
    (cherry picked from commit a32e305bcdc7d47efa033da74309856deb41d37e)

diff --git 
a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx 
b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
index 55b732987d0f..75758d8f9ca3 100644
--- a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
+++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
@@ -800,7 +800,7 @@ sal_Int32 
SecurityEnvironment_MSCryptImpl::verifyCertificate(
     const Reference< css::security::XCertificate >& aCert,
     const Sequence< Reference< css::security::XCertificate > >& seqCerts)
 {
-    sal_Int32 validity = 0;
+    sal_Int32 validity = css::security::CertificateValidity::INVALID;
     PCCERT_CHAIN_CONTEXT pChainContext = nullptr;
     PCCERT_CONTEXT pCertContext = nullptr;
 
@@ -945,7 +945,7 @@ sal_Int32 
SecurityEnvironment_MSCryptImpl::verifyCertificate(
         }
         else
         {
-            SAL_INFO("xmlsecurity.xmlsec", "CertGetCertificateChaine failed.");
+            SAL_INFO("xmlsecurity.xmlsec", "CertGetCertificateChain failed.");
         }
     }
 
commit 8f0ddecac32e5ea5d49a46d8c7ad923ab1ed9a48
Author:     Michael Stahl <[email protected]>
AuthorDate: Fri Feb 26 17:29:37 2021 +0100
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Tue Nov 23 09:34:53 2021 +0100

    xmlsecurity: add tests for multiple X509Data/X509Certificate
    
    (cherry picked from commit 3c3299621628c11bf9f0f38e1259938b391c31e0)
    
    Conflicts:
            xmlsecurity/qa/unit/signing/signing.cxx
    
    (cherry picked from commit d81b142abfa17162f6f40b928a0b2b90ac897e2c)
    
    Conflicts:
            xmlsecurity/qa/unit/signing/signing.cxx
    
    Change-Id: If50ae8156f81c1053aa8fbfc3148da64bb8e1442

diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx
index 88ced5bce483..41fd1be00e19 100644
--- a/include/sfx2/objsh.hxx
+++ b/include/sfx2/objsh.hxx
@@ -743,7 +743,7 @@ public:
     // configuration items
     SAL_DLLPRIVATE SignatureState ImplGetSignatureState( bool 
bScriptingContent = false );
 
-    SAL_DLLPRIVATE css::uno::Sequence< 
css::security::DocumentSignatureInformation >
+    /*SAL_DLLPRIVATE*/ css::uno::Sequence< 
css::security::DocumentSignatureInformation >
         ImplAnalyzeSignature(
             bool bScriptingContent,
             const css::uno::Reference< 
css::security::XDocumentDigitalSignatures >& xSigner
diff --git 
a/xmlsecurity/qa/unit/signing/data/02_doc_macros_signed_by_attacker_manipulated.odt
 
b/xmlsecurity/qa/unit/signing/data/02_doc_macros_signed_by_attacker_manipulated.odt
new file mode 100644
index 000000000000..d63e4b6b7b72
Binary files /dev/null and 
b/xmlsecurity/qa/unit/signing/data/02_doc_macros_signed_by_attacker_manipulated.odt
 differ
diff --git 
a/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated.odt 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated.odt
new file mode 100644
index 000000000000..0190abb00f23
Binary files /dev/null and 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated.odt 
differ
diff --git 
a/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated2.odt 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated2.odt
new file mode 100644
index 000000000000..f4b4198f94a6
Binary files /dev/null and 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated2.odt 
differ
diff --git 
a/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated_triple.odt
 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated_triple.odt
new file mode 100644
index 000000000000..558bdee47e59
Binary files /dev/null and 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_attacker_manipulated_triple.odt
 differ
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index 2b6e60e7c0bd..b7f25c0a5258 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -25,6 +25,9 @@
 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
 #include <com/sun/star/io/TempFile.hpp>
 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
+#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
+#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
 
 #include <comphelper/processfactory.hxx>
 #include <sax/tools/converter.hxx>
@@ -72,6 +75,12 @@ public:
     void testODFBroken();
     /// Document has a signature stream, but no actual signatures.
     void testODFNo();
+
+    void testODFDoubleX509Data();
+    void testODFTripleX509Data();
+    void testODFMacroDoubleX509Data();
+    void testODFDoubleX509Certificate();
+
     /// Test a typical OOXML where a number of (but not all) streams are 
signed.
     void testOOXMLPartial();
     /// Test a typical broken OOXML signature where one stream is corrupted.
@@ -104,6 +113,10 @@ public:
     CPPUNIT_TEST(testODFBroken);
     CPPUNIT_TEST(testODFNo);
     CPPUNIT_TEST(testODFBroken);
+    CPPUNIT_TEST(testODFDoubleX509Data);
+    CPPUNIT_TEST(testODFTripleX509Data);
+    CPPUNIT_TEST(testODFMacroDoubleX509Data);
+    CPPUNIT_TEST(testODFDoubleX509Certificate);
     CPPUNIT_TEST(testOOXMLPartial);
     CPPUNIT_TEST(testOOXMLBroken);
     CPPUNIT_TEST(testOOXMLDescription);
@@ -400,6 +413,82 @@ void SigningTest::testODFNo()
     CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::NOSIGNATURES), 
static_cast<int>(pObjectShell->GetDocumentSignatureState()));
 }
 
+void SigningTest::testODFDoubleX509Data()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_signed_by_attacker_manipulated.odt");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    SignatureState nActual = pObjectShell->GetDocumentSignatureState();
+    CPPUNIT_ASSERT_MESSAGE(
+        
(OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
+        (nActual == SignatureState::NOTVALIDATED || nActual == 
SignatureState::OK));
+    uno::Sequence<security::DocumentSignatureInformation> const infos(
+        pObjectShell->ImplAnalyzeSignature(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
+void SigningTest::testODFTripleX509Data()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_signed_by_attacker_manipulated_triple.odt");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    SignatureState nActual = pObjectShell->GetDocumentSignatureState();
+    // here, libxmlsec will pick the 1st X509Data but signing key is the 2nd
+    
CPPUNIT_ASSERT_EQUAL_MESSAGE((OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
+                                 SignatureState::BROKEN, nActual);
+    uno::Sequence<security::DocumentSignatureInformation> const infos(
+        pObjectShell->ImplAnalyzeSignature(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
+void SigningTest::testODFMacroDoubleX509Data()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_macros_signed_by_attacker_manipulated.odt");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    SignatureState nActual = pObjectShell->GetScriptingSignatureState();
+    CPPUNIT_ASSERT_MESSAGE(
+        
(OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
+        (nActual == SignatureState::NOTVALIDATED || nActual == 
SignatureState::OK));
+    uno::Sequence<security::DocumentSignatureInformation> const infos(
+        pObjectShell->ImplAnalyzeSignature(true));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
+void SigningTest::testODFDoubleX509Certificate()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_signed_by_attacker_manipulated2.odt");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    SignatureState nActual = pObjectShell->GetDocumentSignatureState();
+    CPPUNIT_ASSERT_MESSAGE(
+        
(OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
+        (nActual == SignatureState::NOTVALIDATED || nActual == 
SignatureState::OK));
+    uno::Sequence<security::DocumentSignatureInformation> const infos(
+        pObjectShell->ImplAnalyzeSignature(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
 void SigningTest::testOOXMLPartial()
 {
     createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx");
commit 0c2a0f9b47a1711bc04e8f438db56fc7efdb90d0
Author:     Michael Stahl <[email protected]>
AuthorDate: Thu Feb 25 14:17:48 2021 +0100
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Tue Nov 23 09:34:52 2021 +0100

    xmlsecurity: improve handling of multiple X509Data elements
    
    Combine everything related to a certificate in a new struct X509Data.
    
    The CertDigest is not actually written in the X509Data element but in
    xades:Cert, so try to find the matching entry in
    XSecController::setX509CertDigest().
    
    There was a confusing interaction with PGP signatures, where ouGpgKeyID
    was used for import, but export wrote the value from ouCertDigest
    instead - this needed fixing.
    
    The main point of this is enforcing a constraint from xmldsig-core 4.5.4:
    
      All certificates appearing in an X509Data element MUST relate to the
      validation key by either containing it or being part of a certification
      chain that terminates in a certificate containing the validation key.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111254
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 9e82509b09f5fe2eb77bcdb8fd193c71923abb67)
    
    xmlsecurity: improve handling of multiple certificates per X509Data
    
    It turns out that an X509Data element can contain an arbitrary number of
    each of its child elements.
    
    How exactly certificates of an issuer chain may or should be distributed
    across multiple X509Data elements isn't terribly obvious.
    
    One thing that is clear is that any element that refers to or contains
    one particular certificate has to be a child of the same X509Data
    element, although in no particular order, so try to match the 2 such
    elements that the parser supports in XSecController::setX509Data().
    
    Presumably the only way it makes sense to have multiple signing
    certificates is if they all contain the same key but are signed by
    different CAs. This case isn't handled currently; CheckX509Data() will
    complain there's not a single chain and validation of the certificates
    will fail.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111500
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 5af5ea893bcb8a8eb472ac11133da10e5a604e66)
    
    xmlsecurity: add EqualDistinguishedNames()
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111545
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 1d3da3486d827dd5e7a3bf1c7a533f5aa9860e42)
    
    xmlsecurity: avoid exception in DigitalSignaturesDialog::getCertificate()
    
    Fallback to PGP if there's no X509 signing certificate because
    CheckX509Data() failed prevents the dialog from popping up.
    
    To avoid confusing the user in this situation, the dialog should
    show no certificate, which is already the case.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111664
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 90b725675c2964f4a151d802d9afedd8bc2ae1a7)
    
    xmlsecurity: fix crash in DocumentDigitalSignatures::isAuthorTrusted()
    
    If the argument is null.
    
    This function also should use EqualDistinguishedNames().
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111667
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit ca98e505cd69bf95d8ddb9387cf3f8e03ae4577d)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111910
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>
    (cherry picked from commit a1cf770c2d7ca3e153e0b1f01ddcc313bc2bed7f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113058
    Tested-by: Michael Stahl <[email protected]>
    Reviewed-by: Michael Stahl <[email protected]>
    
    (cherry picked from commit 8558bc8a0702bf41e020018f469b9feccd99f92d)
    
    Conflicts:
            include/svl/sigstruct.hxx
            xmlsecurity/inc/xmlsignaturehelper.hxx
            xmlsecurity/source/helper/pdfsignaturehelper.cxx
            xmlsecurity/source/helper/xsecparser.cxx
            xmlsecurity/source/helper/xsecsign.cxx
            xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
            xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
            xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
    
    (cherry picked from commit ed914263f07acabcea8681418d9d277d62e22ed5)
    
    Conflicts:
            include/svl/sigstruct.hxx
            svl/source/crypto/cryptosign.cxx
            sw/source/core/edit/edfcol.cxx
            xmlsecurity/inc/xsecctl.hxx
            xmlsecurity/source/component/documentdigitalsignatures.cxx
            xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
            xmlsecurity/source/helper/xmlsignaturehelper.cxx
            xmlsecurity/source/helper/xsecctl.cxx
            xmlsecurity/source/helper/xsecverify.cxx
            xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
            xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
    
    Change-Id: I9633a980b0c18d58dfce24fc59396a833498a77d

diff --git a/xmlsecurity/inc/biginteger.hxx b/xmlsecurity/inc/biginteger.hxx
index 2cd116d50763..b4bd3be07f7c 100644
--- a/xmlsecurity/inc/biginteger.hxx
+++ b/xmlsecurity/inc/biginteger.hxx
@@ -31,6 +31,9 @@ namespace xmlsecurity
 {
 XSECXMLSEC_DLLPUBLIC OUString bigIntegerToNumericString( const 
css::uno::Sequence< sal_Int8 >& serial );
 XSECXMLSEC_DLLPUBLIC css::uno::Sequence< sal_Int8 > numericStringToBigInteger 
( const OUString& serialNumber );
+
+XSECXMLSEC_DLLPUBLIC bool EqualDistinguishedNames(OUString const& rName1,
+                                                  OUString const& rName2);
 }
 
 #endif
diff --git a/xmlsecurity/inc/sigstruct.hxx b/xmlsecurity/inc/sigstruct.hxx
index 2b52dc3c0af0..d3f8ef2c68e6 100644
--- a/xmlsecurity/inc/sigstruct.hxx
+++ b/xmlsecurity/inc/sigstruct.hxx
@@ -72,9 +72,30 @@ struct SignatureInformation
     sal_Int32 nSecurityId;
     css::xml::crypto::SecurityOperationStatus nStatus;
     SignatureReferenceInformations  vSignatureReferenceInfors;
-    OUString ouX509IssuerName;
-    OUString ouX509SerialNumber;
-    OUString ouX509Certificate;
+    struct X509CertInfo
+    {
+        OUString X509IssuerName;
+        OUString X509SerialNumber;
+        OUString X509Certificate;
+        /// OOXML certificate SHA-256 digest, empty for ODF except when doing 
XAdES signature.
+        OUString CertDigest;
+        /// The certificate owner (aka subject).
+        OUString X509Subject;
+    };
+    typedef std::vector<X509CertInfo> X509Data;
+    // note: at parse time, it's unkown which one is the signing certificate;
+    // ImplVerifySignatures() figures it out and puts it at the back
+    std::vector<X509Data> X509Datas;
+
+    X509CertInfo const* GetSigningCertificate() const
+    {
+        if (X509Datas.empty())
+        {
+            return nullptr;
+        }
+        assert(!X509Datas.back().empty());
+        return & X509Datas.back().back();
+    }
 
     OUString ouGpgKeyID;
     OUString ouGpgCertificate;
@@ -101,14 +122,13 @@ struct SignatureInformation
     //and the converted time is written back, then the string looks different
     //and the signature is broken.
     OUString ouDateTime;
-
+    /// The Id attribute of the <SignatureProperty> element that contains the 
<dc:date>.
     OUString ouDateTimePropertyId;
     /// Characters of the <dc:description> element inside the signature.
     OUString ouDescription;
     /// The Id attribute of the <SignatureProperty> element that contains the 
<dc:description>.
     OUString ouDescriptionPropertyId;
-    /// OOXML certificate SHA-256 digest, empty for ODF except when doing 
XAdES signature.
-    OUString ouCertDigest;
+
     /// A full OOXML signature for unchanged roundtrip, empty for ODF.
     css::uno::Sequence<sal_Int8> aSignatureBytes;
     /// For PDF: digest format, from css::xml::crypto::DigestID
diff --git a/xmlsecurity/inc/xmlsignaturehelper.hxx 
b/xmlsecurity/inc/xmlsignaturehelper.hxx
index a473b1efd840..6c10108dccdd 100644
--- a/xmlsecurity/inc/xmlsignaturehelper.hxx
+++ b/xmlsecurity/inc/xmlsignaturehelper.hxx
@@ -36,6 +36,11 @@
 #include <com/sun/star/xml/crypto/sax/XSignatureCreationResultListener.hpp>
 #include <com/sun/star/xml/crypto/sax/XSignatureVerifyResultListener.hpp>
 
+#include <com/sun/star/security/XCertificate.hpp>
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+
+
+class DateTime;
 class Date;
 namespace tools { class Time; }
 
@@ -126,6 +131,15 @@ public:
                 // After signing/verifying, get information about signatures
     SignatureInformation  GetSignatureInformation( sal_Int32 nSecurityId ) 
const;
     SignatureInformations GetSignatureInformations() const;
+    /// ImplVerifySignature calls this to figure out which X509Data is the
+    /// signing certificate and update the internal state with the result.
+    /// @return
+    ///    A sequence with the signing certificate at the back on success.
+    ///    An empty sequence on failure.
+    std::vector<css::uno::Reference<css::security::XCertificate>>
+    CheckAndUpdateSignatureInformation(
+        css::uno::Reference<css::xml::crypto::XSecurityEnvironment> const& 
xSecEnv,
+        SignatureInformation const& rInfo);
 
                 // See XSecController for documentation
     void        StartMission(const 
css::uno::Reference<css::xml::crypto::XXMLSecurityContext>& xSecurityContext);
diff --git a/xmlsecurity/inc/xsecctl.hxx b/xmlsecurity/inc/xsecctl.hxx
index 8c6e916f1d31..b510afa60fa8 100644
--- a/xmlsecurity/inc/xsecctl.hxx
+++ b/xmlsecurity/inc/xsecctl.hxx
@@ -303,18 +303,21 @@ private:
         sal_Int32 nDigestID );
     void setReferenceCount() const;
 
-    void setX509IssuerName( OUString& ouX509IssuerName );
-    void setX509SerialNumber( OUString& ouX509SerialNumber );
-    void setX509Certificate( OUString& ouX509Certificate );
-    void setSignatureValue( OUString& ouSignatureValue );
-    void setDigestValue( sal_Int32 nDigestID, OUString& ouDigestValue );
-    void setGpgKeyID( OUString& ouKeyID );
-    void setGpgCertificate( OUString& ouGpgCert );
-    void setGpgOwner( OUString& ouGpgOwner );
+    void setX509Data(
+        std::vector<std::pair<OUString, OUString>> & rX509IssuerSerials,
+        std::vector<OUString> const& rX509Certificates);
+    void setX509CertDigest(
+        OUString const& rCertDigest, sal_Int32 const nReferenceDigestID,
+        OUString const& rX509IssuerName, OUString const& rX509SerialNumber);
+
+    void setSignatureValue( OUString const & ouSignatureValue );
+    void setDigestValue( sal_Int32 nDigestID, OUString const & ouDigestValue );
+    void setGpgKeyID( OUString const & ouKeyID );
+    void setGpgCertificate( OUString const & ouGpgCert );
+    void setGpgOwner( OUString const & ouGpgOwner );
 
     void setDate(OUString const& rId, OUString const& ouDate);
     void setDescription(OUString const& rId, OUString const& rDescription);
-    void setCertDigest(const OUString& rCertDigest);
 
 public:
     void setSignatureBytes(const css::uno::Sequence<sal_Int8>& rBytes);
@@ -347,6 +350,10 @@ public:
     SignatureInformation    getSignatureInformation( sal_Int32 nSecurityId ) 
const;
     SignatureInformations   getSignatureInformations() const;
 
+    /// only verify can figure out which X509Data is the signing certificate
+    void UpdateSignatureInformation(sal_Int32 nSecurityId,
+            std::vector<SignatureInformation::X509Data> const& rDatas);
+
     static void exportSignature(
         const css::uno::Reference< css::xml::sax::XDocumentHandler >& 
xDocumentHandler,
         const SignatureInformation& signatureInfo,
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx 
b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 6f235fd550ac..17b6c4ca4b08 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -43,6 +43,7 @@
 #include <unotools/securityoptions.hxx>
 #include <com/sun/star/security/CertificateValidity.hpp>
 #include <comphelper/documentconstants.hxx>
+#include <comphelper/sequence.hxx>
 #include <cppuhelper/supportsservice.hxx>
 #include <com/sun/star/lang/IllegalArgumentException.hpp>
 
@@ -327,31 +328,36 @@ DocumentDigitalSignatures::ImplVerifySignatures(
             const SignatureInformation& rInfo = aSignInfos[n];
             css::security::DocumentSignatureInformation& rSigInfo = arInfos[n];
 
-            if (rInfo.ouGpgCertificate.isEmpty()) // X.509
+            if (!rInfo.X509Datas.empty()) // X.509
             {
-                if (!rInfo.ouX509Certificate.isEmpty())
-                    rSigInfo.Signer = xSecEnv->createCertificateFromAscii( 
rInfo.ouX509Certificate ) ;
-                if (!rSigInfo.Signer.is())
-                    rSigInfo.Signer = xSecEnv->getCertificate( 
rInfo.ouX509IssuerName,
-                                                               
xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
-
-                // Verify certificate
-                //We have patched our version of libxmlsec, so that it does 
not verify the certificates. This has two
-                //reasons. First we want two separate status for signature and 
certificate. Second libxmlsec calls
-                //CERT_VerifyCertificate (Solaris, Linux) falsely, so that it 
always regards the certificate as valid.
-                //On Windows the checking of the certificate path is buggy. It 
does name matching (issuer, subject name)
-                //to find the parent certificate. It does not take into 
account that there can be several certificates
-                //with the same subject name.
-
-                try {
-                    rSigInfo.CertificateStatus = 
xSecEnv->verifyCertificate(rSigInfo.Signer,
-                                                                            
Sequence<Reference<css::security::XCertificate> >());
-                } catch (SecurityException& ) {
-                    OSL_FAIL("Verification of certificate failed");
+                std::vector<uno::Reference<security::XCertificate>> certs(
+                    rSignatureHelper.CheckAndUpdateSignatureInformation(
+                        xSecEnv, rInfo));
+                if (certs.empty())
+                {
                     rSigInfo.CertificateStatus = 
css::security::CertificateValidity::INVALID;
                 }
+                else
+                {
+                    rSigInfo.Signer = certs.back();
+                    // get only intermediates
+                    certs.pop_back();
+                // On Windows checking the certificate path is buggy. It does 
name matching (issuer, subject name)
+                // to find the parent certificate. It does not take into 
account that there can be several certificates
+                // with the same subject name.
+                    try
+                    {
+                        rSigInfo.CertificateStatus = 
xSecEnv->verifyCertificate(
+                            rSigInfo.Signer, 
comphelper::containerToSequence(certs));
+                    }
+                    catch (SecurityException&)
+                    {
+                        SAL_WARN("xmlsecurity.comp", "Verification of 
certificate failed");
+                        rSigInfo.CertificateStatus = 
css::security::CertificateValidity::INVALID;
+                    }
+                }
             }
-            else // GPG
+            else if (!rInfo.ouGpgCertificate.isEmpty() && xGpgSecEnv.is()) // 
GPG
             {
                 // TODO not ideal to retrieve cert by keyID, might
                 // collide, or PGPKeyID format might change - can't we
@@ -429,11 +435,15 @@ void DocumentDigitalSignatures::showCertificate(
 }
 
 sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
-    const Reference< css::security::XCertificate >& Author )
+    const Reference<css::security::XCertificate>& xAuthor)
 {
+    if (!xAuthor.is())
+    {
+        return false;
+    }
     bool bFound = false;
 
-    OUString sSerialNum = xmlsecurity::bigIntegerToNumericString( 
Author->getSerialNumber() );
+    OUString sSerialNum = 
xmlsecurity::bigIntegerToNumericString(xAuthor->getSerialNumber());
 
     Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = 
SvtSecurityOptions().GetTrustedAuthors();
     const SvtSecurityOptions::Certificate* pAuthors = 
aTrustedAuthors.getConstArray();
@@ -441,7 +451,8 @@ sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
     for ( ; pAuthors != pAuthorsEnd; ++pAuthors )
     {
         SvtSecurityOptions::Certificate aAuthor = *pAuthors;
-        if ( ( aAuthor[0] == Author->getIssuerName() ) && ( aAuthor[1] == 
sSerialNum ) )
+        if (xmlsecurity::EqualDistinguishedNames(aAuthor[0], 
xAuthor->getIssuerName())
+            && (aAuthor[1] == sSerialNum))
         {
             bFound = true;
             break;
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx 
b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
index 5a49151608d3..4fb076966a30 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -575,7 +575,7 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
                 if (!rInfo.ouGpgCertificate.isEmpty())
                     aType = "OpenPGP";
                 // XML based: XAdES or not.
-                else if (!rInfo.ouCertDigest.isEmpty())
+                else if (rInfo.GetSigningCertificate() && 
!rInfo.GetSigningCertificate()->CertDigest.isEmpty())
                     aType = "XAdES";
                 else
                     aType = "XML-DSig";
@@ -674,8 +674,8 @@ uno::Reference<security::XCertificate> 
DigitalSignaturesDialog::getCertificate(c
     uno::Reference<security::XCertificate> xCert;
 
     //First we try to get the certificate which is embedded in the XML 
Signature
-    if (!rInfo.ouX509Certificate.isEmpty())
-        xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
+    if (xSecEnv.is() && rInfo.GetSigningCertificate() && 
!rInfo.GetSigningCertificate()->X509Certificate.isEmpty())
+        xCert = 
xSecEnv->createCertificateFromAscii(rInfo.GetSigningCertificate()->X509Certificate);
     else {
         //There must be an embedded certificate because we use it to get the
         //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
@@ -687,9 +687,13 @@ uno::Reference<security::XCertificate> 
DigitalSignaturesDialog::getCertificate(c
     }
 
     //In case there is no embedded certificate we try to get it from a local 
store
-    if (!xCert.is())
-        xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, 
xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
-    if (!xCert.is())
+
+    if (!xCert.is() && xSecEnv.is() && rInfo.GetSigningCertificate())
+    {
+        xCert = 
xSecEnv->getCertificate(rInfo.GetSigningCertificate()->X509IssuerName,
+            
xmlsecurity::numericStringToBigInteger(rInfo.GetSigningCertificate()->X509SerialNumber));
+    }
+    if (!xCert.is() && xGpgSecEnv.is() && !rInfo.ouGpgKeyID.isEmpty())
         xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, 
xmlsecurity::numericStringToBigInteger("") );
 
     SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found 
and can't be created!" );
diff --git a/xmlsecurity/source/helper/documentsignaturehelper.cxx 
b/xmlsecurity/source/helper/documentsignaturehelper.cxx
index 9a2537ee828d..f4baae9fa7b5 100644
--- a/xmlsecurity/source/helper/documentsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx
@@ -552,6 +552,29 @@ void DocumentSignatureHelper::writeDigestMethod(
     xDocumentHandler->endElement("DigestMethod");
 }
 
+static void WriteXadesCert(
+    uno::Reference<xml::sax::XDocumentHandler> const& xDocumentHandler,
+    SignatureInformation::X509CertInfo const& rCertInfo)
+{
+    xDocumentHandler->startElement("xd:Cert", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    xDocumentHandler->startElement("xd:CertDigest", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    DocumentSignatureHelper::writeDigestMethod(xDocumentHandler);
+    xDocumentHandler->startElement("DigestValue", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    assert(!rCertInfo.CertDigest.isEmpty());
+    xDocumentHandler->characters(rCertInfo.CertDigest);
+    xDocumentHandler->endElement("DigestValue");
+    xDocumentHandler->endElement("xd:CertDigest");
+    xDocumentHandler->startElement("xd:IssuerSerial", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    xDocumentHandler->startElement("X509IssuerName", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    xDocumentHandler->characters(rCertInfo.X509IssuerName);
+    xDocumentHandler->endElement("X509IssuerName");
+    xDocumentHandler->startElement("X509SerialNumber", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    xDocumentHandler->characters(rCertInfo.X509SerialNumber);
+    xDocumentHandler->endElement("X509SerialNumber");
+    xDocumentHandler->endElement("xd:IssuerSerial");
+    xDocumentHandler->endElement("xd:Cert");
+}
+
 void DocumentSignatureHelper::writeSignedProperties(
     const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
     const SignatureInformation& signatureInfo,
@@ -568,26 +591,26 @@ void DocumentSignatureHelper::writeSignedProperties(
     xDocumentHandler->characters(sDate);
     xDocumentHandler->endElement("xd:SigningTime");
     xDocumentHandler->startElement("xd:SigningCertificate", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->startElement("xd:Cert", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->startElement("xd:CertDigest", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    writeDigestMethod(xDocumentHandler);
-
-    xDocumentHandler->startElement("DigestValue", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    // TODO: this is empty for gpg signatures currently
-    //assert(!signatureInfo.ouCertDigest.isEmpty());
-    xDocumentHandler->characters(signatureInfo.ouCertDigest);
-    xDocumentHandler->endElement("DigestValue");
-
-    xDocumentHandler->endElement("xd:CertDigest");
-    xDocumentHandler->startElement("xd:IssuerSerial", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->startElement("X509IssuerName", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters(signatureInfo.ouX509IssuerName);
-    xDocumentHandler->endElement("X509IssuerName");
-    xDocumentHandler->startElement("X509SerialNumber", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    xDocumentHandler->characters(signatureInfo.ouX509SerialNumber);
-    xDocumentHandler->endElement("X509SerialNumber");
-    xDocumentHandler->endElement("xd:IssuerSerial");
-    xDocumentHandler->endElement("xd:Cert");
+    assert(signatureInfo.GetSigningCertificate() || 
!signatureInfo.ouGpgKeyID.isEmpty());
+    if (signatureInfo.GetSigningCertificate())
+    {
+        // how should this deal with multiple X509Data elements?
+        // for now, let's write all of the certificates ...
+        for (auto const& rData : signatureInfo.X509Datas)
+        {
+            for (auto const& it : rData)
+            {
+                WriteXadesCert(xDocumentHandler, it);
+            }
+        }
+    }
+    else
+    {
+        // for PGP, write empty mandatory X509IssuerName, X509SerialNumber
+        SignatureInformation::X509CertInfo temp;
+        temp.CertDigest = signatureInfo.ouGpgKeyID;
+        WriteXadesCert(xDocumentHandler, temp);
+    }
     xDocumentHandler->endElement("xd:SigningCertificate");
     xDocumentHandler->startElement("xd:SignaturePolicyIdentifier", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
     xDocumentHandler->startElement("xd:SignaturePolicyImplied", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx 
b/xmlsecurity/source/helper/documentsignaturemanager.cxx
index 4718555d54c2..fa1ca7915d88 100644
--- a/xmlsecurity/source/helper/documentsignaturemanager.cxx
+++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx
@@ -496,6 +496,18 @@ void DocumentSignatureManager::read(bool bUseTempStream, 
bool bCacheLastSignatur
             
maSignatureHelper.ReadAndVerifySignatureStorage(aStreamHelper.xSignatureStorage,
 bCacheLastSignature);
         maSignatureHelper.EndMission();
 
+        // this parses the XML independently from ImplVerifySignatures() - 
check
+        // certificates here too ...
+        for (auto const& it : maSignatureHelper.GetSignatureInformations())
+        {
+            if (!it.X509Datas.empty())
+            {
+                uno::Reference<xml::crypto::XSecurityEnvironment> const 
xSecEnv(
+                    getSecurityEnvironment());
+                maSignatureHelper.CheckAndUpdateSignatureInformation(xSecEnv, 
it);
+            }
+        }
+
         maCurrentSignatureInformations = 
maSignatureHelper.GetSignatureInformations();
     }
     else
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx 
b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
index 336ab565c2eb..3d2f278feb94 100644
--- a/xmlsecurity/source/helper/ooxmlsecexporter.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
@@ -183,13 +183,21 @@ void OOXMLSecExporter::Impl::writeKeyInfo()
 {
     m_xDocumentHandler->startElement(
         "KeyInfo", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
-    m_xDocumentHandler->startElement(
-        "X509Data", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
-    m_xDocumentHandler->startElement(
-        "X509Certificate", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
-    m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
-    m_xDocumentHandler->endElement("X509Certificate");
-    m_xDocumentHandler->endElement("X509Data");
+    assert(m_rInformation.GetSigningCertificate());
+    for (auto const& rData : m_rInformation.X509Datas)
+    {
+        m_xDocumentHandler->startElement(
+            "X509Data", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
+        for (auto const& it : rData)
+        {
+            m_xDocumentHandler->startElement(
+                "X509Certificate",
+                uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
+            m_xDocumentHandler->characters(it.X509Certificate);
+            m_xDocumentHandler->endElement("X509Certificate");
+        }
+        m_xDocumentHandler->endElement("X509Data");
+    }
     m_xDocumentHandler->endElement("KeyInfo");
 }
 
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx 
b/xmlsecurity/source/helper/ooxmlsecparser.cxx
index 95d9d4767167..4181a207481b 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -146,9 +146,22 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& 
rName)
         m_pXSecController->setSignatureValue(m_aSignatureValue);
         m_bInSignatureValue = false;
     }
+    else if (rName == "X509Data")
+    {
+        std::vector<std::pair<OUString, OUString>> X509IssuerSerials;
+        std::vector<OUString> X509Certificates;
+        if (!m_aX509Certificate.isEmpty())
+        {
+            X509Certificates.emplace_back(m_aX509Certificate);
+        }
+        if (!m_aX509IssuerName.isEmpty() && !m_aX509SerialNumber.isEmpty())
+        {
+            X509IssuerSerials.emplace_back(m_aX509IssuerName, 
m_aX509SerialNumber);
+        }
+        m_pXSecController->setX509Data(X509IssuerSerials, X509Certificates);
+    }
     else if (rName == "X509Certificate")
     {
-        m_pXSecController->setX509Certificate(m_aX509Certificate);
         m_bInX509Certificate = false;
     }
     else if (rName == "mdssi:Value")
@@ -163,17 +176,18 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& 
rName)
     }
     else if (rName == "X509IssuerName")
     {
-        m_pXSecController->setX509IssuerName(m_aX509IssuerName);
         m_bInX509IssuerName = false;
     }
     else if (rName == "X509SerialNumber")
     {
-        m_pXSecController->setX509SerialNumber(m_aX509SerialNumber);
         m_bInX509SerialNumber = false;
     }
+    else if (rName == "xd:Cert")
+    {
+        m_pXSecController->setX509CertDigest(m_aCertDigest, 
css::xml::crypto::DigestID::SHA1, m_aX509IssuerName, m_aX509SerialNumber);
+    }
     else if (rName == "xd:CertDigest")
     {
-        m_pXSecController->setCertDigest(m_aCertDigest);
         m_bInCertDigest = false;
     }
 
diff --git a/xmlsecurity/source/helper/pdfsignaturehelper.cxx 
b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
index 9bb6e59d0380..ef78b8dc8a99 100644
--- a/xmlsecurity/source/helper/pdfsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
@@ -76,8 +76,12 @@ uno::Sequence<security::DocumentSignatureInformation> 
PDFSignatureHelper::GetDoc
         const SignatureInformation& rInternal = m_aSignatureInfos[i];
         security::DocumentSignatureInformation& rExternal = aRet[i];
         rExternal.SignatureIsValid = rInternal.nStatus == 
xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
-        if (!rInternal.ouX509Certificate.isEmpty())
-            rExternal.Signer = 
xSecEnv->createCertificateFromAscii(rInternal.ouX509Certificate);
+        if (rInternal.GetSigningCertificate()
+            && !rInternal.GetSigningCertificate()->X509Certificate.isEmpty())
+        {
+            rExternal.Signer = xSecEnv->createCertificateFromAscii(
+                rInternal.GetSigningCertificate()->X509Certificate);
+        }
         rExternal.PartialDocumentSignature = 
rInternal.bPartialDocumentSignature;
 
         // Verify certificate.
diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx 
b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
index 8cd1afd6e795..0986ac0dbbc2 100644
--- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
@@ -21,6 +21,7 @@
 #include <xmlsignaturehelper.hxx>
 #include <documentsignaturehelper.hxx>
 #include "xsecctl.hxx"
+#include <biginteger.hxx>
 
 #include "xmlsignaturehelper2.hxx"
 
@@ -49,6 +50,8 @@
 #include <comphelper/ofopxmlhelper.hxx>
 #include <comphelper/sequence.hxx>
 
+#include <boost/optional.hpp>
+
 #define NS_DOCUMENTSIGNATURES   "http://openoffice.org/2004/documentsignatures";
 #define NS_DOCUMENTSIGNATURES_ODF_1_2 
"urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0"
 #define OOXML_SIGNATURE_ORIGIN 
"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin";
@@ -576,4 +579,162 @@ bool 
XMLSignatureHelper::CreateAndWriteOOXMLSignature(const uno::Reference<embed
     return !mbError;
 }
 
+/** check this constraint from xmldsig-core 4.5.4:
+
+  All certificates appearing in an X509Data element MUST relate to the
+  validation key by either containing it or being part of a certification
+  chain that terminates in a certificate containing the validation key.
+ */
+static auto CheckX509Data(
+    uno::Reference<xml::crypto::XSecurityEnvironment> const& xSecEnv,
+    std::vector<SignatureInformation::X509CertInfo> const& rX509CertInfos,
+    std::vector<uno::Reference<security::XCertificate>> & rCerts,
+    std::vector<SignatureInformation::X509CertInfo> & rSorted) -> bool
+{
+    assert(rCerts.empty());
+    assert(rSorted.empty());
+    if (rX509CertInfos.empty())
+    {
+        SAL_WARN("xmlsecurity.comp", "no X509Data");
+        return false;
+    }
+    std::vector<uno::Reference<security::XCertificate>> certs;
+    for (SignatureInformation::X509CertInfo const& it : rX509CertInfos)
+    {
+        if (!it.X509Certificate.isEmpty())
+        {
+            
certs.emplace_back(xSecEnv->createCertificateFromAscii(it.X509Certificate));
+        }
+        else
+        {
+            certs.emplace_back(xSecEnv->getCertificate(
+                it.X509IssuerName,
+                xmlsecurity::numericStringToBigInteger(it.X509SerialNumber)));
+        }
+        if (!certs.back().is())
+        {
+            SAL_WARN("xmlsecurity.comp", "X509Data cannot be parsed");
+            return false;
+        }
+    }
+
+    // first, search one whose issuer isn't in the list, or a self-signed one
+    boost::optional<size_t> start;
+    for (size_t i = 0; i < certs.size(); ++i)
+    {
+        for (size_t j = 0; ; ++j)
+        {
+            if (j == certs.size())
+            {
+                if (start)
+                {
+                    SAL_WARN("xmlsecurity.comp", "X509Data do not form a 
chain: certificate has no issuer but already have start of chain: " << 
certs[i]->getSubjectName());
+                    return false;
+                }
+                start = i; // issuer isn't in the list
+                break;
+            }
+            if 
(xmlsecurity::EqualDistinguishedNames(certs[i]->getIssuerName(), 
certs[j]->getSubjectName()))
+            {
+                if (i == j) // self signed
+                {
+                    if (start)
+                    {
+                        SAL_WARN("xmlsecurity.comp", "X509Data do not form a 
chain: certificate is self-signed but already have start of chain: " << 
certs[i]->getSubjectName());
+                        return false;
+                    }
+                    start = i;
+                }
+                break;
+            }
+        }
+    }
+    std::vector<size_t> chain;
+    if (!start)
+    {
+        // this can only be a cycle?
+        SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: cycle 
detected");
+        return false;
+    }
+    chain.emplace_back(*start);
+
+    // second, check that there is a chain, no tree or cycle...
+    for (size_t i = 0; i < certs.size(); ++i)
+    {
+        assert(chain.size() == i + 1);
+        for (size_t j = 0; j < certs.size(); ++j)
+        {
+            if (chain[i] != j)
+            {
+                if (xmlsecurity::EqualDistinguishedNames(
+                        certs[chain[i]]->getSubjectName(), 
certs[j]->getIssuerName()))
+                {
+                    if (chain.size() != i + 1) // already found issuee?
+                    {
+                        SAL_WARN("xmlsecurity.comp", "X509Data do not form a 
chain: certificate issued 2 others: " << certs[chain[i]]->getSubjectName());
+                        return false;
+                    }
+                    chain.emplace_back(j);
+                }
+            }
+        }
+        if (i == certs.size() - 1)
+        {   // last one: must be a leaf
+            if (chain.size() != i + 1)
+            {
+                SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: 
certificate in cycle: " << certs[chain[i]]->getSubjectName());
+                return false;
+            }
+        }
+        else if (chain.size() != i + 2)
+        {   // not issuer of another?
+            SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: 
certificate issued 0 others: " << certs[chain[i]]->getSubjectName());
+            return false;
+        }
+    }
+
+    // success
+    assert(chain.size() == rX509CertInfos.size());
+    for (auto const& it : chain)
+    {
+        rSorted.emplace_back(rX509CertInfos[it]);
+        rCerts.emplace_back(certs[it]);
+    }
+    return true;
+}
+
+std::vector<uno::Reference<security::XCertificate>>
+XMLSignatureHelper::CheckAndUpdateSignatureInformation(
+    uno::Reference<xml::crypto::XSecurityEnvironment> const& xSecEnv,
+    SignatureInformation const& rInfo)
+{
+    // if the check fails, it's not possible to determine which X509Data
+    // contained the signing certificate - the UI cannot display something
+    // useful in this case, so prevent anything misleading by clearing the
+    // X509Datas.
+
+    std::vector<uno::Reference<security::XCertificate>> certs;
+    std::vector<SignatureInformation::X509Data> datas;
+    // TODO: for now, just merge all X509Datas together for checking...
+    // (this will probably break round-trip of signature with multiple 
X509Data,
+    // no idea if that is a problem)
+    SignatureInformation::X509Data temp;
+    SignatureInformation::X509Data tempResult;
+    for (auto const& rData : rInfo.X509Datas)
+    {
+        for (auto const& it : rData)
+        {
+            temp.emplace_back(it);
+        }
+    }
+    if (CheckX509Data(xSecEnv, temp, certs, tempResult))
+    {
+        datas.emplace_back(tempResult);
+    }
+
+    // rInfo is a copy, update the original
+    mpXSecController->UpdateSignatureInformation(rInfo.nSecurityId, datas);
+    return certs;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecctl.cxx 
b/xmlsecurity/source/helper/xsecctl.cxx
index ee5ec75c28fe..2d7bdfe3d7e6 100644
--- a/xmlsecurity/source/helper/xsecctl.cxx
+++ b/xmlsecurity/source/helper/xsecctl.cxx
@@ -738,7 +738,7 @@ void XSecController::exportSignature(
                     xDocumentHandler->startElement(
                         "PGPKeyID",
                         cssu::Reference< cssxs::XAttributeList > (new 
SvXMLAttributeList()));
-                    xDocumentHandler->characters( signatureInfo.ouCertDigest );
+                    xDocumentHandler->characters(signatureInfo.ouGpgKeyID);
                     xDocumentHandler->endElement( "PGPKeyID" );
 
                     /* Write PGPKeyPacket element */
@@ -762,43 +762,50 @@ void XSecController::exportSignature(
             }
             else
             {
-                /* Write X509Data element */
-                xDocumentHandler->startElement(
-                    "X509Data",
-                    cssu::Reference< cssxs::XAttributeList > (new 
SvXMLAttributeList()));
+                assert(signatureInfo.GetSigningCertificate());
+                for (auto const& rData : signatureInfo.X509Datas)
                 {
-                    /* Write X509IssuerSerial element */
+                    /* Write X509Data element */
                     xDocumentHandler->startElement(
-                        "X509IssuerSerial",
-                        cssu::Reference< cssxs::XAttributeList > (new 
SvXMLAttributeList()));
-                    {
-                        /* Write X509IssuerName element */
-                        xDocumentHandler->startElement(
-                            "X509IssuerName",
-                            cssu::Reference< cssxs::XAttributeList > (new 
SvXMLAttributeList()));
-                        xDocumentHandler->characters( 
signatureInfo.ouX509IssuerName );
-                        xDocumentHandler->endElement( "X509IssuerName" );
-
-                        /* Write X509SerialNumber element */
-                        xDocumentHandler->startElement(
-                            "X509SerialNumber",
-                            cssu::Reference< cssxs::XAttributeList > (new 
SvXMLAttributeList()));
-                        xDocumentHandler->characters( 
signatureInfo.ouX509SerialNumber );
-                        xDocumentHandler->endElement( "X509SerialNumber" );
-                    }
-                    xDocumentHandler->endElement( "X509IssuerSerial" );
-
-                    /* Write X509Certificate element */
-                    if (!signatureInfo.ouX509Certificate.isEmpty())
+                        "X509Data",
+                        css::uno::Reference< css::xml::sax::XAttributeList > 
(new SvXMLAttributeList()));
                     {
-                        xDocumentHandler->startElement(
-                            "X509Certificate",
-                            cssu::Reference< cssxs::XAttributeList > (new 
SvXMLAttributeList()));
-                        xDocumentHandler->characters( 
signatureInfo.ouX509Certificate );
-                        xDocumentHandler->endElement( "X509Certificate" );
+                        for (auto const& it : rData)
+                        {
+                            /* Write X509IssuerSerial element */
+                            xDocumentHandler->startElement(
+                                "X509IssuerSerial",
+                                css::uno::Reference< 
css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+                            {
+                                /* Write X509IssuerName element */
+                                xDocumentHandler->startElement(
+                                    "X509IssuerName",
+                                    css::uno::Reference< 
css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+                                
xDocumentHandler->characters(it.X509IssuerName);
+                                xDocumentHandler->endElement( "X509IssuerName" 
);
+
+                                /* Write X509SerialNumber element */
+                                xDocumentHandler->startElement(
+                                    "X509SerialNumber",
+                                    css::uno::Reference< 
css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+                                
xDocumentHandler->characters(it.X509SerialNumber);
+                                xDocumentHandler->endElement( 
"X509SerialNumber" );
+                            }
+                            xDocumentHandler->endElement( "X509IssuerSerial" );
+
+                            /* Write X509Certificate element */
+                            if (!it.X509Certificate.isEmpty())
+                            {
+                                xDocumentHandler->startElement(
+                                    "X509Certificate",
+                                    css::uno::Reference< 
css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+                                
xDocumentHandler->characters(it.X509Certificate);
+                                xDocumentHandler->endElement( 
"X509Certificate" );
+                            }
+                        }
                     }
+                    xDocumentHandler->endElement( "X509Data" );
                 }
-                xDocumentHandler->endElement( "X509Data" );
             }
         }
         xDocumentHandler->endElement( "KeyInfo" );
@@ -917,6 +924,15 @@ void XSecController::exportOOXMLSignature(const 
uno::Reference<embed::XStorage>&
     aExporter.writeSignature();
 }
 
+void XSecController::UpdateSignatureInformation(sal_Int32 const nSecurityId,
+    std::vector<SignatureInformation::X509Data> const& rDatas)
+{
+    SignatureInformation aInf( 0 );
+    int const nIndex = findSignatureInfor(nSecurityId);
+    assert(nIndex != -1); // nothing should touch this between parsing and 
verify
+    m_vInternalSignatureInformations[nIndex].signatureInfor.X509Datas = rDatas;
+}
+
 SignatureInformation XSecController::getSignatureInformation( sal_Int32 
nSecurityId ) const
 {
     SignatureInformation aInf( 0 );
diff --git a/xmlsecurity/source/helper/xsecparser.cxx 
b/xmlsecurity/source/helper/xsecparser.cxx
index abc5fa0e0471..16dc6827f9b6 100644
--- a/xmlsecurity/source/helper/xsecparser.cxx
+++ b/xmlsecurity/source/helper/xsecparser.cxx
@@ -248,98 +248,79 @@ class XSecParser::DsX509CertificateContext
     : public XSecParser::Context
 {
     private:
-        OUString m_Value;
+        OUString & m_rValue;
 
     public:
         DsX509CertificateContext(XSecParser & rParser,
-                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
             : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
         {
         }
 
-        virtual void EndElement() override
-        {
-            m_rParser.m_pXSecController->setX509Certificate(m_Value);
-        }
-
         virtual void Characters(OUString const& rChars) override
         {
-            m_Value += rChars;
+            m_rValue += rChars;
         }
 };
 
 class XSecParser::DsX509SerialNumberContext
-    : public XSecParser::ReferencedContextImpl
+    : public XSecParser::Context
 {
     private:
-        OUString m_Value;
+        OUString & m_rValue;
 
     public:
         DsX509SerialNumberContext(XSecParser & rParser,
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
-                bool const isReferenced)
-            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+                OUString & rValue)
+            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
         {
         }
 
-        virtual void EndElement() override
-        {
-            if (m_isReferenced)
-            {
-                m_rParser.m_pXSecController->setX509SerialNumber(m_Value);
-            }
-            else
-            {
-                SAL_INFO("xmlsecurity.helper", "ignoring unsigned 
X509SerialNumber");
-            }
-        }
-
         virtual void Characters(OUString const& rChars) override
         {
-            m_Value += rChars;
+            m_rValue += rChars;
         }
 };
 
 class XSecParser::DsX509IssuerNameContext
-    : public XSecParser::ReferencedContextImpl
+    : public XSecParser::Context
 {
     private:
-        OUString m_Value;
+        OUString & m_rValue;
 
     public:
         DsX509IssuerNameContext(XSecParser & rParser,
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
-                bool const isReferenced)
-            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+                OUString & rValue)
+            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
         {
         }
 
-        virtual void EndElement() override
-        {
-            if (m_isReferenced)
-            {
-                m_rParser.m_pXSecController->setX509IssuerName(m_Value);
-            }
-            else
-            {
-                SAL_INFO("xmlsecurity.helper", "ignoring unsigned 
X509IssuerName");
-            }
-        }
-
         virtual void Characters(OUString const& rChars) override
         {
-            m_Value += rChars;
+            m_rValue += rChars;
         }
 };
 
 class XSecParser::DsX509IssuerSerialContext
-    : public XSecParser::ReferencedContextImpl
+    : public XSecParser::Context
 {
+    private:
+        OUString & m_rX509IssuerName;
+        OUString & m_rX509SerialNumber;
+
     public:
         DsX509IssuerSerialContext(XSecParser & rParser,
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
-                bool const isReferenced)
-            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+                OUString & rIssuerName, OUString & rSerialNumber)
+            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rX509IssuerName(rIssuerName)
+            , m_rX509SerialNumber(rSerialNumber)
         {
         }
 
@@ -349,20 +330,27 @@ class XSecParser::DsX509IssuerSerialContext
         {
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerName")
             {
-                return o3tl::make_unique<DsX509IssuerNameContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+                return o3tl::make_unique<DsX509IssuerNameContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rX509IssuerName);
             }
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509SerialNumber")
             {
-                return o3tl::make_unique<DsX509SerialNumberContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+                return o3tl::make_unique<DsX509SerialNumberContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rX509SerialNumber);
             }
             // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
             return 
XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
         }
 };
 
+/// can't be sure what is supposed to happen here because the spec is clear as 
mud
 class XSecParser::DsX509DataContext
     : public XSecParser::Context
 {
+    private:
+        // sigh... "No ordering is implied by the above constraints."
+        // so store the ball of mud in vectors and try to figure it out later.
+        std::vector<std::pair<OUString, OUString>> m_X509IssuerSerials;
+        std::vector<OUString> m_X509Certificates;
+
     public:
         DsX509DataContext(XSecParser & rParser,
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
@@ -370,18 +358,25 @@ class XSecParser::DsX509DataContext
         {
         }
 
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setX509Data(m_X509IssuerSerials, 
m_X509Certificates);
+        }
+
         virtual std::unique_ptr<Context> CreateChildContext(
             std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
             sal_uInt16 const nNamespace, OUString const& rName) override
         {
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerSerial")
             {
-                // can't require KeyInfo to be signed so pass in *true*
-                return o3tl::make_unique<DsX509IssuerSerialContext>(m_rParser, 
std::move(pOldNamespaceMap), true);
+
+                m_X509IssuerSerials.emplace_back();
+                return o3tl::make_unique<DsX509IssuerSerialContext>(m_rParser, 
std::move(pOldNamespaceMap), m_X509IssuerSerials.back().first, 
m_X509IssuerSerials.back().second);
             }
             if (nNamespace == XML_NAMESPACE_DS && rName == "X509Certificate")
             {
-                return o3tl::make_unique<DsX509CertificateContext>(m_rParser, 
std::move(pOldNamespaceMap));
+                m_X509Certificates.emplace_back();
+                return o3tl::make_unique<DsX509CertificateContext>(m_rParser, 
std::move(pOldNamespaceMap), m_X509Certificates.back());
             }
             // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
             return 
XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
@@ -940,30 +935,20 @@ class XSecParser::LoSignatureLineContext
 };
 
 class XSecParser::XadesCertDigestContext
-    : public XSecParser::ReferencedContextImpl
+    : public XSecParser::Context
 {
     private:
-        OUString m_Value;
-        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+        OUString & m_rDigestValue;
+        sal_Int32 & m_rReferenceDigestID;
 
     public:
         XadesCertDigestContext(XSecParser & rParser,
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
-                bool const isReferenced)
-            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
-        {
-        }
-
-        virtual void EndElement() override
+                OUString & rDigestValue, sal_Int32 & rReferenceDigestID)
+            : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rDigestValue(rDigestValue)
+            , m_rReferenceDigestID(rReferenceDigestID)
         {
-            if (m_isReferenced)
-            {
-                m_rParser.m_pXSecController->setCertDigest(m_Value/* FIXME , 
m_nReferenceDigestID*/);
-            }
-            else
-            {
-                SAL_INFO("xmlsecurity.helper", "ignoring unsigned CertDigest");
-            }
         }
 
         virtual std::unique_ptr<Context> CreateChildContext(
@@ -972,11 +957,11 @@ class XSecParser::XadesCertDigestContext
         {
             if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
             {
-                return o3tl::make_unique<DsDigestMethodContext>(m_rParser, 
std::move(pOldNamespaceMap), m_nReferenceDigestID);
+                return o3tl::make_unique<DsDigestMethodContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rReferenceDigestID);
             }
             if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
             {
-                return o3tl::make_unique<DsDigestValueContext>(m_rParser, 
std::move(pOldNamespaceMap), m_Value);
+                return o3tl::make_unique<DsDigestValueContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rDigestValue);
             }
             return 
XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
         }
@@ -985,6 +970,12 @@ class XSecParser::XadesCertDigestContext
 class XSecParser::XadesCertContext
     : public XSecParser::ReferencedContextImpl
 {
+    private:
+        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+        OUString m_CertDigest;
+        OUString m_X509IssuerName;
+        OUString m_X509SerialNumber;
+
     public:
         XadesCertContext(XSecParser & rParser,
                 std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
@@ -993,17 +984,29 @@ class XSecParser::XadesCertContext
         {
         }
 
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                m_rParser.m_pXSecController->setX509CertDigest(m_CertDigest, 
m_nReferenceDigestID, m_X509IssuerName, m_X509SerialNumber);
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned xades:Cert");
+            }
+        }
+
         virtual std::unique_ptr<Context> CreateChildContext(
             std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
             sal_uInt16 const nNamespace, OUString const& rName) override
         {
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == "CertDigest")
             {
-                return o3tl::make_unique<XadesCertDigestContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+                return o3tl::make_unique<XadesCertDigestContext>(m_rParser, 
std::move(pOldNamespaceMap), m_CertDigest, m_nReferenceDigestID);
             }
             if (nNamespace == XML_NAMESPACE_XADES132 && rName == 
"IssuerSerial")
             {
-                return o3tl::make_unique<DsX509IssuerSerialContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+                return o3tl::make_unique<DsX509IssuerSerialContext>(m_rParser, 
std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber);
             }
             return 
XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
         }
diff --git a/xmlsecurity/source/helper/xsecsign.cxx 
b/xmlsecurity/source/helper/xsecsign.cxx
index 03b553846d46..e2be55a0623e 100644
--- a/xmlsecurity/source/helper/xsecsign.cxx
+++ b/xmlsecurity/source/helper/xsecsign.cxx
@@ -210,6 +210,7 @@ void XSecController::signAStream( sal_Int32 securityId, 
const OUString& uri, boo
     }
 }
 
+// note: this is called when creating a new signature from scratch
 void XSecController::setX509Certificate(
     sal_Int32 nSecurityId,
     const OUString& ouX509IssuerName,
@@ -222,26 +223,32 @@ void XSecController::setX509Certificate(
     if ( index == -1 )
     {
         InternalSignatureInformation isi(nSecurityId, nullptr);
-        isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
-        isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
-        isi.signatureInfor.ouX509Certificate = ouX509Cert;
-        isi.signatureInfor.ouCertDigest = ouX509CertDigest;
+        isi.signatureInfor.X509Datas.clear();
+        isi.signatureInfor.X509Datas.emplace_back();
+        isi.signatureInfor.X509Datas.back().emplace_back();
+        isi.signatureInfor.X509Datas.back().back().X509IssuerName = 
ouX509IssuerName;
+        isi.signatureInfor.X509Datas.back().back().X509SerialNumber = 
ouX509SerialNumber;
+        isi.signatureInfor.X509Datas.back().back().X509Certificate = 
ouX509Cert;
+        isi.signatureInfor.X509Datas.back().back().CertDigest = 
ouX509CertDigest;
         m_vInternalSignatureInformations.push_back( isi );
     }
     else
     {
         SignatureInformation &si
             = m_vInternalSignatureInformations[index].signatureInfor;
-        si.ouX509IssuerName = ouX509IssuerName;
-        si.ouX509SerialNumber = ouX509SerialNumber;
-        si.ouX509Certificate = ouX509Cert;
-        si.ouCertDigest = ouX509CertDigest;
+        si.X509Datas.clear();
+        si.X509Datas.emplace_back();
+        si.X509Datas.back().emplace_back();
+        si.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
+        si.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
+        si.X509Datas.back().back().X509Certificate = ouX509Cert;
+        si.X509Datas.back().back().CertDigest = ouX509CertDigest;
     }
 }
 
 void XSecController::setGpgCertificate(
         sal_Int32 nSecurityId,
-        const OUString& ouCertDigest,
+        const OUString& ouKeyDigest,
         const OUString& ouCert,
         const OUString& ouOwner)
 {
@@ -252,16 +259,17 @@ void XSecController::setGpgCertificate(
         InternalSignatureInformation isi(nSecurityId, nullptr);
         isi.signatureInfor.ouGpgCertificate = ouCert;
         isi.signatureInfor.ouGpgOwner = ouOwner;
-        isi.signatureInfor.ouCertDigest = ouCertDigest;
+        isi.signatureInfor.ouGpgKeyID = ouKeyDigest;
         m_vInternalSignatureInformations.push_back( isi );
     }
     else
     {
         SignatureInformation &si
             = m_vInternalSignatureInformations[index].signatureInfor;
+        si.X509Datas.clear(); // it is a PGP signature now
         si.ouGpgCertificate = ouCert;
         si.ouGpgOwner = ouOwner;
-        si.ouCertDigest = ouCertDigest;
+        si.ouGpgKeyID = ouKeyDigest;
     }
 }
 
diff --git a/xmlsecurity/source/helper/xsecverify.cxx 
b/xmlsecurity/source/helper/xsecverify.cxx
index 5c1ee3b42e1b..7da0e0ba1484 100644
--- a/xmlsecurity/source/helper/xsecverify.cxx
+++ b/xmlsecurity/source/helper/xsecverify.cxx
@@ -21,6 +21,7 @@
 #include "xsecctl.hxx"
 #include "xsecparser.hxx"
 #include "ooxmlsecparser.hxx"
+#include <biginteger.hxx>
 #include "framework/signatureverifierimpl.hxx"
 #include "framework/saxeventkeeperimpl.hxx"
 #include "gpg/xmlsignature_gpgimpl.hxx"
@@ -226,7 +227,9 @@ void XSecController::setReferenceCount() const
     }
 }
 
-void XSecController::setX509IssuerName( OUString& ouX509IssuerName )
+void XSecController::setX509Data(
+        std::vector<std::pair<OUString, OUString>> & rX509IssuerSerials,
+        std::vector<OUString> const& rX509Certificates)
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -234,32 +237,56 @@ void XSecController::setX509IssuerName( OUString& 
ouX509IssuerName )
         return;
     }
     InternalSignatureInformation &isi = 
m_vInternalSignatureInformations.back();
-    isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
-}
 
-void XSecController::setX509SerialNumber( OUString& ouX509SerialNumber )
-{
-    if (m_vInternalSignatureInformations.empty())
+    SignatureInformation::X509Data data;
+    // due to the excessive flexibility of the spec it's possible that there
+    // is both a reference to a cert and the cert itself in one X509Data
+    for (OUString const& it : rX509Certificates)
     {
-        SAL_INFO("xmlsecurity.helper","XSecController::setX509SerialNumber: no 
signature");
-        return;
+        try
+        {
+            data.emplace_back();
+            data.back().X509Certificate = it;
+            uno::Reference<xml::crypto::XSecurityEnvironment> const 
xSecEnv(m_xSecurityContext->getSecurityEnvironment());
+            uno::Reference<security::XCertificate> const 
xCert(xSecEnv->createCertificateFromAscii(it));
+            if (!xCert.is())
+            {
+                SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
+                continue; // will be handled in CheckX509Data
+            }
+            OUString const issuerName(xCert->getIssuerName());
+            OUString const 
serialNumber(xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()));
+            auto const iter = std::find_if(rX509IssuerSerials.begin(), 
rX509IssuerSerials.end(),
+                [&](std::pair<OUString, OUString> const& rX509IssuerSerial) {
+                    return xmlsecurity::EqualDistinguishedNames(issuerName, 
rX509IssuerSerial.first)
+                        && serialNumber == rX509IssuerSerial.second;
+                });
+            if (iter != rX509IssuerSerials.end())
+            {
+                data.back().X509IssuerName = iter->first;
+                data.back().X509SerialNumber = iter->second;
+                rX509IssuerSerials.erase(iter);
+            }
+        }
+        catch (uno::Exception const&)
+        {
+            SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
+        }
     }
-    InternalSignatureInformation &isi = 
m_vInternalSignatureInformations.back();
-    isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
-}
-
-void XSecController::setX509Certificate( OUString& ouX509Certificate )
-{
-    if (m_vInternalSignatureInformations.empty())
+    // now handle any that are left...
+    for (auto const& it : rX509IssuerSerials)
     {
-        SAL_INFO("xmlsecurity.helper","XSecController::setX509Certificate: no 
signature");
-        return;
+        data.emplace_back();
+        data.back().X509IssuerName = it.first;
+        data.back().X509SerialNumber = it.second;
+    }
+    if (!data.empty())
+    {
+        isi.signatureInfor.X509Datas.push_back(data);
     }
-    InternalSignatureInformation &isi = 
m_vInternalSignatureInformations.back();
-    isi.signatureInfor.ouX509Certificate = ouX509Certificate;
 }
 
-void XSecController::setSignatureValue( OUString& ouSignatureValue )
+void XSecController::setSignatureValue( OUString const & ouSignatureValue )
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -270,7 +297,7 @@ void XSecController::setSignatureValue( OUString& 
ouSignatureValue )
     isi.signatureInfor.ouSignatureValue = ouSignatureValue;
 }
 
-void XSecController::setDigestValue( sal_Int32 nDigestID, OUString& 
ouDigestValue )
+void XSecController::setDigestValue( sal_Int32 nDigestID, OUString const & 
ouDigestValue )
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -289,7 +316,7 @@ void XSecController::setDigestValue( sal_Int32 nDigestID, 
OUString& ouDigestValu
     reference.ouDigestValue = ouDigestValue;
 }
 
-void XSecController::setGpgKeyID( OUString& ouKeyID )
+void XSecController::setGpgKeyID( OUString const & ouKeyID )
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -300,7 +327,7 @@ void XSecController::setGpgKeyID( OUString& ouKeyID )
     isi.signatureInfor.ouGpgKeyID = ouKeyID;
 }
 
-void XSecController::setGpgCertificate( OUString& ouGpgCert )
+void XSecController::setGpgCertificate( OUString const & ouGpgCert )
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -311,7 +338,7 @@ void XSecController::setGpgCertificate( OUString& ouGpgCert 
)
     isi.signatureInfor.ouGpgCertificate = ouGpgCert;
 }
 
-void XSecController::setGpgOwner( OUString& ouGpgOwner )
+void XSecController::setGpgOwner( OUString const & ouGpgOwner )
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -366,13 +393,67 @@ void XSecController::setSignatureBytes(const 
uno::Sequence<sal_Int8>& rBytes)
     rInformation.signatureInfor.aSignatureBytes = rBytes;
 }
 
-void XSecController::setCertDigest(const OUString& rCertDigest)
+void XSecController::setX509CertDigest(
+    OUString const& rCertDigest, sal_Int32 const /*TODO nReferenceDigestID*/,
+    OUString const& rX509IssuerName, OUString const& rX509SerialNumber)
 {
     if (m_vInternalSignatureInformations.empty())
         return;
 
     InternalSignatureInformation& rInformation = 
m_vInternalSignatureInformations.back();
-    rInformation.signatureInfor.ouCertDigest = rCertDigest;
+    for (auto & rData : rInformation.signatureInfor.X509Datas)
+    {
+        for (auto & it : rData)
+        {
+            if (xmlsecurity::EqualDistinguishedNames(it.X509IssuerName, 
rX509IssuerName)
+                && it.X509SerialNumber == rX509SerialNumber)
+            {
+                it.CertDigest = rCertDigest;
+                return;
+            }
+        }
+    }
+    // fall-back: read the actual certificates
+    for (auto & rData : rInformation.signatureInfor.X509Datas)
+    {
+        for (auto & it : rData)
+        {
+            if (!it.X509Certificate.isEmpty())
+            {
+                try
+                {
+                    uno::Reference<xml::crypto::XSecurityEnvironment> const 
xSecEnv(m_xSecurityContext->getSecurityEnvironment());
+                    uno::Reference<security::XCertificate> const 
xCert(xSecEnv->createCertificateFromAscii(it.X509Certificate));
+                    if (!xCert.is())
+                    {
+                        SAL_INFO("xmlsecurity.helper", "cannot parse 
X509Certificate");
+                    }
+                    else if 
(xmlsecurity::EqualDistinguishedNames(xCert->getIssuerName(),rX509IssuerName)
+                        && 
xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()) == 
rX509SerialNumber)
+                    {
+                        it.CertDigest = rCertDigest;
+                        // note: testInsertCertificate_PEM_DOCX requires these!
+                        it.X509SerialNumber = rX509SerialNumber;
+                        it.X509IssuerName = rX509IssuerName;
+                        return;
+                    }
+                }
+                catch (uno::Exception const&)
+                {
+                    SAL_INFO("xmlsecurity.helper", "cannot parse 
X509Certificate");
+                }
+            }
+        }
+    }
+    if (!rInformation.signatureInfor.ouGpgCertificate.isEmpty())
+    {
+        SAL_INFO_IF(rCertDigest != rInformation.signatureInfor.ouGpgKeyID,
+            "xmlsecurity.helper", "PGPKeyID vs CertDigest mismatch");
+    }
+    else
+    {
+        SAL_INFO("xmlsecurity.helper", "cannot find X509Data for CertDigest");
+    }
 }
 
 void XSecController::addEncapsulatedX509Certificate(const OUString& 
rEncapsulatedX509Certificate)
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx 
b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 5420196df7d8..effc754f8ec7 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -553,7 +553,12 @@ bool ValidateSignature(SvStream& rStream, 
vcl::filter::PDFObjectElement* pSignat
             aDerCert[i] = pCertificate->derCert.data[i];
         OUStringBuffer aBuffer;
         sax::Converter::encodeBase64(aBuffer, aDerCert);
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
+        SignatureInformation::X509Data temp;
+        temp.emplace_back();
+        temp.back().X509Certificate = aBuffer.makeStringAndClear();
+        temp.back().X509Subject = OUString(pCertificate->subjectName, 
PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
+        rInformation.X509Datas.clear();
+        rInformation.X509Datas.emplace_back(temp);
     }
 
     PRTime nSigningTime;
@@ -755,7 +760,12 @@ bool ValidateSignature(SvStream& rStream, 
vcl::filter::PDFObjectElement* pSignat
             aDerCert[i] = pSignerCertContext->pbCertEncoded[i];
         OUStringBuffer aBuffer;
         sax::Converter::encodeBase64(aBuffer, aDerCert);
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
+        SignatureInformation::X509Data temp;
+        temp.emplace_back();
+        temp.back().X509Certificate = aBuffer.makeStringAndClear();
+        temp.back().X509Subject = GetSubjectName(pSignerCertContext);
+        rInformation.X509Datas.clear();
+        rInformation.X509Datas.emplace_back(temp);
     }
 
     if (bNonDetached)
diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx 
b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
index 35b3835a2afe..5852c7c32bb3 100644
--- a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
+++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
@@ -24,6 +24,7 @@
 #include <comphelper/windowserrorstring.hxx>
 #include "x509certificate_mscryptimpl.hxx"
 #include "certificateextension_xmlsecimpl.hxx"
+#include <biginteger.hxx>
 #include "sanextension_mscryptimpl.hxx"
 
 #include "oid.hxx"
@@ -658,4 +659,50 @@ sal_Int32 SAL_CALL 
X509Certificate_MSCryptImpl::getCertificateUsage(  )
     return usage;
 }
 
+namespace xmlsecurity {
+
+static bool EncodeDistinguishedName(OUString const& rName, CERT_NAME_BLOB & 
rBlob)
+{
+    LPCWSTR pszError;
+    if (!CertStrToNameW(X509_ASN_ENCODING,
+            reinterpret_cast<LPCWSTR>(rName.getStr()), CERT_X500_NAME_STR,
+            nullptr, nullptr, &rBlob.cbData, &pszError))
+    {
+        SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << 
WindowsErrorString(GetLastError()) << "; " << reinterpret_cast<char16_t 
const*>(pszError));
+        return false;
+    }
+    rBlob.pbData = new BYTE[rBlob.cbData];
+    if (!CertStrToNameW(X509_ASN_ENCODING,
+            reinterpret_cast<LPCWSTR>(rName.getStr()), CERT_X500_NAME_STR,
+            nullptr, rBlob.pbData, &rBlob.cbData, &pszError))
+    {
+        SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << 
WindowsErrorString(GetLastError()) << "; " << reinterpret_cast<char16_t 
const*>(pszError));
+        return false;
+    }
+    return true;
+}
+
+bool EqualDistinguishedNames(
+        OUString const& rName1, OUString const& rName2)
+{
+    CERT_NAME_BLOB blob1;
+    if (!EncodeDistinguishedName(rName1, blob1))
+    {
+        return false;
+    }
+    CERT_NAME_BLOB blob2;
+    if (!EncodeDistinguishedName(rName2, blob2))
+    {
+        delete[] blob1.pbData;
+        return false;
+    }
+    bool const ret(CertCompareCertificateName(X509_ASN_ENCODING,
+            &blob1, &blob2) == TRUE);
+    delete[] blob2.pbData;
+    delete[] blob1.pbData;
+    return ret;
+}
+
+} // namespace xmlsecurity
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx 
b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
index 08b4bf2ddc51..9751a21fe937 100644
--- a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
+++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
@@ -18,6 +18,7 @@
  */
 
 #include <sal/config.h>
+#include <sal/log.hxx>
 #include <rtl/uuid.h>
 
 #include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
@@ -224,6 +225,7 @@ SAL_CALL XMLSignature_MSCryptImpl::validate(
                  ++nReferenceGood;
         }
     }
+    SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << 
pDsigCtx->status << ", references good " << nReferenceGood << " of " << 
nReferenceCount);
 
     if (rs == 0 && nReferenceCount == nReferenceGood)
     {
diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx 
b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
index 079be582e02b..245dfe29887a 100644
--- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
+++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
@@ -31,6 +31,7 @@
 #include <rtl/ref.hxx>
 #include "x509certificate_nssimpl.hxx"
 
+#include <biginteger.hxx>
 #include "certificateextension_xmlsecimpl.hxx"
 
 #include "sanextension_nssimpl.hxx"
@@ -492,4 +493,28 @@ sal_Int32 SAL_CALL 
X509Certificate_NssImpl::getCertificateUsage(  )
     return usage;
 }
 
+namespace xmlsecurity {
+
+bool EqualDistinguishedNames(
+        OUString const& rName1, OUString const& rName2)
+{
+    CERTName *const pName1(CERT_AsciiToName(OUStringToOString(rName1, 
RTL_TEXTENCODING_UTF8).getStr()));
+    if (pName1 == nullptr)
+    {
+        return false;
+    }
+    CERTName *const pName2(CERT_AsciiToName(OUStringToOString(rName2, 
RTL_TEXTENCODING_UTF8).getStr()));
+    if (pName2 == nullptr)
+    {
+        CERT_DestroyName(pName1);
+        return false;
+    }
+    bool const ret(CERT_CompareName(pName1, pName2) == SECEqual);
+    CERT_DestroyName(pName2);
+    CERT_DestroyName(pName1);
+    return ret;
+}
+
+} // namespace xmlsecurity
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx 
b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
index a78ff38695ef..a5ee64b16e88 100644
--- a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
+++ b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
@@ -32,6 +32,10 @@
 
 #include "xmlsec-wrapper.h"
 
+#include <sal/log.hxx>
+
+#include <com/sun/star/xml/crypto/XXMLSignature.hpp>
+
 using namespace ::com::sun::star::uno ;
 using namespace ::com::sun::star::lang ;
 using ::com::sun::star::lang::XMultiServiceFactory ;
@@ -239,6 +243,7 @@ SAL_CALL XMLSignature_NssImpl::validate(
                     ++nReferenceGood;
             }
         }
+        SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << 
pDsigCtx->status << ", references good " << nReferenceGood << " of " << 
nReferenceCount);
 
         if (rs == 0 && pDsigCtx->status == xmlSecDSigStatusSucceeded && 
nReferenceCount == nReferenceGood)
         {
commit ba5789d1b23681d63d8fc83d43ce8a65761c4ea4
Author:     Michael Stahl <[email protected]>
AuthorDate: Wed Mar 24 17:21:53 2021 +0100
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Tue Nov 23 09:34:52 2021 +0100

    clang-format ooxmlsecexporter.cxx
    
    (cherry picked from commit 0559f8ee41d9f6d6fff342cdcaf878c769c48161)
    
    Conflicts:
            xmlsecurity/source/helper/ooxmlsecexporter.cxx
    
    Change-Id: I3faa33c98ec56197a1528f443c3850c70e171c4b
    (cherry picked from commit 4c9ff57c34dcfc4decf6a6053b5c0f91ce49c97e)

diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx 
b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
index 8b50019d5c92..336ab565c2eb 100644
--- a/xmlsecurity/source/helper/ooxmlsecexporter.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
@@ -73,25 +73,20 @@ struct OOXMLSecExporter::Impl
 
 bool OOXMLSecExporter::Impl::isOOXMLBlacklist(const OUString& rStreamName)
 {
-    static const std::initializer_list<OUStringLiteral> vBlacklist =
-    {
-        "/%5BContent_Types%5D.xml",
-        "/docProps/app.xml",
-        "/docProps/core.xml",
-        // Don't attempt to sign other signatures for now.
-        "/_xmlsignatures"
-    };
+    static const std::initializer_list<OUStringLiteral> vBlacklist
+        = { "/%5BContent_Types%5D.xml", "/docProps/app.xml", 
"/docProps/core.xml",
+            // Don't attempt to sign other signatures for now.
+            "/_xmlsignatures" };
     // Just check the prefix, as we don't care about the content type part of 
the stream name.
-    return std::find_if(vBlacklist.begin(), vBlacklist.end(), [&](const 
OUStringLiteral& rLiteral)
-    {
-        return rStreamName.startsWith(rLiteral);
-    }) != vBlacklist.end();
+    return std::find_if(
+               vBlacklist.begin(), vBlacklist.end(),
+               [&](const OUStringLiteral& rLiteral) { return 
rStreamName.startsWith(rLiteral); })
+           != vBlacklist.end();
 }
 
 bool OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(const OUString& 
rRelationName)
 {
-    static const std::initializer_list<OUStringLiteral> vBlacklist =
-    {
+    static const std::initializer_list<OUStringLiteral> vBlacklist = {
         
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";,
         
"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";,
         
"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin";
@@ -101,7 +96,8 @@ bool OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(const 
OUString& rRelationN
 
 void OOXMLSecExporter::Impl::writeSignedInfo()
 {
-    m_xDocumentHandler->startElement("SignedInfo", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "SignedInfo", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
 
     writeCanonicalizationMethod();
     writeSignatureMethod();
@@ -114,25 +110,26 @@ void OOXMLSecExporter::Impl::writeCanonicalizationMethod()
 {
     rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
     pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
-    m_xDocumentHandler->startElement("CanonicalizationMethod", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->startElement(
+        "CanonicalizationMethod", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
     m_xDocumentHandler->endElement("CanonicalizationMethod");
-
 }
 
 void OOXMLSecExporter::Impl::writeCanonicalizationTransform()
 {
     rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
     pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
-    m_xDocumentHandler->startElement("Transform", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->startElement(
+        "Transform", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
     m_xDocumentHandler->endElement("Transform");
-
 }
 
 void OOXMLSecExporter::Impl::writeSignatureMethod()
 {
     rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
     pAttributeList->AddAttribute("Algorithm", ALGO_RSASHA256);
-    m_xDocumentHandler->startElement("SignatureMethod", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->startElement(
+        "SignatureMethod", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
     m_xDocumentHandler->endElement("SignatureMethod");
 }
 
@@ -146,21 +143,27 @@ void OOXMLSecExporter::Impl::writeSignedInfoReferences()
             {
                 rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
                 if (rReference.ouURI != "idSignedProperties")
-                    pAttributeList->AddAttribute("Type", 
"http://www.w3.org/2000/09/xmldsig#Object";);
+                    pAttributeList->AddAttribute("Type",
+                                                 
"http://www.w3.org/2000/09/xmldsig#Object";);
                 else
-                    pAttributeList->AddAttribute("Type", 
"http://uri.etsi.org/01903#SignedProperties";);
+                    pAttributeList->AddAttribute("Type",
+                                                 
"http://uri.etsi.org/01903#SignedProperties";);
                 pAttributeList->AddAttribute("URI", "#" + rReference.ouURI);
-                m_xDocumentHandler->startElement("Reference", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+                m_xDocumentHandler->startElement(
+                    "Reference", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
             }
             if (rReference.ouURI == "idSignedProperties")
             {
-                m_xDocumentHandler->startElement("Transforms", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+                m_xDocumentHandler->startElement(
+                    "Transforms",
+                    uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
                 writeCanonicalizationTransform();
                 m_xDocumentHandler->endElement("Transforms");
             }
 
             DocumentSignatureHelper::writeDigestMethod(m_xDocumentHandler);
-            m_xDocumentHandler->startElement("DigestValue", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+            m_xDocumentHandler->startElement(
+                "DigestValue", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
             m_xDocumentHandler->characters(rReference.ouDigestValue);
             m_xDocumentHandler->endElement("DigestValue");
             m_xDocumentHandler->endElement("Reference");
@@ -170,16 +173,20 @@ void OOXMLSecExporter::Impl::writeSignedInfoReferences()
 
 void OOXMLSecExporter::Impl::writeSignatureValue()
 {
-    m_xDocumentHandler->startElement("SignatureValue", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "SignatureValue", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
     m_xDocumentHandler->characters(m_rInformation.ouSignatureValue);
     m_xDocumentHandler->endElement("SignatureValue");
 }
 
 void OOXMLSecExporter::Impl::writeKeyInfo()
 {
-    m_xDocumentHandler->startElement("KeyInfo", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    m_xDocumentHandler->startElement("X509Data", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
-    m_xDocumentHandler->startElement("X509Certificate", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "KeyInfo", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "X509Data", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "X509Certificate", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
     m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
     m_xDocumentHandler->endElement("X509Certificate");
     m_xDocumentHandler->endElement("X509Data");
@@ -190,7 +197,8 @@ void OOXMLSecExporter::Impl::writePackageObject()
 {
     rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
     pAttributeList->AddAttribute("Id", "idPackageObject");
-    m_xDocumentHandler->startElement("Object", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+    m_xDocumentHandler->startElement(
+        "Object", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
 
     writeManifest();
     writePackageObjectSignatureProperties();
@@ -200,7 +208,8 @@ void OOXMLSecExporter::Impl::writePackageObject()
 
 void OOXMLSecExporter::Impl::writeManifest()
 {
-    m_xDocumentHandler->startElement("Manifest", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "Manifest", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
     const SignatureReferenceInformations& rReferences = 
m_rInformation.vSignatureReferenceInfors;
     for (const SignatureReferenceInformation& rReference : rReferences)
     {
@@ -217,15 +226,22 @@ void OOXMLSecExporter::Impl::writeManifest()
 
 void OOXMLSecExporter::Impl::writeRelationshipTransform(const OUString& rURI)
 {
-    uno::Reference<embed::XHierarchicalStorageAccess> 
xHierarchicalStorageAccess(m_xRootStorage, uno::UNO_QUERY);
-    uno::Reference<io::XInputStream> 
xRelStream(xHierarchicalStorageAccess->openStreamElementByHierarchicalName(rURI,
 embed::ElementModes::READ), uno::UNO_QUERY);
+    uno::Reference<embed::XHierarchicalStorageAccess> 
xHierarchicalStorageAccess(m_xRootStorage,
+                                                                               
  uno::UNO_QUERY);
+    uno::Reference<io::XInputStream> xRelStream(
+        xHierarchicalStorageAccess->openStreamElementByHierarchicalName(rURI,
+                                                                        
embed::ElementModes::READ),
+        uno::UNO_QUERY);
     {
         rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
         pAttributeList->AddAttribute("Algorithm", ALGO_RELATIONSHIP);
-        m_xDocumentHandler->startElement("Transform", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+        m_xDocumentHandler->startElement(
+            "Transform", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
     }
 
-    uno::Sequence< uno::Sequence<beans::StringPair> > aRelationsInfo = 
comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, rURI, 
m_xComponentContext);
+    uno::Sequence<uno::Sequence<beans::StringPair>> aRelationsInfo
+        = comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, 
rURI,
+                                                               
m_xComponentContext);
     for (const uno::Sequence<beans::StringPair>& rPairs : aRelationsInfo)
     {
         OUString aId;
@@ -244,7 +260,9 @@ void 
OOXMLSecExporter::Impl::writeRelationshipTransform(const OUString& rURI)
         rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
         pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
         pAttributeList->AddAttribute("SourceId", aId);
-        m_xDocumentHandler->startElement("mdssi:RelationshipReference", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+        m_xDocumentHandler->startElement(
+            "mdssi:RelationshipReference",
+            uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
         m_xDocumentHandler->endElement("mdssi:RelationshipReference");
     }
 
@@ -253,23 +271,28 @@ void 
OOXMLSecExporter::Impl::writeRelationshipTransform(const OUString& rURI)
 
 void OOXMLSecExporter::Impl::writePackageObjectSignatureProperties()
 {
-    m_xDocumentHandler->startElement("SignatureProperties", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "SignatureProperties", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));
     {
         rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
         pAttributeList->AddAttribute("Id", "idSignatureTime");
         pAttributeList->AddAttribute("Target", "#idPackageSignature");
-        m_xDocumentHandler->startElement("SignatureProperty", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+        m_xDocumentHandler->startElement(
+            "SignatureProperty", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
     }
     {
         rtl::Reference<SvXMLAttributeList> pAttributeList(new 
SvXMLAttributeList());
         pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
-        m_xDocumentHandler->startElement("mdssi:SignatureTime", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+        m_xDocumentHandler->startElement(
+            "mdssi:SignatureTime", 
uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
     }
-    m_xDocumentHandler->startElement("mdssi:Format", 
uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+    m_xDocumentHandler->startElement(
+        "mdssi:Format", uno::Reference<xml::sax::XAttributeList>(new 
SvXMLAttributeList()));

... etc. - the rest is truncated

Reply via email to