RepositoryExternal.mk                                                          
   |    4 
 configure.ac                                                                   
   |    2 
 download.lst                                                                   
   |    4 
 external/curl/ExternalPackage_curl.mk                                          
   |    4 
 external/curl/ExternalProject_curl.mk                                          
   |    9 
 external/curl/curl-7.26.0_win-proxy.patch                                      
   |    2 
 external/curl/curl-msvc-disable-protocols.patch.1                              
   |    7 
 external/curl/zlib.patch.0                                                     
   |    4 
 external/liblangtag/UnpackedTarball_liblangtag.mk                              
   |    3 
 external/liblangtag/Wformat-overflow.patch                                     
   |   17 
 external/nss/ExternalProject_nss.mk                                            
   |    8 
 external/nss/nsinstall.py                                                      
   |   12 
 external/openssl/UnpackedTarball_openssl.mk                                    
   |    1 
 external/openssl/ccb0a11145ee72b042d10593a64eaf9e8a55ec12.patch.1              
   |   56 
 
external/xmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
 |   68 
 external/xmlsec/UnpackedTarball_xmlsec.mk                                      
   |    1 
 filter/source/graphicfilter/icgm/bitmap.cxx                                    
   |   10 
 include/svl/sigstruct.hxx                                                      
   |   42 
 include/vcl/BitmapTools.hxx                                                    
   |    3 
 include/xmloff/xmlimp.hxx                                                      
   |    6 
 include/xmloff/xmlnmspe.hxx                                                    
   |   10 
 include/xmloff/xmltoken.hxx                                                    
   |   13 
 libreofficekit/qa/gtktiledviewer/gtv-calc-header-bar.cxx                       
   |    5 
 lotuswordpro/qa/cppunit/data/pass/ofz20517-1.lwp                               
   |binary
 lotuswordpro/source/filter/lwprowlayout.cxx                                    
   |   11 
 lotuswordpro/source/filter/lwptablelayout.cxx                                  
   |    9 
 svl/source/crypto/cryptosign.cxx                                               
   |   16 
 sw/source/core/edit/edfcol.cxx                                                 
   |    3 
 sw/source/filter/basflt/fltshell.cxx                                           
   |    5 
 sw/source/filter/ww8/ww8scan.cxx                                               
   |   37 
 sw/source/filter/ww8/ww8scan.hxx                                               
   |    6 
 vcl/source/font/fontcharmap.cxx                                                
   |   18 
 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/xmlsignaturehelper.hxx                                         
   |   12 
 xmlsecurity/inc/xsecctl.hxx                                                    
   |   20 
 
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/data/02_doc_signed_by_trusted_person_manipulated.odt
  |binary
 xmlsecurity/qa/unit/signing/data/signed_with_x509certificate_chain.odt         
   |binary
 xmlsecurity/qa/unit/signing/signing.cxx                                        
   |  135 
 xmlsecurity/source/component/documentdigitalsignatures.cxx                     
   |   50 
 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx                         
   |   15 
 xmlsecurity/source/helper/documentsignaturehelper.cxx                          
   |   63 
 xmlsecurity/source/helper/documentsignaturemanager.cxx                         
   |   12 
 xmlsecurity/source/helper/ooxmlsecexporter.cxx                                 
   |   23 
 xmlsecurity/source/helper/ooxmlsecparser.cxx                                   
   | 1458 +++++++-
 xmlsecurity/source/helper/ooxmlsecparser.hxx                                   
   |   75 
 xmlsecurity/source/helper/pdfsignaturehelper.cxx                               
   |    8 
 xmlsecurity/source/helper/xmlsignaturehelper.cxx                               
   |  162 
 xmlsecurity/source/helper/xsecctl.cxx                                          
   |  194 -
 xmlsecurity/source/helper/xsecparser.cxx                                       
   | 1756 ++++++++--
 xmlsecurity/source/helper/xsecparser.hxx                                       
   |  106 
 xmlsecurity/source/helper/xsecsign.cxx                                         
   |   60 
 xmlsecurity/source/helper/xsecverify.cxx                                       
   |  227 -
 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                         
   |    4 
 64 files changed, 3969 insertions(+), 937 deletions(-)

New commits:
commit 0aeb55efca4a3218b8d0c63121fb19fc87ee22c9
Author:     Andras Timar <andras.ti...@collabora.com>
AuthorDate: Tue Oct 19 12:44:44 2021 +0200
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Oct 19 12:44:44 2021 +0200

    Bump version to 6.2-33
    
    Change-Id: I003658766ec3cdd56363092c11692c3ce159f9ff

diff --git a/configure.ac b/configure.ac
index c6375d63277b..f94fbac35304 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,7 +9,7 @@ dnl in order to create a configure script.
 # several non-alphanumeric characters, those are split off and used only for 
the
 # ABOUTBOXPRODUCTVERSIONSUFFIX in openoffice.lst. Why that is necessary, no 
idea.
 
-AC_INIT([Collabora Office],[6.2.10.32],[],[],[https://collaboraoffice.com/])
+AC_INIT([Collabora Office],[6.2.10.33],[],[],[https://collaboraoffice.com/])
 
 AC_PREREQ([2.59])
 
commit fb17ca759e838ab561a91418b178b3e6a53e079e
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Feb 26 17:29:37 2021 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Oct 19 12:44:05 2021 +0200

    xmlsecurity: add tests for multiple X509Data/X509Certificate
    
    Change-Id: If50ae8156f81c1053aa8fbfc3148da64bb8e1442

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/data/signed_with_x509certificate_chain.odt 
b/xmlsecurity/qa/unit/signing/data/signed_with_x509certificate_chain.odt
new file mode 100644
index 000000000000..5e519dd8b7e7
Binary files /dev/null and 
b/xmlsecurity/qa/unit/signing/data/signed_with_x509certificate_chain.odt differ
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index d908e2354626..729baf586312 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -24,6 +24,7 @@
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/frame/XStorable.hpp>
 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
 
@@ -81,6 +82,11 @@ public:
     /// Document has a signature stream, but no actual signatures.
     void testODFNo();
     void testODFUnsignedTimestamp();
+    void testODFX509CertificateChain();
+    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.
@@ -135,6 +141,11 @@ public:
     CPPUNIT_TEST(testODFNo);
     CPPUNIT_TEST(testODFBroken);
     CPPUNIT_TEST(testODFUnsignedTimestamp);
+    CPPUNIT_TEST(testODFX509CertificateChain);
+    CPPUNIT_TEST(testODFDoubleX509Data);
+    CPPUNIT_TEST(testODFTripleX509Data);
+    CPPUNIT_TEST(testODFMacroDoubleX509Data);
+    CPPUNIT_TEST(testODFDoubleX509Certificate);
     CPPUNIT_TEST(testOOXMLPartial);
     CPPUNIT_TEST(testOOXMLBroken);
     CPPUNIT_TEST(testOOXMLDescription);
@@ -659,6 +670,106 @@ void SigningTest::testODFUnsignedTimestamp()
     CPPUNIT_ASSERT_EQUAL(sal_Int32(18183742), infos[0].SignatureTime);
 }
 
+void SigningTest::testODFX509CertificateChain()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "signed_with_x509certificate_chain.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->GetDocumentSignatureInformation(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    // check that the signing certificate was picked, not one of the 2 CA ones
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::VALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(infos[0].Signer.is());
+    CPPUNIT_ASSERT_EQUAL(
+        OUString("CN=Xmlsecurity RSA Test example Alice,O=Xmlsecurity RSA 
Test,ST=England,C=UK"),
+        infos[0].Signer->getSubjectName());
+}
+
+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->GetDocumentSignatureInformation(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->GetDocumentSignatureInformation(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->GetDocumentSignatureInformation(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->GetDocumentSignatureInformation(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 cf18a7c0b321f92e059f0ef0cfe6f0b8dbc1d646
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Feb 26 17:24:10 2021 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Oct 19 12:44:00 2021 +0200

    xmlsecurity: add test for timestamps
    
    Change-Id: I6ce64ca7c59639684779144ed0ed8d36c4aca32b

diff --git 
a/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_trusted_person_manipulated.odt
 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_trusted_person_manipulated.odt
new file mode 100644
index 000000000000..4136b32e5610
Binary files /dev/null and 
b/xmlsecurity/qa/unit/signing/data/02_doc_signed_by_trusted_person_manipulated.odt
 differ
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index 5ed480ba819d..d908e2354626 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -80,6 +80,7 @@ public:
     void testODFBroken();
     /// Document has a signature stream, but no actual signatures.
     void testODFNo();
+    void testODFUnsignedTimestamp();
     /// 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.
@@ -133,6 +134,7 @@ public:
     CPPUNIT_TEST(testODFBroken);
     CPPUNIT_TEST(testODFNo);
     CPPUNIT_TEST(testODFBroken);
+    CPPUNIT_TEST(testODFUnsignedTimestamp);
     CPPUNIT_TEST(testOOXMLPartial);
     CPPUNIT_TEST(testOOXMLBroken);
     CPPUNIT_TEST(testOOXMLDescription);
@@ -635,6 +637,28 @@ void SigningTest::testODFNo()
                          
static_cast<int>(pObjectShell->GetDocumentSignatureState()));
 }
 
+// document has one signed timestamp and one unsigned timestamp
+void SigningTest::testODFUnsignedTimestamp()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_signed_by_trusted_person_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->GetDocumentSignatureInformation(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    // was: 66666666
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(20210126), infos[0].SignatureDate);
+    // was: 0
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(18183742), infos[0].SignatureTime);
+}
+
 void SigningTest::testOOXMLPartial()
 {
     createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx");
commit 8003f5f5319a726fde1dcacf96c64028c4d0d892
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Apr 7 17:00:43 2021 +0200
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Oct 19 12:43:54 2021 +0200

    xmlsec: fix signing documents on WNT
    
    Duplicate ds:X509Certificate elements cause:
    
warn:xmlsecurity.comp:9604:3820:xmlsecurity/source/helper/xmlsignaturehelper.cxx:658:
 X509Data do not form a chain: certificate in cycle:
    
    (regression from 5af5ea893bcb8a8eb472ac11133da10e5a604e66)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113746
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit ae08aa8a095832ae2a88eac14f9680ac8d3a13b6)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113752
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit 0ab3a264ba8d732cffa42a069c9aa50dab44e99f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113754
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    
    Change-Id: I3d319a2f74dbec17b73f1c7bb8f4efe4e335f0ac

diff --git 
a/external/xmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
 
b/external/xmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
new file mode 100644
index 000000000000..51607ca6ee73
--- /dev/null
+++ 
b/external/xmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
@@ -0,0 +1,68 @@
+From a39b110cb2c25680259a38b2f397b350151bc6e7 Mon Sep 17 00:00:00 2001
+From: Michael Stahl <michael.st...@allotropia.de>
+Date: Wed, 7 Apr 2021 16:43:48 +0200
+Subject: [PATCH] xmlSecX509DataGetNodeContent(): don't return 0 for non-empty
+ elements
+
+LibreOffice wants to write the content of KeyInfo itself and thus writes
+X509Certificate element with content.
+
+But then xmlSecMSCngKeyDataX509XmlWrite() writes a duplicate
+X509Certificate element, which then makes a new additional consistency
+check in LO unhappy.
+
+The duplicate is written because xmlSecX509DataGetNodeContent() returns
+0 because it only checks for empty nodes; if there are only non-empty
+nodes a fallback to XMLSEC_X509DATA_DEFAULT occurs in all backends.
+
+Change the return value to be non-0 without changing the signature of
+the function, as it is apparently public.
+
+This doesn't happen in LO in the NSS backend due to another accident,
+where the private key flag isn't set when the X509Certificate is read,
+but otherwise the code is the same.
+---
+ src/x509.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/x509.c b/src/x509.c
+index ed8788ae..dac8bd2b 100644
+--- a/src/x509.c
++++ b/src/x509.c
+@@ -60,22 +60,33 @@ xmlSecX509DataGetNodeContent (xmlNodePtr node, 
xmlSecKeyInfoCtxPtr keyInfoCtx) {
+         if(xmlSecCheckNodeName(cur, xmlSecNodeX509Certificate, xmlSecDSigNs)) 
{
+             if(xmlSecIsEmptyNode(cur) == 1) {
+                 content |= XMLSEC_X509DATA_CERTIFICATE_NODE;
++            } else {
++                /* ensure return value isn't 0 if there are non-empty 
elements */
++                content |= (XMLSEC_X509DATA_CERTIFICATE_NODE << 16);
+             }
+         } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, 
xmlSecDSigNs)) {
+             if(xmlSecIsEmptyNode(cur) == 1) {
+                 content |= XMLSEC_X509DATA_SUBJECTNAME_NODE;
++            } else {
++                content |= (XMLSEC_X509DATA_SUBJECTNAME_NODE << 16);
+             }
+         } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, 
xmlSecDSigNs)) {
+             if(xmlSecIsEmptyNode(cur) == 1) {
+                 content |= XMLSEC_X509DATA_ISSUERSERIAL_NODE;
++            } else {
++                content |= (XMLSEC_X509DATA_ISSUERSERIAL_NODE << 16);
+             }
+         } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) {
+             if(xmlSecIsEmptyNode(cur) == 1) {
+                 content |= XMLSEC_X509DATA_SKI_NODE;
++            } else {
++                content |= (XMLSEC_X509DATA_SKI_NODE << 16);
+             }
+         } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) {
+             if(xmlSecIsEmptyNode(cur) == 1) {
+                 content |= XMLSEC_X509DATA_CRL_NODE;
++            } else {
++                content |= (XMLSEC_X509DATA_CRL_NODE << 16);
+             }
+         } else {
+             /* todo: fail on unknown child node? */
+-- 
+2.30.2
+
diff --git a/external/xmlsec/UnpackedTarball_xmlsec.mk 
b/external/xmlsec/UnpackedTarball_xmlsec.mk
index 3ad978cdb829..c0591ddcea0d 100644
--- a/external/xmlsec/UnpackedTarball_xmlsec.mk
+++ b/external/xmlsec/UnpackedTarball_xmlsec.mk
@@ -8,6 +8,7 @@
 #
 
 xmlsec_patches :=
+xmlsec_patches += 
0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
 
 $(eval $(call gb_UnpackedTarball_UnpackedTarball,xmlsec))
 
commit d4c84edd0d7d9f371de6ef98e3017a89fb3476fb
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Mar 30 17:37:31 2021 +0200
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Oct 19 12:43:43 2021 +0200

    xmlsecurity: replace OOXMLSecParser implementation
    
    This is similar to 12b15be8f4f930a04d8056b9219ac969b42a9784 and following
    commits, but OOXMLSecParser has some differences to XSecParser, such as
    using a ds:Manifest, and requires a couple extra namespaces.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113381
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit cc1d19f7bbaefa5fb22ebd1344112755068b93c9)
    
    Change-Id: I56e39d9609db8fcad50ca1632ff482c1f0a30ff5

diff --git a/include/xmloff/xmlnmspe.hxx b/include/xmloff/xmlnmspe.hxx
index cc97a9c5aaa4..a7505a64190d 100644
--- a/include/xmloff/xmlnmspe.hxx
+++ b/include/xmloff/xmlnmspe.hxx
@@ -145,6 +145,9 @@ const sal_uInt16 XML_NAMESPACE_DSIG =            201;
 const sal_uInt16 XML_NAMESPACE_DS =              202;
 const sal_uInt16 XML_NAMESPACE_XADES132 =        203;
 const sal_uInt16 XML_NAMESPACE_XADES141 =        204;
+// OOXML digital signature extension namespaces, also based on xmldsig-core
+const sal_uInt16 XML_NAMESPACE_MDSSI =           205;
+const sal_uInt16 XML_NAMESPACE_MSODIGSIG =       206;
 
 #endif // INCLUDED_XMLOFF_XMLNMSPE_HXX
 
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx 
b/xmlsecurity/source/helper/ooxmlsecparser.cxx
index 5d1f67f7deb1..50fe150419a2 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -12,30 +12,1240 @@
 #include <xmlsignaturehelper.hxx>
 #include <sal/log.hxx>
 
+#include <xmloff/xmlnmspe.hxx>
+#include <xmloff/xmlimp.hxx>
+
+#include <com/sun/star/xml/sax/SAXException.hpp>
+
+#include <sal/log.hxx>
+
 using namespace com::sun::star;
 
+class OOXMLSecParser::Context
+{
+    protected:
+        friend class OOXMLSecParser;
+        OOXMLSecParser & m_rParser;
+    private:
+        std::unique_ptr<SvXMLNamespaceMap> m_pOldNamespaceMap;
+
+    public:
+        Context(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : m_rParser(rParser)
+            , m_pOldNamespaceMap(std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual ~Context() = default;
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& 
/*xAttrs*/)
+        {
+        }
+
+        virtual void EndElement()
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/);
+
+        virtual void Characters(OUString const& /*rChars*/)
+        {
+        }
+};
+
+// it's possible that an unsupported element has an Id attribute and a
+// ds:Reference digesting it - probably this means XSecController needs to know
+// about it. (For known elements, the Id attribute is only processed according
+// to the schema.)
+class OOXMLSecParser::UnknownContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        UnknownContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+};
+
+auto OOXMLSecParser::Context::CreateChildContext(
+    std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+    sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/)
+-> std::unique_ptr<Context>
+{
+    // default: create new base context
+    return std::make_unique<UnknownContext>(m_rParser, 
std::move(pOldNamespaceMap));
+}
+
+/**
+note: anything in ds:Object should be trusted *only* if there is a ds:Reference
+      to it so it is signed (exception: the xades:EncapsulatedX509Certificate).
+      ds:SignedInfo precedes all ds:Object.
+
+      There may be multiple ds:Signature for purpose of counter-signatures
+      but the way XAdES describes these, only the ds:SignatureValue element
+      would be referenced, so requiring a ds:Reference for anything in
+      ds:Object shouldn't cause issues.
+ */
+class OOXMLSecParser::ReferencedContextImpl
+    : public OOXMLSecParser::Context
+{
+    protected:
+        bool m_isReferenced;
+
+    public:
+        ReferencedContextImpl(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_isReferenced(isReferenced)
+        {
+        }
+
+        OUString 
CheckIdAttrReferenced(css::uno::Reference<css::xml::sax::XAttributeList> const& 
xAttrs)
+        {
+            OUString const id(m_rParser.HandleIdAttr(xAttrs));
+            if (!id.isEmpty() && 
m_rParser.m_pXSecController->haveReferenceForId(id))
+            {
+                m_isReferenced = true;
+            }
+            return id;
+        }
+};
+
+class OOXMLSecParser::DsX509CertificateContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsX509CertificateContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsX509SerialNumberContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsX509SerialNumberContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsX509IssuerNameContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsX509IssuerNameContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsX509IssuerSerialContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rX509IssuerName;
+        OUString & m_rX509SerialNumber;
+
+    public:
+        DsX509IssuerSerialContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rIssuerName, OUString & rSerialNumber)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rX509IssuerName(rIssuerName)
+            , m_rX509SerialNumber(rSerialNumber)
+        {
+        }
+
+        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 == "X509IssuerName")
+            {
+                return std::make_unique<DsX509IssuerNameContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rX509IssuerName);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "X509SerialNumber")
+            {
+                return std::make_unique<DsX509SerialNumberContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rX509SerialNumber);
+            }
+            // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
+            return 
OOXMLSecParser::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 OOXMLSecParser::DsX509DataContext
+    : public OOXMLSecParser::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(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        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")
+            {
+                m_X509IssuerSerials.emplace_back();
+                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, 
std::move(pOldNamespaceMap), m_X509IssuerSerials.back().first, 
m_X509IssuerSerials.back().second);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "X509Certificate")
+            {
+                m_X509Certificates.emplace_back();
+                return std::make_unique<DsX509CertificateContext>(m_rParser, 
std::move(pOldNamespaceMap), m_X509Certificates.back());
+            }
+            // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsKeyInfoContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsKeyInfoContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+
+        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 == "X509Data")
+            {
+                return std::make_unique<DsX509DataContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            // missing: ds:PGPData
+            // missing: ds:KeyName, ds:KeyValue, ds:RetrievalMethod, 
ds:SPKIData, ds:MgmtData
+            // (old code would read ds:Transform inside ds:RetrievalMethod but
+            // presumably that was a bug)
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+
+};
+
+class OOXMLSecParser::DsSignatureValueContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString m_Value;
+
+    public:
+        DsSignatureValueContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setSignatureValue(m_Value);
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_Value += rChars;
+        }
+};
+
+class OOXMLSecParser::DsDigestValueContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        DsDigestValueContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& 
/*xAttrs*/) override
+        {
+            m_rValue.clear();
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::DsDigestMethodContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        sal_Int32 & m_rReferenceDigestID;
+
+    public:
+        DsDigestMethodContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                sal_Int32 & rReferenceDigestID)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rReferenceDigestID(rReferenceDigestID)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            OUString ouAlgorithm = xAttrs->getValueByName("Algorithm");
+
+            SAL_WARN_IF( ouAlgorithm.isEmpty(), "xmlsecurity.helper", "no 
Algorithm in Reference" );
+            if (!ouAlgorithm.isEmpty())
+            {
+                SAL_WARN_IF( ouAlgorithm != ALGO_XMLDSIGSHA1
+                             && ouAlgorithm != ALGO_XMLDSIGSHA256
+                             && ouAlgorithm != ALGO_XMLDSIGSHA512,
+                             "xmlsecurity.helper", "Algorithm neither SHA1, 
SHA256 nor SHA512");
+                if (ouAlgorithm == ALGO_XMLDSIGSHA1)
+                    m_rReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+                else if (ouAlgorithm == ALGO_XMLDSIGSHA256)
+                    m_rReferenceDigestID = css::xml::crypto::DigestID::SHA256;
+                else if (ouAlgorithm == ALGO_XMLDSIGSHA512)
+                    m_rReferenceDigestID = css::xml::crypto::DigestID::SHA512;
+                else
+                    m_rReferenceDigestID = 0;
+            }
+        }
+};
+
+class OOXMLSecParser::DsTransformContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        bool & m_rIsC14N;
+
+    public:
+        DsTransformContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool & rIsC14N)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rIsC14N(rIsC14N)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            OUString aAlgorithm = xAttrs->getValueByName("Algorithm");
+
+            if (aAlgorithm == ALGO_RELATIONSHIP)
+            {
+                m_rIsC14N = true;
+            }
+        }
+};
+
+class OOXMLSecParser::DsTransformsContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        bool & m_rIsC14N;
+
+    public:
+        DsTransformsContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool & rIsC14N)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rIsC14N(rIsC14N)
+        {
+        }
+
+        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 == "Transform")
+            {
+                return std::make_unique<DsTransformContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rIsC14N);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsReferenceContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString m_URI;
+        OUString m_Type;
+        OUString m_DigestValue;
+        bool m_IsC14N = false;
+        // Relevant for ODF. The digest algorithm selected by the DigestMethod
+        // element's Algorithm attribute. @see css::xml::crypto::DigestID.
+        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA256;
+
+    public:
+        DsReferenceContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+
+            m_URI = xAttrs->getValueByName("URI");
+            SAL_WARN_IF(m_URI.isEmpty(), "xmlsecurity.helper", "URI is empty");
+            // Remember the type of this reference.
+            m_Type = xAttrs->getValueByName("Type");
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_URI.startsWith("#"))
+            {
+                /*
+                * remove the first character '#' from the attribute value
+                */
+                m_rParser.m_pXSecController->addReference(m_URI.copy(1), 
m_nReferenceDigestID, m_Type);
+            }
+            else
+            {
+                if (m_IsC14N) // this is determined by nested ds:Transform
+                {
+                    m_rParser.m_pXSecController->addStreamReference(m_URI, 
false, m_nReferenceDigestID);
+                }
+                else
+            /*
+            * it must be an octet stream
+            */
+                {
+                    m_rParser.m_pXSecController->addStreamReference(m_URI, 
true, m_nReferenceDigestID);
+                }
+            }
+
+            m_rParser.m_pXSecController->setDigestValue(m_nReferenceDigestID, 
m_DigestValue);
+        }
+
+        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 == "Transforms")
+            {
+                return std::make_unique<DsTransformsContext>(m_rParser, 
std::move(pOldNamespaceMap), m_IsC14N);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
+            {
+                return std::make_unique<DsDigestMethodContext>(m_rParser, 
std::move(pOldNamespaceMap), m_nReferenceDigestID);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
+            {
+                return std::make_unique<DsDigestValueContext>(m_rParser, 
std::move(pOldNamespaceMap), m_DigestValue);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsSignatureMethodContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsSignatureMethodContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            OUString ouAlgorithm = xAttrs->getValueByName("Algorithm");
+            if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == 
ALGO_ECDSASHA256
+                || ouAlgorithm == ALGO_ECDSASHA512)
+            {
+                
m_rParser.m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
+            }
+        }
+};
+
+class OOXMLSecParser::DsSignedInfoContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsSignedInfoContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            m_rParser.HandleIdAttr(xAttrs);
+        }
+
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setReferenceCount();
+        }
+
+        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 == "SignatureMethod")
+            {
+                return std::make_unique<DsSignatureMethodContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Reference")
+            {
+                return std::make_unique<DsReferenceContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            // missing: ds:CanonicalizationMethod
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesCertDigestContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rDigestValue;
+        sal_Int32 & m_rReferenceDigestID;
+
+    public:
+        XadesCertDigestContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rDigestValue, sal_Int32 & rReferenceDigestID)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rDigestValue(rDigestValue)
+            , m_rReferenceDigestID(rReferenceDigestID)
+        {
+        }
+
+        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 == "DigestMethod")
+            {
+                return std::make_unique<DsDigestMethodContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rReferenceDigestID);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
+            {
+                return std::make_unique<DsDigestValueContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rDigestValue);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesCertContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+        OUString m_CertDigest;
+        OUString m_X509IssuerName;
+        OUString m_X509SerialNumber;
+
+    public:
+        XadesCertContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        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 std::make_unique<XadesCertDigestContext>(m_rParser, 
std::move(pOldNamespaceMap), m_CertDigest, m_nReferenceDigestID);
+            }
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == 
"IssuerSerial")
+            {
+                return std::make_unique<DsX509IssuerSerialContext>(m_rParser, 
std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesSigningCertificateContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesSigningCertificateContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        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 == "Cert")
+            {
+                return std::make_unique<XadesCertContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesSigningTimeContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        OUString m_Value;
+
+    public:
+        XadesSigningTimeContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                m_rParser.m_pXSecController->setDate("", m_Value);
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned 
SigningTime");
+            }
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_Value += rChars;
+        }
+};
+
+class OOXMLSecParser::XadesSignedSignaturePropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesSignedSignaturePropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        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 == "SigningTime")
+            {
+                return std::make_unique<XadesSigningTimeContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == 
"SigningCertificate")
+            {
+                return 
std::make_unique<XadesSigningCertificateContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            // missing: xades:SignaturePolicyIdentifier, 
xades:SignatureProductionPlace, xades:SignerRole
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesSignedPropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesSignedPropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        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 == 
"SignedSignatureProperties")
+            {
+                return 
std::make_unique<XadesSignedSignaturePropertiesContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            // missing: xades:SignedDataObjectProperties
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::XadesQualifyingPropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        XadesQualifyingPropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        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 == 
"SignedProperties")
+            {
+                return 
std::make_unique<XadesSignedPropertiesContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            // missing: xades:UnsignedSignatureProperties
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::MsodigsigSetupIDContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MsodigsigSetupIDContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::MsodigsigSignatureCommentsContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MsodigsigSignatureCommentsContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::MsodigsigSignatureInfoV1Context
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        OUString m_SetupID;
+        OUString m_SignatureComments;
+
+    public:
+        MsodigsigSignatureInfoV1Context(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SetupID")
+            {
+                return std::make_unique<MsodigsigSetupIDContext>(m_rParser, 
std::move(pOldNamespaceMap), m_SetupID);
+            }
+            if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == 
"SignatureComments")
+            {
+                return 
std::make_unique<MsodigsigSignatureCommentsContext>(m_rParser, 
std::move(pOldNamespaceMap), m_SignatureComments);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                if (!m_SetupID.isEmpty())
+                {
+                    m_rParser.m_pXSecController->setSignatureLineId(m_SetupID);
+                }
+                if (!m_SignatureComments.isEmpty())
+                {
+                    m_rParser.m_pXSecController->setDescription("", 
m_SignatureComments);
+
+                }
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned 
SignatureInfoV1");
+            }
+        }
+};
+
+class OOXMLSecParser::MdssiValueContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MdssiValueContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_rValue += rChars;
+        }
+};
+
+class OOXMLSecParser::MdssiSignatureTimeContext
+    : public OOXMLSecParser::Context
+{
+    private:
+        OUString & m_rValue;
+
+    public:
+        MdssiSignatureTimeContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                OUString & rValue)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+            , m_rValue(rValue)
+        {
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_MDSSI && rName == "Value")
+            {
+                return std::make_unique<MdssiValueContext>(m_rParser, 
std::move(pOldNamespaceMap), m_rValue);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+
+class OOXMLSecParser::DsSignaturePropertyContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    private:
+        enum class SignatureProperty { Unknown, Date, Info };
+        SignatureProperty m_Property = SignatureProperty::Unknown;
+        OUString m_Id;
+        OUString m_Value;
+
+    public:
+        DsSignaturePropertyContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            m_Id = CheckIdAttrReferenced(xAttrs);
+        }
+
+        virtual void EndElement() override
+        {
+            if (m_isReferenced)
+            {
+                switch (m_Property)
+                {
+                    case SignatureProperty::Unknown:
+                        SAL_INFO("xmlsecurity.helper", "Unknown property in 
ds:Object ignored");
+                        break;
+                    case SignatureProperty::Info:
+                        break; // handled by child context
+                    case SignatureProperty::Date:
+                        m_rParser.m_pXSecController->setDate(m_Id, m_Value);
+                        break;
+                }
+            }
+            else
+            {
+                SAL_INFO("xmlsecurity.helper", "ignoring unsigned 
SignatureProperty");
+            }
+        }
+
+        virtual std::unique_ptr<Context> CreateChildContext(
+            std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+            sal_uInt16 const nNamespace, OUString const& rName) override
+        {
+            if (nNamespace == XML_NAMESPACE_MDSSI && rName == "SignatureTime")
+            {
+                m_Property = SignatureProperty::Date;
+                return std::make_unique<MdssiSignatureTimeContext>(m_rParser, 
std::move(pOldNamespaceMap), m_Value);
+            }
+            if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == 
"SignatureInfoV1")
+            {
+                return 
std::make_unique<MsodigsigSignatureInfoV1Context>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsSignaturePropertiesContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        DsSignaturePropertiesContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+        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 == "SignatureProperty")
+            {
+                return std::make_unique<DsSignaturePropertyContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsManifestContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+    public:
+        DsManifestContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+                bool const isReferenced)
+            : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), 
isReferenced)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            CheckIdAttrReferenced(xAttrs);
+        }
+
+#if 0
+        ???
+        virtual void EndElement() override
+        {
+            m_rParser.m_pXSecController->setReferenceCount();
+        }
+#endif
+
+        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 == "Reference")
+            {
+                return std::make_unique<DsReferenceContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            // missing: ds:CanonicalizationMethod
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsObjectContext
+    : public OOXMLSecParser::ReferencedContextImpl
+{
+        enum class Mode { Default, ValidSignatureLineImage, 
InvalidSignatureLineImage };
+        Mode m_Mode = Mode::Default;
+        OUString m_Value;
+
+    public:
+        DsObjectContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            // init with "false" here - the Signature element can't be 
referenced by its child
+            : OOXMLSecParser::ReferencedContextImpl(rParser, 
std::move(pOldNamespaceMap), false)
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            OUString const id(CheckIdAttrReferenced(xAttrs));
+            if (id == "idValidSigLnImg")
+            {
+                m_Mode = Mode::ValidSignatureLineImage;
+            }
+            else if (id == "idInvalidSigLnImg")
+            {
+                m_Mode = Mode::InvalidSignatureLineImage;
+            }
+        }
+
+        virtual void EndElement() override
+        {
+            switch (m_Mode)
+            {
+                case Mode::ValidSignatureLineImage:
+                    if (m_isReferenced)
+                    {
+                        
m_rParser.m_pXSecController->setValidSignatureImage(m_Value);
+                    }
+                    else
+                    {
+                        SAL_INFO("xmlsecurity.helper", "ignoring unsigned 
SignatureLineValidImage");
+                    }
+                    break;
+                case Mode::InvalidSignatureLineImage:
+                    if (m_isReferenced)
+                    {
+                        
m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value);
+                    }
+                    else
+                    {
+                        SAL_INFO("xmlsecurity.helper", "ignoring unsigned 
SignatureLineInvalidImage");
+                    }
+                    break;
+                case Mode::Default:
+                    break;
+            }
+        }
+
+        virtual void Characters(OUString const& rChars) override
+        {
+            m_Value += rChars;
+        }
+
+        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 == 
"SignatureProperties")
+            {
+                return 
std::make_unique<DsSignaturePropertiesContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            if (nNamespace == XML_NAMESPACE_XADES132 && rName == 
"QualifyingProperties")
+            {
+                return 
std::make_unique<XadesQualifyingPropertiesContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Manifest")
+            {
+                return std::make_unique<DsManifestContext>(m_rParser, 
std::move(pOldNamespaceMap), m_isReferenced);
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+class OOXMLSecParser::DsSignatureContext
+    : public OOXMLSecParser::Context
+{
+    public:
+        DsSignatureContext(OOXMLSecParser & rParser,
+                std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+            : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+        {
+        }
+
+        virtual void StartElement(
+            css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) 
override
+        {
+            OUString const ouIdAttr(m_rParser.HandleIdAttr(xAttrs));
+            m_rParser.m_rXMLSignatureHelper.StartVerifySignatureElement();
+            m_rParser.m_pXSecController->addSignature();
+            if (!ouIdAttr.isEmpty())
+            {
+                m_rParser.m_pXSecController->setId( ouIdAttr );
+            }
+        }
+
+        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 == "SignedInfo")
+            {
+                return std::make_unique<DsSignedInfoContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureValue")
+            {
+                return std::make_unique<DsSignatureValueContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "KeyInfo")
+            {
+                return std::make_unique<DsKeyInfoContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            if (nNamespace == XML_NAMESPACE_DS && rName == "Object")
+            {
+                return std::make_unique<DsObjectContext>(m_rParser, 
std::move(pOldNamespaceMap));
+            }
+            return 
OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), 
nNamespace, rName);
+        }
+};
+
+
 OOXMLSecParser::OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, 
XSecController* pXSecController)
-    : m_pXSecController(pXSecController)
-    ,m_bInDigestValue(false)
-    ,m_bInSignatureValue(false)
-    ,m_bInX509Certificate(false)
-    ,m_bInMdssiValue(false)
-    ,m_bInSignatureComments(false)
-    ,m_bInX509IssuerName(false)
-    ,m_bInX509SerialNumber(false)
-    ,m_bInCertDigest(false)
-    ,m_bInValidSignatureImage(false)
-    ,m_bInInvalidSignatureImage(false)
-    ,m_bInSignatureLineId(false)
-    ,m_bReferenceUnresolved(false)
+    : m_pNamespaceMap(new SvXMLNamespaceMap)
+    , m_pXSecController(pXSecController)
     ,m_rXMLSignatureHelper(rXMLSignatureHelper)
 {
+    using namespace xmloff::token;
+    m_pNamespaceMap->Add( GetXMLToken(XML_XML), GetXMLToken(XML_N_XML), 
XML_NAMESPACE_XML );
+    m_pNamespaceMap->Add( "_ds", GetXMLToken(XML_N_DS), XML_NAMESPACE_DS );
+    m_pNamespaceMap->Add( "_xades132", GetXMLToken(XML_N_XADES132), 
XML_NAMESPACE_XADES132);
+    m_pNamespaceMap->Add( "_xades141", GetXMLToken(XML_N_XADES141), 
XML_NAMESPACE_XADES141);
+    m_pNamespaceMap->Add( "_dc", GetXMLToken(XML_N_DC), XML_NAMESPACE_DC );
+    m_pNamespaceMap->Add( "_mdssi", NS_MDSSI, XML_NAMESPACE_MDSSI );
+    m_pNamespaceMap->Add( "_msodigsig", 
"http://schemas.microsoft.com/office/2006/digsig";, XML_NAMESPACE_MSODIGSIG );
+    m_pNamespaceMap->Add( "_office_libo",
+                         GetXMLToken(XML_N_LO_EXT), XML_NAMESPACE_LO_EXT);
 }
 
 OOXMLSecParser::~OOXMLSecParser()
 {
 }
 
+OUString 
OOXMLSecParser::HandleIdAttr(css::uno::Reference<css::xml::sax::XAttributeList> 
const& xAttrs)
+{
+    OUString const aId = xAttrs->getValueByName("Id");
+    if (!aId.isEmpty())
+    {
+        m_pXSecController->collectToVerify(aId);
+    }
+    return aId;
+}
+
 void SAL_CALL OOXMLSecParser::startDocument()
 {
     if (m_xNextHandler.is())
@@ -50,231 +1260,69 @@ void SAL_CALL OOXMLSecParser::endDocument()
 
 void SAL_CALL OOXMLSecParser::startElement(const OUString& rName, const 
uno::Reference<xml::sax::XAttributeList>& xAttribs)
 {
-    OUString aId = xAttribs->getValueByName("Id");
-    if (!aId.isEmpty())
-        m_pXSecController->collectToVerify(aId);
+    assert(m_pNamespaceMap);
+    std::unique_ptr<SvXMLNamespaceMap> pRewindMap(
+        SvXMLImport::processNSAttributes(m_pNamespaceMap, nullptr, xAttribs));
 
-    if (rName == "Signature")
-    {
-        m_rXMLSignatureHelper.StartVerifySignatureElement();
-        m_pXSecController->addSignature();
-        if (!aId.isEmpty())
-            m_pXSecController->setId(aId);
-    }
-    else if (rName == "SignatureMethod")
-    {
-        OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
-        if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256
-            || ouAlgorithm == ALGO_ECDSASHA512)
-            
m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
-    }
-    else if (rName == "Reference")
-    {
-        OUString aURI = xAttribs->getValueByName("URI");
-        if (aURI.startsWith("#"))
-            m_pXSecController->addReference(aURI.copy(1), 
xml::crypto::DigestID::SHA1, OUString());
-        else
-        {
-            m_aReferenceURI = aURI;
-            m_bReferenceUnresolved = true;
-        }
-    }
-    else if (rName == "Transform")
-    {
-        if (m_bReferenceUnresolved)
-        {
-            OUString aAlgorithm = xAttribs->getValueByName("Algorithm");
-            if (aAlgorithm == ALGO_RELATIONSHIP)
-            {
-                m_pXSecController->addStreamReference(m_aReferenceURI, 
/*isBinary=*/false, /*nDigestID=*/xml::crypto::DigestID::SHA256);
-                m_bReferenceUnresolved = false;
-            }
-        }
-    }
-    else if (rName == "DigestValue" && !m_bInCertDigest)
-    {
-        m_aDigestValue.clear();
-        m_bInDigestValue = true;
-    }
-    else if (rName == "SignatureValue")
-    {
-        m_aSignatureValue.clear();
-        m_bInSignatureValue = true;
-    }
-    else if (rName == "X509Certificate")
-    {
-        m_aX509Certificate.clear();
-        m_bInX509Certificate = true;
-    }
-    else if (rName == "mdssi:Value")
-    {
-        m_aMdssiValue.clear();
-        m_bInMdssiValue = true;
-    }
-    else if (rName == "SignatureComments")
-    {
-        m_aSignatureComments.clear();
-        m_bInSignatureComments = true;
-    }
-    else if (rName == "X509IssuerName")
-    {
-        m_aX509IssuerName.clear();
-        m_bInX509IssuerName = true;
-    }
-    else if (rName == "X509SerialNumber")
-    {
-        m_aX509SerialNumber.clear();
-        m_bInX509SerialNumber = true;
-    }
-    else if (rName == "xd:CertDigest")
-    {
-        m_aCertDigest.clear();
-        m_bInCertDigest = true;
-    }
-    else if (rName == "Object")
+    OUString localName;
+    sal_uInt16 const nPrefix(m_pNamespaceMap->GetKeyByAttrName(rName, 
&localName));
+
+    std::unique_ptr<Context> pContext;
+
+    if (m_ContextStack.empty())
     {
-        OUString sId = xAttribs->getValueByName("Id");
-        if (sId == "idValidSigLnImg")
-        {
-            m_aValidSignatureImage.clear();
-            m_bInValidSignatureImage = true;
-        }
-        else if (sId == "idInvalidSigLnImg")
+        if (nPrefix == XML_NAMESPACE_DS
+            && localName == "Signature")
         {
-            m_aInvalidSignatureImage.clear();
-            m_bInInvalidSignatureImage = true;
+            pContext.reset(new DsSignatureContext(*this, 
std::move(pRewindMap)));
         }
         else
         {
-            SAL_INFO("xmlsecurity.ooxml", "Unknown 'Object' child element: " 
<< rName);
+            throw css::xml::sax::SAXException(
+                "xmlsecurity: unexpected root element", nullptr,
+                css::uno::Any());
         }
     }
-    else if (rName == "SetupID")
-    {
-        m_aSignatureLineId.clear();
-        m_bInSignatureLineId = true;
-    }
     else
     {
-        SAL_INFO("xmlsecurity.ooxml", "Unknown xml element: " << rName);
+        pContext = m_ContextStack.top()->CreateChildContext(
+                std::move(pRewindMap), nPrefix, localName);
     }
 
+    m_ContextStack.push(std::move(pContext));
+    assert(!pRewindMap);
+
+    m_ContextStack.top()->StartElement(xAttribs);
+
     if (m_xNextHandler.is())
+    {
         m_xNextHandler->startElement(rName, xAttribs);
+    }
+
 }
 
 void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
 {
-    if (rName == "SignedInfo")
-        m_pXSecController->setReferenceCount();
-    else if (rName == "Reference")
-    {
-        if (m_bReferenceUnresolved)
-        {
-            // No transform algorithm found, assume binary.
-            m_pXSecController->addStreamReference(m_aReferenceURI, 
/*isBinary=*/true, /*nDigestID=*/xml::crypto::DigestID::SHA256);
-            m_bReferenceUnresolved = false;
-        }
-        m_pXSecController->setDigestValue(xml::crypto::DigestID::SHA256, 
m_aDigestValue);
-    }
-    else if (rName == "DigestValue" && !m_bInCertDigest)
-        m_bInDigestValue = false;
-    else if (rName == "SignatureValue")
-    {
-        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_bInX509Certificate = false;
-    }
-    else if (rName == "mdssi:Value")
-    {
-        m_pXSecController->setDate("", m_aMdssiValue);
-        m_bInMdssiValue = false;
-    }
-    else if (rName == "SignatureComments")
-    {
-        m_pXSecController->setDescription("", m_aSignatureComments);
-        m_bInSignatureComments = false;
-    }
-    else if (rName == "X509IssuerName")
-    {
-        m_bInX509IssuerName = false;
-    }
-    else if (rName == "X509SerialNumber")
-    {
-        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_bInCertDigest = false;
-    }
-    else if (rName == "Object")
+    assert(!m_ContextStack.empty()); // this should be checked by sax parser?
+
+    m_ContextStack.top()->EndElement();
+
+    if (m_xNextHandler.is())
     {
-        if (m_bInValidSignatureImage)
-        {
-            m_pXSecController->setValidSignatureImage(m_aValidSignatureImage);
-            m_bInValidSignatureImage = false;
-        }
-        else if (m_bInInvalidSignatureImage)
-        {
-            
m_pXSecController->setInvalidSignatureImage(m_aInvalidSignatureImage);
-            m_bInInvalidSignatureImage = false;
-        }
+        m_xNextHandler->endElement(rName);
     }
-    else if (rName == "SetupID")
+
+    if (m_ContextStack.top()->m_pOldNamespaceMap)
     {
-        m_pXSecController->setSignatureLineId(m_aSignatureLineId);
-        m_bInSignatureLineId = false;
+        m_pNamespaceMap = std::move(m_ContextStack.top()->m_pOldNamespaceMap);
     }
-
-    if (m_xNextHandler.is())
-        m_xNextHandler->endElement(rName);
+    m_ContextStack.pop();
 }
 
 void SAL_CALL OOXMLSecParser::characters(const OUString& rChars)
 {
-    if (m_bInDigestValue && !m_bInCertDigest)
-        m_aDigestValue += rChars;
-    else if (m_bInSignatureValue)
-        m_aSignatureValue += rChars;
-    else if (m_bInX509Certificate)
-        m_aX509Certificate += rChars;
-    else if (m_bInMdssiValue)
-        m_aMdssiValue += rChars;
-    else if (m_bInSignatureComments)
-        m_aSignatureComments += rChars;
-    else if (m_bInX509IssuerName)
-        m_aX509IssuerName += rChars;
-    else if (m_bInX509SerialNumber)
-        m_aX509SerialNumber += rChars;
-    else if (m_bInCertDigest)
-        m_aCertDigest += rChars;
-    else if (m_bInValidSignatureImage)
-        m_aValidSignatureImage += rChars;
-    else if (m_bInInvalidSignatureImage)
-        m_aInvalidSignatureImage += rChars;
-    else if (m_bInSignatureLineId)
-        m_aSignatureLineId += rChars;
+    assert(!m_ContextStack.empty()); // this should be checked by sax parser?
+    m_ContextStack.top()->Characters(rChars);
 
     if (m_xNextHandler.is())
         m_xNextHandler->characters(rChars);
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.hxx 
b/xmlsecurity/source/helper/ooxmlsecparser.hxx
index b425e4c32a0f..88e87fd1c39c 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.hxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.hxx
@@ -19,6 +19,11 @@
 
 #include <xsecctl.hxx>
 
+#include <xmloff/nmspmap.hxx>
+
+#include <stack>
+
+
 /// Parses an OOXML digital signature.
 class OOXMLSecParser: public cppu::WeakImplHelper
     <
@@ -26,38 +31,62 @@ class OOXMLSecParser: public cppu::WeakImplHelper
     css::lang::XInitialization
     >
 {
+public:
+    class Context;
+private:
+    class UnknownContext;
+    class ReferencedContextImpl;
+    class DsX509CertificateContext;
+    class DsX509SerialNumberContext;
+    class DsX509IssuerNameContext;
+    class DsX509IssuerSerialContext;
+    class DsX509DataContext;
+    class DsKeyInfoContext;
+    class DsSignatureValueContext;
+    class DsDigestValueContext;
+    class DsDigestMethodContext;
+    class DsTransformContext;
+    class DsTransformsContext;
+    class DsReferenceContext;
+    class DsSignatureMethodContext;
+    class DsSignedInfoContext;
+    class XadesEncapsulatedX509CertificateContext;
+    class XadesCertificateValuesContext;
+    class XadesUnsignedSignaturePropertiesContext;
+    class XadesUnsignedPropertiesContext;
+    class XadesCertDigestContext;
+    class XadesCertContext;
+    class XadesSigningCertificateContext;
+    class XadesSigningTimeContext;
+    class XadesSignedSignaturePropertiesContext;
+    class XadesSignedPropertiesContext;
+    class XadesQualifyingPropertiesContext;
+    class MdssiValueContext;
+    class MdssiSignatureTimeContext;
+    class MsodigsigSetupIDContext;
+    class MsodigsigSignatureCommentsContext;
+    class MsodigsigSignatureInfoV1Context;
+    class DsSignaturePropertyContext;
+    class DsSignaturePropertiesContext;
+    class DsManifestContext;
+    class DsObjectContext;
+    class DsSignatureContext;
+    class DsigSignaturesContext;
+
+    std::stack<std::unique_ptr<Context>> m_ContextStack;
+    std::unique_ptr<SvXMLNamespaceMap> m_pNamespaceMap;
+
     XSecController* m_pXSecController;
     css::uno::Reference<css::xml::sax::XDocumentHandler> m_xNextHandler;
 
-    bool m_bInDigestValue;
-    OUString m_aDigestValue;
-    bool m_bInSignatureValue;
-    OUString m_aSignatureValue;
-    bool m_bInX509Certificate;
-    OUString m_aX509Certificate;
-    bool m_bInMdssiValue;
-    OUString m_aMdssiValue;
-    bool m_bInSignatureComments;
-    OUString m_aSignatureComments;
-    bool m_bInX509IssuerName;
-    OUString m_aX509IssuerName;
-    bool m_bInX509SerialNumber;
-    OUString m_aX509SerialNumber;
-    bool m_bInCertDigest;
-    OUString m_aCertDigest;
-    bool m_bInValidSignatureImage;
-    OUString m_aValidSignatureImage;
-    bool m_bInInvalidSignatureImage;
-    OUString m_aInvalidSignatureImage;
-    bool m_bInSignatureLineId;
-    OUString m_aSignatureLineId;
-
     /// Last seen <Reference URI="...">.
     OUString m_aReferenceURI;
     /// Already called addStreamReference() for this reference.
     bool m_bReferenceUnresolved;
     XMLSignatureHelper& m_rXMLSignatureHelper;
 
+    OUString HandleIdAttr(css::uno::Reference<css::xml::sax::XAttributeList> 
const& xAttrs);
+
 public:
     explicit OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, 
XSecController* pXSecController);
     virtual ~OOXMLSecParser() override;
commit 78284e4135247734c583bf83e76757d3dafffb3b
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Feb 25 14:17:48 2021 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Oct 19 12:43:36 2021 +0200

    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 <michael.st...@allotropia.de>
    (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 <michael.st...@allotropia.de>
    (cherry picked from commit 5af5ea893bcb8a8eb472ac11133da10e5a604e66)
    
    xmlsecurity: add EqualDistinguishedNames()
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111545
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (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 <michael.st...@allotropia.de>
    (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 <michael.st...@allotropia.de>
    (cherry picked from commit ca98e505cd69bf95d8ddb9387cf3f8e03ae4577d)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111910
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit a1cf770c2d7ca3e153e0b1f01ddcc313bc2bed7f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113058
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    
    Change-Id: I9633a980b0c18d58dfce24fc59396a833498a77d

diff --git a/include/svl/sigstruct.hxx b/include/svl/sigstruct.hxx
index 769f8ca36842..02b5c11e73a3 100644
--- a/include/svl/sigstruct.hxx
+++ b/include/svl/sigstruct.hxx
@@ -22,6 +22,7 @@
 
 #include <rtl/ustring.hxx>
 #include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
 #include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
 #include <com/sun/star/xml/crypto/DigestID.hpp>
 #include <com/sun/star/uno/Sequence.hxx>
@@ -29,8 +30,6 @@
 #include <set>
 #include <vector>
 
-namespace com { namespace sun { namespace star { namespace graphic { class 
XGraphic; } } } }
-
 /*
  * type of reference
  */
@@ -89,9 +88,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;
@@ -124,8 +144,6 @@ struct SignatureInformation
     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;
     /// Valid and invalid signature line images
     css::uno::Reference<css::graphic::XGraphic> aValidSignatureImage;
     css::uno::Reference<css::graphic::XGraphic> aInvalidSignatureImage;
@@ -140,9 +158,6 @@ struct SignatureInformation
     /// For PDF: the byte range doesn't cover the whole document.
     bool bPartialDocumentSignature;
 
-    /// The certificate owner (aka subject).
-    OUString ouSubject;
-
     svl::crypto::SignatureMethodAlgorithm eAlgorithmID;
 
     SignatureInformation( sal_Int32 nId )
diff --git a/svl/source/crypto/cryptosign.cxx b/svl/source/crypto/cryptosign.cxx
index 617c926201fa..fb5fd7038033 100644
--- a/svl/source/crypto/cryptosign.cxx
+++ b/svl/source/crypto/cryptosign.cxx
@@ -2111,8 +2111,12 @@ bool Signing::Verify(const std::vector<unsigned char>& 
aData,
             aDerCert[i] = pCertificate->derCert.data[i];
         OUStringBuffer aBuffer;
         comphelper::Base64::encode(aBuffer, aDerCert);
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
-        rInformation.ouSubject = OUString(pCertificate->subjectName, 
PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
+        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;
@@ -2291,8 +2295,12 @@ bool Signing::Verify(const std::vector<unsigned char>& 
aData,
             aDerCert[i] = pSignerCertContext->pbCertEncoded[i];
         OUStringBuffer aBuffer;
         comphelper::Base64::encode(aBuffer, aDerCert);
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
-        rInformation.ouSubject = GetSubjectName(pSignerCertContext);
+        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/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx
index e2014a101966..1929880d60a2 100644
--- a/sw/source/core/edit/edfcol.cxx
+++ b/sw/source/core/edit/edfcol.cxx
@@ -407,7 +407,8 @@ std::pair<bool, OUString> 
lcl_MakeParagraphSignatureFieldText(const SignatureDes
             valid = valid
                     && aInfo.nStatus == 
xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
 
-            msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.ouSubject + ", ";
+            assert(aInfo.GetSigningCertificate()); // it was valid
+            msg = SwResId(STR_SIGNED_BY) + ": " + 
aInfo.GetSigningCertificate()->X509Subject + ", ";
             msg += aDescr.msDate;
             msg += (!aDescr.msUsage.isEmpty() ? (" (" + aDescr.msUsage + "): 
") : OUString(": "));
             msg += (valid ? SwResId(STR_VALID) : SwResId(STR_INVALID));
diff --git a/xmlsecurity/inc/biginteger.hxx b/xmlsecurity/inc/biginteger.hxx
index d07ecf45d8af..8b4d8a9143b5 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/xmlsignaturehelper.hxx 
b/xmlsecurity/inc/xmlsignaturehelper.hxx
index 02128bb4f6a8..9d6bf7b3c6de 100644
--- a/xmlsecurity/inc/xmlsignaturehelper.hxx
+++ b/xmlsecurity/inc/xmlsignaturehelper.hxx
@@ -37,6 +37,9 @@
 #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;
 
 namespace com {
@@ -95,6 +98,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 a8167949e159..1b61be773f7d 100644
--- a/xmlsecurity/inc/xsecctl.hxx
+++ b/xmlsecurity/inc/xsecctl.hxx
@@ -270,9 +270,13 @@ private:
         sal_Int32 nDigestID );
     void setReferenceCount() const;
 
-    void setX509IssuerName( OUString const & ouX509IssuerName );
-    void setX509SerialNumber( OUString const & ouX509SerialNumber );
-    void setX509Certificate( OUString const & ouX509Certificate );
+    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 );
@@ -281,7 +285,6 @@ private:
 
     void setDate(OUString const& rId, OUString const& ouDate);
     void setDescription(OUString const& rId, OUString const& rDescription);
-    void setCertDigest(const OUString& rCertDigest);
     void setValidSignatureImage(const OUString& rValidSigImg);
     void setInvalidSignatureImage(const OUString& rInvalidSigImg);
     void setSignatureLineId(const OUString& rSignatureLineId);
@@ -310,6 +313,9 @@ 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,
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx 
b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index c67d893b0624..fdd08892d24a 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -499,27 +499,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 ) );
-
+                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,
-                                                                            
Sequence<Reference<css::security::XCertificate> >());
-                } catch (SecurityException& ) {
-                    OSL_FAIL("Verification of certificate failed");
-                    rSigInfo.CertificateStatus = 
css::security::CertificateValidity::INVALID;
+                    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 if (xGpgSecEnv.is()) // 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
@@ -604,11 +613,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();
@@ -616,7 +629,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 2280c77bbfb1..fbaf5a10ef14 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -593,7 +593,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";
@@ -691,8 +691,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 (xSecEnv.is() && !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
@@ -704,9 +704,12 @@ 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() && xSecEnv.is())
-        xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, 
xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
-    if (!xCert.is() && xGpgSecEnv.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 1dda0be4d7f5..47e788b759bb 100644
--- a/xmlsecurity/source/helper/documentsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx
@@ -512,6 +512,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()));

... etc. - the rest is truncated

Reply via email to