RepositoryExternal.mk                                                          
      |   26 
 dev/null                                                                       
      |binary
 
external/libxmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
 |   68 
 external/libxmlsec/UnpackedTarball_xmlsec.mk                                   
      |    2 
 include/sfx2/objsh.hxx                                                         
      |    2 
 include/xmloff/xmlimp.hxx                                                      
      |    6 
 include/xmloff/xmlnmspe.hxx                                                    
      |   10 
 include/xmloff/xmltoken.hxx                                                    
      |   13 
 offapi/com/sun/star/security/DocumentSignatureInformation.idl                  
      |    1 
 sfx2/source/dialog/dinfdlg.cxx                                                 
      |    2 
 xmloff/source/core/xmlimp.cxx                                                  
      |   26 
 xmloff/source/core/xmltoken.cxx                                                
      |   13 
 xmloff/source/token/tokens.txt                                                 
      |   10 
 xmlsecurity/CppunitTest_xmlsecurity_pdfsigning.mk                              
      |    8 
 xmlsecurity/CppunitTest_xmlsecurity_signing.mk                                 
      |    9 
 xmlsecurity/inc/biginteger.hxx                                                 
      |   12 
 xmlsecurity/inc/sigstruct.hxx                                                  
      |   41 
 xmlsecurity/inc/xmlsec-wrapper.h                                               
      |    4 
 xmlsecurity/inc/xmlsignaturehelper.hxx                                         
      |   12 
 xmlsecurity/inc/xsecctl.hxx                                                    
      |   31 
 xmlsecurity/qa/create-certs/create-certs.sh                                    
      |    6 
 xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx                                  
      |   32 
 
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/cert9.db                                      
      |binary
 xmlsecurity/qa/unit/signing/data/key4.db                                       
      |binary
 xmlsecurity/qa/unit/signing/data/notype-xades.odt                              
      |binary
 xmlsecurity/qa/unit/signing/data/pkcs11.txt                                    
      |    5 
 xmlsecurity/qa/unit/signing/data/signed_with_x509certificate_chain.odt         
      |binary
 xmlsecurity/qa/unit/signing/data/test.p7b                                      
      |  249 +
 xmlsecurity/qa/unit/signing/signing.cxx                                        
      |  261 +
 xmlsecurity/source/component/documentdigitalsignatures.cxx                     
      |   61 
 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx                         
      |   15 
 xmlsecurity/source/helper/documentsignaturehelper.cxx                          
      |   63 
 xmlsecurity/source/helper/documentsignaturemanager.cxx                         
      |   12 
 xmlsecurity/source/helper/ooxmlsecexporter.cxx                                 
      |  234 -
 xmlsecurity/source/helper/ooxmlsecparser.cxx                                   
      | 1404 +++++++-
 xmlsecurity/source/helper/ooxmlsecparser.hxx                                   
      |   69 
 xmlsecurity/source/helper/pdfsignaturehelper.cxx                               
      |    8 
 xmlsecurity/source/helper/xmlsignaturehelper.cxx                               
      |  164 
 xmlsecurity/source/helper/xsecctl.cxx                                          
      |   92 
 xmlsecurity/source/helper/xsecparser.cxx                                       
      | 1720 ++++++++--
 xmlsecurity/source/helper/xsecparser.hxx                                       
      |  104 
 xmlsecurity/source/helper/xsecsign.cxx                                         
      |   50 
 xmlsecurity/source/helper/xsecverify.cxx                                       
      |  194 -
 xmlsecurity/source/pdfio/pdfdocument.cxx                                       
      |   14 
 xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx          
      |   63 
 xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx              
      |  125 
 xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx                 
      |    6 
 xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx                  
      |   36 
 xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx                      
      |  108 
 xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx                         
      |    8 
 55 files changed, 4591 insertions(+), 808 deletions(-)

New commits:
commit 36d13fcb5f5e9fd6ec75a0b56ba69c66d8792d7d
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Thu Mar 3 14:22:37 2022 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 20:00:02 2022 +0000

    compare authors using Thumbprint
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130929
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit 65442205b5b274ad309308162f150f8d41648f72)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130866
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit a7aaa78acea4c1d51283c2fce54ff9f5339026f8)
    
    Change-Id: I338f58eb07cbf0a3d13a7dafdaddac09252a8546
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131368
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 2c8c221b88f2e2bb5b29a6c1bcce1ea75e98136a)

diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx 
b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 3eaaca1b0918..30c360c19773 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -456,8 +456,17 @@ sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
     for ( ; pAuthors != pAuthorsEnd; ++pAuthors )
     {
         SvtSecurityOptions::Certificate aAuthor = *pAuthors;
-        if (xmlsecurity::EqualDistinguishedNames(aAuthor[0], 
xAuthor->getIssuerName(), xmlsecurity::NOCOMPAT)
-            && (aAuthor[1] == sSerialNum))
+        if (!xmlsecurity::EqualDistinguishedNames(aAuthor[0], 
xAuthor->getIssuerName(), xmlsecurity::NOCOMPAT))
+            continue;
+        if (aAuthor[1] != sSerialNum)
+            continue;
+
+        DocumentSignatureManager aSignatureManager(mxCtx, {});
+        if (!aSignatureManager.init())
+            return false;
+        uno::Reference<css::security::XCertificate> xCert =
+            
aSignatureManager.getSecurityEnvironment()->createCertificateFromAscii(aAuthor[2]);
+        if (xCert->getSHA1Thumbprint() == xAuthor->getSHA1Thumbprint())
         {
             bFound = true;
             break;
commit 02c99ee8df6173a4cfeb2625f939185cb40c2bb6
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Mon Dec 20 17:05:44 2021 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 20:00:02 2022 +0000

    only use X509Data
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127193
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit be446d81e07b5499152efeca6ca23034e51ea5ff)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127178
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>
    (cherry picked from commit b0404f80577de9ff69e58390c6f6ef949fdb0139)
    
    (cherry picked from commit 71e24ced5ed93618215bb95f9d32783f9ebe95a3)
    
    Change-Id: I52e6588f5fac04bb26d77c1f3af470db73e41f72

diff --git a/xmlsecurity/inc/xmlsec-wrapper.h b/xmlsecurity/inc/xmlsec-wrapper.h
index 6047d516a9ce..107a06771ac8 100644
--- a/xmlsecurity/inc/xmlsec-wrapper.h
+++ b/xmlsecurity/inc/xmlsec-wrapper.h
@@ -42,6 +42,10 @@
 #include "xmlsec/xmltree.h"
 #ifdef XMLSEC_CRYPTO_NSS
 #include "xmlsec/nss/pkikeys.h"
+#include <xmlsec/nss/x509.h>
+#endif
+#ifdef XMLSEC_CRYPTO_MSCRYPTO
+#include <xmlsec/mscrypto/x509.h>
 #endif
 
 #endif
diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx 
b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
index 9751a21fe937..33faf81575d1 100644
--- a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
+++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
@@ -203,6 +203,10 @@ SAL_CALL XMLSignature_MSCryptImpl::validate(
     // We do certificate verification ourselves.
     pDsigCtx->keyInfoReadCtx.flags |= 
XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
 
+    // limit possible key data to valid X509 certificates only, no KeyValues
+    if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST 
xmlSecMSCryptoKeyDataX509GetKlass()) < 0)
+        throw RuntimeException("failed to limit allowed key data");
+
     //Verify signature
     //The documentation says that the signature is only valid if the return 
value is 0 (that is, not < 0)
     //AND pDsigCtx->status == xmlSecDSigStatusSucceeded. That is, we must not 
make any assumptions, if
diff --git a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx 
b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
index 2d07dc5e6c09..ce872394c3e4 100644
--- a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
+++ b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
@@ -226,6 +226,10 @@ SAL_CALL XMLSignature_NssImpl::validate(
         // We do certificate verification ourselves.
         pDsigCtx->keyInfoReadCtx.flags |= 
XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
 
+        // limit possible key data to valid X509 certificates only, no 
KeyValues
+        if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), 
BAD_CAST xmlSecNssKeyDataX509GetKlass()) < 0)
+            throw RuntimeException("failed to limit allowed key data");
+
         //Verify signature
         int rs = xmlSecDSigCtxVerify( pDsigCtx , pNode );
 
commit 39b1ac4a18e93c6c4e3d3a31ce14d0b221243a98
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Oct 27 15:28:11 2021 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 20:00:02 2022 +0000

    xmlsecurity: some Distinguished Names are less equal than others
    
    It turns out that the 2 backends NSS and MS CryptoAPI generate different
    string representations of the same Distinguished Name in at least one
    corner case, when a value contains a quote " U+0022.
    
    The CryptoAPI function to generate the strings is:
    CertNameToStr(..., CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, ...)
    
    This is documented on MSDN:
    
https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra#CERT_X500_NAME_STR
    
    NSS appears to implement RFC 1485, at least that's what the internal
    function is named after, or perhaps one of its several successor RFCs
    (not clear currently if there's a relevant difference).
    
    This is now causing trouble if a certificate with such a DN is used in a
    signature, created on WNT but then verified on another platform, because
    commit 5af5ea893bcb8a8eb472ac11133da10e5a604e66
    introduced consistency checks that compare the DNs that occur as strings
    in META-INF/documentsignatures.xml:
    
    xmlsecurity/source/helper/xmlsignaturehelper.cxx:672: X509Data cannot be 
parsed
    
    The reason is that in XSecController::setX509Data() the value read from
    the X509IssuerSerial element (a string generated by CryptoAPI) doesn't
    match the value generated by NSS from the certificate parsed from the
    X509Certificate element, so these are erroneously interpreted as 2
    distinct certificates.
    
    Try to make the EqualDistinguishedNames() more flexible so that it can
    try also a converted variant of the DN.
    
    (libxmlsec's NSS backend also complains that it cannot parse the DN:
     x509vfy.c:607: xmlSecNssX509NameRead() '' '' 12 'invalid data for 'char': 
actual=34 and expected comma ',''
     but it manages to validate the signature despite this.)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124287
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit e63611fabd38c757809b510fbb71c077880b1081)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124196
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit 3dfe381032fc61ea31106f103dee9db8277d4d25)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124421
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit f77ecfff1963aea4e5903824a304fa902ac4be35)
    
    Change-Id: I4f72900738d1f5313146bbda7320a8f44319ebc8

diff --git a/xmlsecurity/CppunitTest_xmlsecurity_signing.mk 
b/xmlsecurity/CppunitTest_xmlsecurity_signing.mk
index fbdb05f4b5f1..3bd0ad08a823 100644
--- a/xmlsecurity/CppunitTest_xmlsecurity_signing.mk
+++ b/xmlsecurity/CppunitTest_xmlsecurity_signing.mk
@@ -27,6 +27,7 @@ $(eval $(call 
gb_CppunitTest_use_libraries,xmlsecurity_signing, \
        unotest \
        utl \
        xmlsecurity \
+       xsec_xmlsec \
 ))
 
 $(eval $(call gb_CppunitTest_use_externals,xmlsecurity_signing,\
diff --git a/xmlsecurity/inc/biginteger.hxx b/xmlsecurity/inc/biginteger.hxx
index b4bd3be07f7c..e716c438b97f 100644
--- a/xmlsecurity/inc/biginteger.hxx
+++ b/xmlsecurity/inc/biginteger.hxx
@@ -32,8 +32,17 @@ namespace xmlsecurity
 XSECXMLSEC_DLLPUBLIC OUString bigIntegerToNumericString( const 
css::uno::Sequence< sal_Int8 >& serial );
 XSECXMLSEC_DLLPUBLIC css::uno::Sequence< sal_Int8 > numericStringToBigInteger 
( const OUString& serialNumber );
 
+// DNs read as strings from XML files may need to be mangled for compatibility
+// as NSS and MS CryptoAPI have different string serialisations; if the DN is
+// from an XCertificate it's "native" already and doesn't need to be mangled.
+enum EqualMode
+{
+    NOCOMPAT,
+    COMPAT_2ND,
+    COMPAT_BOTH
+};
 XSECXMLSEC_DLLPUBLIC bool EqualDistinguishedNames(OUString const& rName1,
-                                                  OUString const& rName2);
+                                                  OUString const& rName2, 
EqualMode eMode);
 }
 
 #endif
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index 36fbb54200c5..444a8446907f 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -48,6 +48,7 @@
 #include <documentsignaturehelper.hxx>
 #include <xmlsignaturehelper.hxx>
 #include <documentsignaturemanager.hxx>
+#include <biginteger.hxx>
 
 using namespace com::sun::star;
 
@@ -83,6 +84,7 @@ public:
     void testODFTripleX509Data();
     void testODFMacroDoubleX509Data();
     void testODFDoubleX509Certificate();
+    void testDNCompatibility();
     /// 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.
@@ -124,6 +126,7 @@ public:
     CPPUNIT_TEST(testODFTripleX509Data);
     CPPUNIT_TEST(testODFMacroDoubleX509Data);
     CPPUNIT_TEST(testODFDoubleX509Certificate);
+    CPPUNIT_TEST(testDNCompatibility);
     CPPUNIT_TEST(testOOXMLPartial);
     CPPUNIT_TEST(testOOXMLBroken);
     CPPUNIT_TEST(testOOXMLDescription);
@@ -569,6 +572,21 @@ void SigningTest::testODFDoubleX509Certificate()
     CPPUNIT_ASSERT(!infos[0].Signer.is());
 }
 
+void SigningTest::testDNCompatibility()
+{
+    OUString const msDN("CN=\"\"\"ABC\"\".\", O=\"Enterprise \"\"ABC\"\"\"");
+    OUString const nssDN("CN=\\\"ABC\\\".,O=Enterprise \\\"ABC\\\"");
+    // this is just the status quo, possibly either NSS or CryptoAPI might 
change
+    CPPUNIT_ASSERT(!xmlsecurity::EqualDistinguishedNames(msDN, nssDN, 
xmlsecurity::NOCOMPAT));
+    CPPUNIT_ASSERT(!xmlsecurity::EqualDistinguishedNames(nssDN, msDN, 
xmlsecurity::NOCOMPAT));
+    // with compat flag it should work, with the string one 2nd and the native 
one 1st
+#ifdef _WIN32
+    CPPUNIT_ASSERT(xmlsecurity::EqualDistinguishedNames(msDN, nssDN, 
xmlsecurity::COMPAT_2ND));
+#else
+    CPPUNIT_ASSERT(xmlsecurity::EqualDistinguishedNames(nssDN, msDN, 
xmlsecurity::COMPAT_2ND));
+#endif
+}
+
 void SigningTest::testOOXMLPartial()
 {
     createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx");
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx 
b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 62fe4cdc976c..3eaaca1b0918 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -456,7 +456,7 @@ sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
     for ( ; pAuthors != pAuthorsEnd; ++pAuthors )
     {
         SvtSecurityOptions::Certificate aAuthor = *pAuthors;
-        if (xmlsecurity::EqualDistinguishedNames(aAuthor[0], 
xAuthor->getIssuerName())
+        if (xmlsecurity::EqualDistinguishedNames(aAuthor[0], 
xAuthor->getIssuerName(), xmlsecurity::NOCOMPAT)
             && (aAuthor[1] == sSerialNum))
         {
             bFound = true;
diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx 
b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
index 2c5d624410ec..801ae24d1621 100644
--- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
@@ -49,6 +49,8 @@
 #include <tools/time.hxx>
 #include <comphelper/ofopxmlhelper.hxx>
 #include <comphelper/sequence.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
 
 #include <boost/optional.hpp>
 
@@ -635,7 +637,7 @@ static auto CheckX509Data(
                 start = i; // issuer isn't in the list
                 break;
             }
-            if 
(xmlsecurity::EqualDistinguishedNames(certs[i]->getIssuerName(), 
certs[j]->getSubjectName()))
+            if 
(xmlsecurity::EqualDistinguishedNames(certs[i]->getIssuerName(), 
certs[j]->getSubjectName(), xmlsecurity::NOCOMPAT))
             {
                 if (i == j) // self signed
                 {
@@ -668,7 +670,7 @@ static auto CheckX509Data(
             if (chain[i] != j)
             {
                 if (xmlsecurity::EqualDistinguishedNames(
-                        certs[chain[i]]->getSubjectName(), 
certs[j]->getIssuerName()))
+                        certs[chain[i]]->getSubjectName(), 
certs[j]->getIssuerName(), xmlsecurity::NOCOMPAT))
                 {
                     if (chain.size() != i + 1) // already found issuee?
                     {
diff --git a/xmlsecurity/source/helper/xsecverify.cxx 
b/xmlsecurity/source/helper/xsecverify.cxx
index e2a0373cdb12..83c041c4de8a 100644
--- a/xmlsecurity/source/helper/xsecverify.cxx
+++ b/xmlsecurity/source/helper/xsecverify.cxx
@@ -257,7 +257,7 @@ void XSecController::setX509Data(
             OUString const 
serialNumber(xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()));
             auto const iter = std::find_if(rX509IssuerSerials.begin(), 
rX509IssuerSerials.end(),
                 [&](auto const& rX509IssuerSerial) {
-                    return xmlsecurity::EqualDistinguishedNames(issuerName, 
rX509IssuerSerial.first)
+                    return xmlsecurity::EqualDistinguishedNames(issuerName, 
rX509IssuerSerial.first, xmlsecurity::COMPAT_2ND)
                         && serialNumber == rX509IssuerSerial.second;
                 });
             if (iter != rX509IssuerSerials.end())
@@ -404,7 +404,7 @@ void XSecController::setX509CertDigest(
     {
         for (auto & it : rData)
         {
-            if (xmlsecurity::EqualDistinguishedNames(it.X509IssuerName, 
rX509IssuerName)
+            if (xmlsecurity::EqualDistinguishedNames(it.X509IssuerName, 
rX509IssuerName, xmlsecurity::COMPAT_BOTH)
                 && it.X509SerialNumber == rX509SerialNumber)
             {
                 it.CertDigest = rCertDigest;
@@ -427,7 +427,7 @@ void XSecController::setX509CertDigest(
                     {
                         SAL_INFO("xmlsecurity.helper", "cannot parse 
X509Certificate");
                     }
-                    else if 
(xmlsecurity::EqualDistinguishedNames(xCert->getIssuerName(),rX509IssuerName)
+                    else if 
(xmlsecurity::EqualDistinguishedNames(xCert->getIssuerName(), rX509IssuerName, 
xmlsecurity::COMPAT_2ND)
                         && 
xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()) == 
rX509SerialNumber)
                     {
                         it.CertDigest = rCertDigest;
diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx 
b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
index 5852c7c32bb3..ce68efe078df 100644
--- a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
+++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
@@ -30,6 +30,7 @@
 #include "oid.hxx"
 
 #include <rtl/locale.h>
+#include <rtl/ustrbuf.hxx>
 #include <osl/nlsupport.h>
 #include <osl/process.h>
 
@@ -661,6 +662,67 @@ sal_Int32 SAL_CALL 
X509Certificate_MSCryptImpl::getCertificateUsage(  )
 
 namespace xmlsecurity {
 
+// based on some guesswork and:
+// https://datatracker.ietf.org/doc/html/rfc1485
+// 
https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra#CERT_X500_NAME_STR
+// the main problem appears to be that in values NSS uses \ escapes but 
CryptoAPI requires " quotes around value
+static OUString CompatDNNSS(OUString const& rDN)
+{
+    OUStringBuffer buf(rDN.getLength());
+    enum { DEFAULT, INVALUE, INQUOTE } state(DEFAULT);
+    for (sal_Int32 i = 0; i < rDN.getLength(); ++i)
+    {
+        if (state == DEFAULT)
+        {
+            buf.append(rDN[i]);
+            if (rDN[i] == '=')
+            {
+                if (rDN.getLength() == i+1)
+                {
+                    break; // invalid?
+                }
+                else
+                {
+                    buf.append('"');
+                    state = INVALUE;
+                }
+            }
+        }
+        else if (state == INVALUE)
+        {
+            if (rDN[i] == '+' || rDN[i] == ',' || rDN[i] == ';')
+            {
+                buf.append('"');
+                buf.append(rDN[i]);
+                state = DEFAULT;
+            }
+            else if (rDN[i] == '\\')
+            {
+                if (rDN.getLength() == i+1)
+                {
+                    break; // invalid?
+                }
+                if (rDN[i+1] == '"')
+                {
+                    buf.append('"');
+                }
+                buf.append(rDN[i+1]);
+                ++i;
+            }
+            else
+            {
+                buf.append(rDN[i]);
+            }
+            if (i+1 == rDN.getLength())
+            {
+                buf.append('"');
+                state = DEFAULT;
+            }
+        }
+    }
+    return buf.makeStringAndClear();
+}
+
 static bool EncodeDistinguishedName(OUString const& rName, CERT_NAME_BLOB & 
rBlob)
 {
     LPCWSTR pszError;
@@ -683,22 +745,38 @@ static bool EncodeDistinguishedName(OUString const& 
rName, CERT_NAME_BLOB & rBlo
 }
 
 bool EqualDistinguishedNames(
-        OUString const& rName1, OUString const& rName2)
+        OUString const& rName1, OUString const& rName2,
+        EqualMode const eMode)
 {
+    if (eMode == COMPAT_BOTH && !rName1.isEmpty() && rName1 == rName2)
+    {   // handle case where both need to be converted
+        return true;
+    }
     CERT_NAME_BLOB blob1;
     if (!EncodeDistinguishedName(rName1, blob1))
     {
         return false;
     }
     CERT_NAME_BLOB blob2;
-    if (!EncodeDistinguishedName(rName2, blob2))
+    bool ret(false);
+    if (!!EncodeDistinguishedName(rName2, blob2))
     {
-        delete[] blob1.pbData;
-        return false;
+        ret = CertCompareCertificateName(X509_ASN_ENCODING,
+            &blob1, &blob2) == TRUE;
+        delete[] blob2.pbData;
+    }
+    if (!ret && eMode == COMPAT_2ND)
+    {
+        CERT_NAME_BLOB blob2compat;
+        if (!EncodeDistinguishedName(CompatDNNSS(rName2), blob2compat))
+        {
+            delete[] blob1.pbData;
+            return false;
+        }
+        ret = CertCompareCertificateName(X509_ASN_ENCODING,
+            &blob1, &blob2compat) == TRUE;
+        delete[] blob2compat.pbData;
     }
-    bool const ret(CertCompareCertificateName(X509_ASN_ENCODING,
-            &blob1, &blob2) == TRUE);
-    delete[] blob2.pbData;
     delete[] blob1.pbData;
     return ret;
 }
diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx 
b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
index 245dfe29887a..4ae05a592414 100644
--- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
+++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
@@ -29,6 +29,8 @@
 #include <sal/config.h>
 #include <comphelper/servicehelper.hxx>
 #include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
 #include "x509certificate_nssimpl.hxx"
 
 #include <biginteger.hxx>
@@ -495,22 +497,103 @@ sal_Int32 SAL_CALL 
X509Certificate_NssImpl::getCertificateUsage(  )
 
 namespace xmlsecurity {
 
+// based on some guesswork and:
+// https://datatracker.ietf.org/doc/html/rfc1485
+// 
https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra#CERT_X500_NAME_STR
+// the main problem appears to be that in values " is escaped as "" vs. \"
+static OUString CompatDNCryptoAPI(OUString const& rDN)
+{
+    OUStringBuffer buf(rDN.getLength());
+    enum { DEFAULT, INVALUE, INQUOTE } state(DEFAULT);
+    for (sal_Int32 i = 0; i < rDN.getLength(); ++i)
+    {
+        if (state == DEFAULT)
+        {
+            buf.append(rDN[i]);
+            if (rDN[i] == '=')
+            {
+                if (rDN.getLength() == i+1)
+                {
+                    break; // invalid?
+                }
+                else if (rDN[i+1] == '"')
+                {
+                    buf.append(rDN[i+1]);
+                    ++i;
+                    state = INQUOTE;
+                }
+                else
+                {
+                    state = INVALUE;
+                }
+            }
+        }
+        else if (state == INVALUE)
+        {
+            if (rDN[i] == '+' || rDN[i] == ',' || rDN[i] == ';')
+            {
+                state = DEFAULT;
+            }
+            buf.append(rDN[i]);
+        }
+        else
+        {
+            assert(state == INQUOTE);
+            if (rDN[i] == '"')
+            {
+                if (rDN.getLength() != i+1 && rDN[i+1] == '"')
+                {
+                    buf.append('\\');
+                    buf.append(rDN[i+1]);
+                    ++i;
+                }
+                else
+                {
+                    buf.append(rDN[i]);
+                    state = DEFAULT;
+                }
+            }
+            else
+            {
+                buf.append(rDN[i]);
+            }
+        }
+    }
+    return buf.makeStringAndClear();
+}
+
 bool EqualDistinguishedNames(
-        OUString const& rName1, OUString const& rName2)
+        OUString const& rName1, OUString const& rName2,
+        EqualMode const eMode)
 {
+    if (eMode == COMPAT_BOTH && !rName1.isEmpty() && rName1 == rName2)
+    {   // handle case where both need to be converted
+        return true;
+    }
     CERTName *const pName1(CERT_AsciiToName(OUStringToOString(rName1, 
RTL_TEXTENCODING_UTF8).getStr()));
     if (pName1 == nullptr)
     {
         return false;
     }
     CERTName *const pName2(CERT_AsciiToName(OUStringToOString(rName2, 
RTL_TEXTENCODING_UTF8).getStr()));
-    if (pName2 == nullptr)
+    bool ret(false);
+    if (pName2)
     {
-        CERT_DestroyName(pName1);
-        return false;
+        ret = (CERT_CompareName(pName1, pName2) == SECEqual);
+        CERT_DestroyName(pName2);
+    }
+    if (!ret && eMode == COMPAT_2ND)
+    {
+        CERTName *const pName2Compat(CERT_AsciiToName(OUStringToOString(
+            CompatDNCryptoAPI(rName2), RTL_TEXTENCODING_UTF8).getStr()));
+        if (pName2Compat == nullptr)
+        {
+            CERT_DestroyName(pName1);
+            return false;
+        }
+        ret = CERT_CompareName(pName1, pName2Compat) == SECEqual;
+        CERT_DestroyName(pName2Compat);
     }
-    bool const ret(CERT_CompareName(pName1, pName2) == SECEqual);
-    CERT_DestroyName(pName2);
     CERT_DestroyName(pName1);
     return ret;
 }
commit ab831d75fa76b2e29f14f707684001756654f993
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Oct 15 20:52:47 2021 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 20:00:00 2022 +0000

    xmlsecurity: fix test failing because NSS policy forbids SHA1
    
    With Fedora's nss-3.71.0-1.fc34.x86_64 there is the problem that
    8 tests including testODFGood in CppunitTest/xmlsecurity_signing
    fail because the crypto policy disallows SHA1 for signatures.
    
    Apparently this particular policy bit was added in NSS 3.59:
    https://bugzilla.mozilla.org/show_bug.cgi?id=1670835
    
    For signatures, maybe it's not a good idea to override system policy
    for product builds, so do it locally in the tests, at least for now.
    
    If similar problems turn up for encrypted documents in the future,
    that should be fixed in product builds too of course, as encrypted
    documents must always be decryptable.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123768
    Tested-by: Jenkins
    Tested-by: Caolán McNamara <caol...@redhat.com>
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit 51e82016e8783a452fe5f7921d12c1bf20bfd6b5)
    
    xmlsecurity: fix --without-system-nss usage of NSS_SetAlgorithmPolicy
    
    The problem with commit ff572d9222ec16ffd679ae907a0bf4a8900265e1
    is that it's using the wrong library; NSS_SetAlgorithmPolicy is actually
    in libnssutil3.so.
    
    This causes a linking problem when upgrading the internal NSS to a
    version that has NSS_USE_ALG_IN_ANY_SIGNATURE.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123819
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 395c0c0bbaceadf909e0189af99c6358487c7978)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123841
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 874c02831fd2420b35b9719266ecec5d76707121)
    
    Change-Id: I4f634cf5da1707fb628e63cd0cdafebdf4fc903f

diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index c40434cc6403..17e7dbc0e4ef 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -3288,6 +3288,11 @@ $(call gb_LinkTarget_add_libs,$(1),\
 
 endef
 
+define gb_LinkTarget__use_nssutil3
+$(call gb_LinkTarget__use_nss3,$(1))
+
+endef
+
 define gb_LinkTarget__use_plc4
 $(call gb_LinkTarget__use_nss3,$(1))
 
@@ -3357,6 +3362,27 @@ endif
 
 endef
 
+define gb_LinkTarget__use_nssutil3
+$(call gb_LinkTarget_use_package,$(1),nss)
+$(call gb_LinkTarget_set_include,$(1),\
+       $$(INCLUDE) \
+       -I$(call gb_UnpackedTarball_get_dir,nss)/dist/public/nss \
+       -I$(call gb_UnpackedTarball_get_dir,nss)/dist/out/include \
+)
+
+ifeq ($(COM),MSC)
+$(call gb_LinkTarget_add_libs,$(1),\
+       $(call gb_UnpackedTarball_get_dir,nss)/dist/out/lib/nssutil3.lib \
+)
+else
+$(call gb_LinkTarget_add_libs,$(1),\
+       -L$(call gb_UnpackedTarball_get_dir,nss)/dist/out/lib \
+       -lnssutil3 \
+)
+endif
+
+endef
+
 define gb_ExternalProject__use_nss3
 $(call gb_ExternalProject_use_package,$(1),nss)
 
diff --git a/xmlsecurity/CppunitTest_xmlsecurity_pdfsigning.mk 
b/xmlsecurity/CppunitTest_xmlsecurity_pdfsigning.mk
index 021ab8dbe99f..083edf36dbe7 100644
--- a/xmlsecurity/CppunitTest_xmlsecurity_pdfsigning.mk
+++ b/xmlsecurity/CppunitTest_xmlsecurity_pdfsigning.mk
@@ -34,6 +34,14 @@ $(eval $(call 
gb_CppunitTest_use_externals,xmlsecurity_pdfsigning,\
     boost_headers \
 ))
 
+ifneq ($(OS),WNT)
+ifneq (,$(ENABLE_NSS))
+$(eval $(call gb_CppunitTest_use_externals,xmlsecurity_pdfsigning,\
+    nssutil3 \
+))
+endif
+endif
+
 $(eval $(call gb_CppunitTest_set_include,xmlsecurity_pdfsigning,\
        -I$(SRCDIR)/xmlsecurity/inc \
        $$(INCLUDE) \
diff --git a/xmlsecurity/CppunitTest_xmlsecurity_signing.mk 
b/xmlsecurity/CppunitTest_xmlsecurity_signing.mk
index e39e5c085bac..fbdb05f4b5f1 100644
--- a/xmlsecurity/CppunitTest_xmlsecurity_signing.mk
+++ b/xmlsecurity/CppunitTest_xmlsecurity_signing.mk
@@ -34,6 +34,14 @@ $(eval $(call 
gb_CppunitTest_use_externals,xmlsecurity_signing,\
     libxml2 \
 ))
 
+ifneq ($(OS),WNT)
+ifneq (,$(ENABLE_NSS))
+$(eval $(call gb_CppunitTest_use_externals,xmlsecurity_signing,\
+    nssutil3 \
+))
+endif
+endif
+
 $(eval $(call gb_CppunitTest_set_include,xmlsecurity_signing,\
        -I$(SRCDIR)/xmlsecurity/inc \
        $$(INCLUDE) \
diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx 
b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
index 6dbea78ebb98..58335210bf5d 100644
--- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
+++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
@@ -7,6 +7,10 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#ifndef _WIN32
+#include <secoid.h>
+#endif
+
 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
 
 #include <comphelper/processfactory.hxx>
@@ -134,6 +138,18 @@ void PDFSigningTest::setUp()
     osl::File::copy(aSourceDir + "key4.db", aTargetDir + "key4.db");
     osl::File::copy(aSourceDir + "pkcs11.txt", aTargetDir + "pkcs11.txt");
     setenv("MOZILLA_CERTIFICATE_FOLDER", aTargetPath.toUtf8().getStr(), 1);
+#endif
+
+    uno::Reference<xml::crypto::XSEInitializer> xSEInitializer
+        = xml::crypto::SEInitializer::create(mxComponentContext);
+    uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext
+        = xSEInitializer->createSecurityContext(OUString());
+#ifndef _WIN32
+#ifdef NSS_USE_ALG_IN_ANY_SIGNATURE
+    // policy may disallow using SHA1 for signatures but unit test documents
+    // have such existing signatures (call this after createSecurityContext!)
+    NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_ANY_SIGNATURE, 0);
+#endif
 #endif
 }
 
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index 583ea0948c23..36fbb54200c5 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -13,6 +13,10 @@
 
 #include <type_traits>
 
+#ifndef _WIN32
+#include <secoid.h>
+#endif
+
 #include <test/bootstrapfixture.hxx>
 #include <unotest/macros_test.hxx>
 #include <test/xmltesttools.hxx>
@@ -181,6 +185,13 @@ void SigningTest::setUp()
     mxDesktop.set(frame::Desktop::create(mxComponentContext));
     mxSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext);
     mxSecurityContext = mxSEInitializer->createSecurityContext(OUString());
+#ifndef _WIN32
+#ifdef NSS_USE_ALG_IN_ANY_SIGNATURE
+    // policy may disallow using SHA1 for signatures but unit test documents
+    // have such existing signatures (call this after createSecurityContext!)
+    NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_ANY_SIGNATURE, 0);
+#endif
+#endif
 }
 
 void SigningTest::tearDown()
commit 9cbe0f8b34ef119fbe7b214f44b72a74abd70935
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Oct 14 13:44:14 2021 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 19:59:27 2022 +0000

    test: upgrade test NSS database from dbm: to sql:
    
    Fedora nss-3.69.0-1.fc34.x86_64 and Debian libnss3:amd64 2:3.70-1 no
    longer support the old BerekelyDB databases, so convert them to the new
    SQLite format for the benefit of --with-system-nss builds.
    
    This worked to do the upgrade:
    
    > certutil -N -d sql:test/new --empty-password
    > LD_LIBRARY_PATH=instdir/program 
workdir/UnpackedTarball/nss/dist/out/bin/certutil --merge -d sql:test/new 
--source-dir dbm:test/signing-keys
    
    Builds would fail running tests added in commit
    40d70d427edddb589eda64fafc2e56536953d274
    
      signing.cxx:551:Assertion
      Test name: testODFX509CertificateChain::TestBody
      equality assertion failed
      - Expected: 0
      - Actual  : 1
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123586
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 907784ccce7bd8b5121888cff7f5723a55d35358)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123643
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit 7b4b03b9cf21ecd11bc82da5f29c4ff91ad242c9)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123840
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit d6c4807a8351c9ddde4a3358fe5a0e3ca95049e5)
    
    Change-Id: I00aa20703e117ebf583c3331b84e966c2cfc78cd

diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx 
b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
index cee0642fffcd..6dbea78ebb98 100644
--- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
+++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
@@ -129,9 +129,10 @@ void PDFSigningTest::setUp()
     OUString caVar("LIBO_TEST_CRYPTOAPI_PKCS7");
     osl_setEnvironment(caVar.pData, aTargetPath.pData);
 #else
-    // Set up cert8.db and key3.db in workdir/CppunitTest/
-    osl::File::copy(aSourceDir + "cert8.db", aTargetDir + "cert8.db");
-    osl::File::copy(aSourceDir + "key3.db", aTargetDir + "key3.db");
+    // Set up NSS database in workdir/CppunitTest/
+    osl::File::copy(aSourceDir + "cert9.db", aTargetDir + "cert9.db");
+    osl::File::copy(aSourceDir + "key4.db", aTargetDir + "key4.db");
+    osl::File::copy(aSourceDir + "pkcs11.txt", aTargetDir + "pkcs11.txt");
     setenv("MOZILLA_CERTIFICATE_FOLDER", aTargetPath.toUtf8().getStr(), 1);
 #endif
 }
diff --git a/xmlsecurity/qa/unit/signing/data/cert8.db 
b/xmlsecurity/qa/unit/signing/data/cert9.db
similarity index 50%
rename from xmlsecurity/qa/unit/signing/data/cert8.db
rename to xmlsecurity/qa/unit/signing/data/cert9.db
index 95e58ffe5b92..c4064e419f42 100644
Binary files a/xmlsecurity/qa/unit/signing/data/cert8.db and 
b/xmlsecurity/qa/unit/signing/data/cert9.db differ
diff --git a/xmlsecurity/qa/unit/signing/data/key3.db 
b/xmlsecurity/qa/unit/signing/data/key3.db
deleted file mode 100644
index f449e60a667f..000000000000
Binary files a/xmlsecurity/qa/unit/signing/data/key3.db and /dev/null differ
diff --git a/xmlsecurity/qa/unit/signing/data/key4.db 
b/xmlsecurity/qa/unit/signing/data/key4.db
new file mode 100644
index 000000000000..34a7fa28aa32
Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/key4.db differ
diff --git a/xmlsecurity/qa/unit/signing/data/pkcs11.txt 
b/xmlsecurity/qa/unit/signing/data/pkcs11.txt
new file mode 100644
index 000000000000..22c8f8519efd
--- /dev/null
+++ b/xmlsecurity/qa/unit/signing/data/pkcs11.txt
@@ -0,0 +1,5 @@
+library=
+name=NSS Internal PKCS #11 Module
+parameters=configdir='sql:test/new' certPrefix='' keyPrefix='' 
secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' 
updateid='' updateTokenDescription='' 
+NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 
slotParams=(1={slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512]
 askpw=any timeout=30})
+
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index 39d4380375e7..583ea0948c23 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -158,8 +158,12 @@ void SigningTest::setUp()
     OUString aSourceDir = m_directories.getURLFromSrc(DATA_DIRECTORY);
     OUString aTargetDir = m_directories.getURLFromWorkdir(
                               "/CppunitTest/xmlsecurity_signing.test.user/");
-    osl::File::copy(aSourceDir + "cert8.db", aTargetDir + "cert8.db");
-    osl::File::copy(aSourceDir + "key3.db", aTargetDir + "key3.db");
+
+    // Set up NSS database in workdir/CppunitTest/
+    osl::File::copy(aSourceDir + "cert9.db", aTargetDir + "cert9.db");
+    osl::File::copy(aSourceDir + "key4.db", aTargetDir + "key4.db");
+    osl::File::copy(aSourceDir + "pkcs11.txt", aTargetDir + "pkcs11.txt");
+
     OUString aTargetPath;
     osl::FileBase::getSystemPathFromFileURL(aTargetDir, aTargetPath);
     setenv("MOZILLA_CERTIFICATE_FOLDER", aTargetPath.toUtf8().getStr(), 1);
commit f5e38fe27e08c71345c570ab57fdebfb8bf35a01
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Oct 15 16:58:07 2021 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 19:59:23 2022 +0000

    xmlsecurity: fix new tests on WNT
    
    Tests added in commit 40d70d427edddb589eda64fafc2e56536953d274 don't
    actually run on WNT but that wasn't obvious because commit
    149df1fec6472e30582162e17e04c75aee91d26a prevented running them in
    Jenkins on master, they failed only in the libreoffice-7-1 backport.
    
      xmlsecurity/qa/unit/signing/signing.cxx(631) : error : Assertion
      Test name: testODFDoubleX509Certificate::TestBody
      assertion failed
      - Expression: (nActual == SignatureState::NOTVALIDATED || nActual == 
SignatureState::OK)
      - 2
    
    This is an oddity where NSS claims the signature in the document is
    valid but CryptoAPI claims it is invalid; the hashes passed into the
    validation functions are the same.  Just allow BROKEN as an additional
    result value on WNT.
    
      xmlsecurity/qa/unit/signing/signing.cxx(550) : error : Assertion
      Test name: testODFX509CertificateChain::TestBody
      equality assertion failed
      - Expected: 0
      - Actual  : 1
    
    The problem here is that with NSS the tests use a custom NSS database
    in test/signing-keys so we need to make these certificates available for
    CryptoAPI too.
    
    The following one-liner converts the NSS database to a PKCS#7 that can
    be loaded by CrytpAPI:
    
    > openssl crl2pkcs7 -nocrl -certfile <(certutil -d sql:test/signing-keys -L 
| awk '/^[^ ].*,[^ ]*,/ { printf "%s", $1; for (i = 2; i < NF; i++) { printf " 
%s", $i; } printf "
    "; }' | while read name; do certutil -L -d sql:test/signing-keys -a -n 
"${name}" ; done) > test/signing-keys/test.p7b
    
    Then one might naively assume that something like this would allow these
    certificates to be added temporarily as trusted CAs:
    
    +                HCERTSTORE hRoot = CertOpenSystemStoreW( 0, L"Root" ) ;
    +                HCERTSTORE const hExtra = CertOpenStore(
    +                        CERT_STORE_PROV_FILENAME_A,
    +                        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
    +                        NULL,
    +                        CERT_STORE_OPEN_EXISTING_FLAG | 
CERT_STORE_READONLY_FLAG,
    +                        path);
    +                if (hExtra != NULL && hRoot != NULL)
    +                {
    +                    BOOL ret = CertAddStoreToCollection(
    +                        hRoot,
    +                        hExtra,
    +                        CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
    +                        0);
    +                    SAL_DEBUG("XXX hExtra done " << ret);
    +                }
    
    There is no error from this, but it doesn't work.
    
    Instead, check if CertGetCertificateChain() sets the
    CERT_TRUST_IS_UNTRUSTED_ROOT flag and then look up the certificate
    manually in the extra PKCS#7 store.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123667
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit 7d664ec788acdc378506a7ff8b1120cea24a6770)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123839
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit dadfe46e75888391e9f965b79371fd1066a29dd4)
    
    Change-Id: Ic9865e0b5783211c2128ce0327c4583b7784ff62

diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx 
b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
index d63ae11eeb28..cee0642fffcd 100644
--- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
+++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
@@ -11,6 +11,7 @@
 
 #include <comphelper/processfactory.hxx>
 #include <osl/file.hxx>
+#include <osl/process.h>
 #include <test/bootstrapfixture.hxx>
 #include <tools/datetime.hxx>
 #include <unotools/streamwrap.hxx>
@@ -116,15 +117,21 @@ void PDFSigningTest::setUp()
 
     
mxComponentContext.set(comphelper::getComponentContext(getMultiServiceFactory()));
 
-#ifndef _WIN32
-    // Set up cert8.db and key3.db in workdir/CppunitTest/
     OUString aSourceDir = m_directories.getURLFromSrc(DATA_DIRECTORY);
     OUString aTargetDir = m_directories.getURLFromWorkdir(
                               
"/CppunitTest/xmlsecurity_pdfsigning.test.user/");
-    osl::File::copy(aSourceDir + "cert8.db", aTargetDir + "cert8.db");
-    osl::File::copy(aSourceDir + "key3.db", aTargetDir + "key3.db");
     OUString aTargetPath;
     osl::FileBase::getSystemPathFromFileURL(aTargetDir, aTargetPath);
+
+#ifdef _WIN32
+    // CryptoAPI test certificates
+    osl::File::copy(aSourceDir + "test.p7b", aTargetDir + "test.p7b");
+    OUString caVar("LIBO_TEST_CRYPTOAPI_PKCS7");
+    osl_setEnvironment(caVar.pData, aTargetPath.pData);
+#else
+    // Set up cert8.db and key3.db in workdir/CppunitTest/
+    osl::File::copy(aSourceDir + "cert8.db", aTargetDir + "cert8.db");
+    osl::File::copy(aSourceDir + "key3.db", aTargetDir + "key3.db");
     setenv("MOZILLA_CERTIFICATE_FOLDER", aTargetPath.toUtf8().getStr(), 1);
 #endif
 }
diff --git a/xmlsecurity/qa/unit/signing/data/test.p7b 
b/xmlsecurity/qa/unit/signing/data/test.p7b
new file mode 100644
index 000000000000..44723697a2bf
--- /dev/null
+++ b/xmlsecurity/qa/unit/signing/data/test.p7b
@@ -0,0 +1,249 @@
+-----BEGIN PKCS7-----
+MIIuNgYJKoZIhvcNAQcCoIIuJzCCLiMCAQExADALBgkqhkiG9w0BBwGggi4LMIIF
+sjCCA5qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVUsxEDAO
+BgNVBAgMB0VuZ2xhbmQxHTAbBgNVBAoMFFhtbHNlY3VyaXR5IFJTQSBUZXN0MSUw
+IwYDVQQDDBxYbWxzZWN1cml0eSBSU0EgVGVzdCBSb290IENBMCAXDTE4MDYwNjE1
+MjAwNloYDzIxMTgwNTEzMTUyMDA2WjBpMQswCQYDVQQGEwJVSzEQMA4GA1UECAwH
+RW5nbGFuZDEdMBsGA1UECgwUWG1sc2VjdXJpdHkgUlNBIFRlc3QxKTAnBgNVBAMM
+IFhtbHNlY3VyaXR5IEludGVybWVkaWF0ZSBSb290IENBMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEA+uBkXt39Yc0aOe2UkBWlVIqQcvlSwLheXlcGeDDI
+PSwSRaDcuGdGQXs+WFM65xDak8eZJwyyQSWtoDRV0lXEP63OJk/ktWLjFywLP69g
+Br2E4vsjOdr9DR94AAQY2WTW2/UXxcI92nB+sq6ZhVF5I9rfzDHPGYEiWTQqtnTM
+JDGpO5eo9JBjQtaB/sHG7ZnxF1FOl6V85F/dfGG3MBGp9glg5qE6QDjA11DsTuki
+V5OeP8vZsmoYkyNmViA7L+xuOM6iVUGY+b4XDCeI1Kgr5ZhF9xL7ByVTxtZrdMXz
+cPu+Dgcr9VF7QqhAYg/W/0s4WzoyXV/f1fjC5+uKXWSuttrRHNt16DMOh5T1lS4q
+HLfMoDYZ+AK8L0JrjQMXCzCp4WTmqplBg6bYWFpHvyzp0uccYJdUXv5o6PFhpIV6
+VpdVtT6fVfh9V5C5jDKBv+n14rZ9hPYzvIxVAnF6SYtXRTbrSzSDi5QqCiWwU56u
+SAWyyrwdED1zETgTDmGOFv5j2tIEcAbQ6TT8n/Mit5NuL98M5XxPnKduCQ39ssKD
+wO146lAe5kREJRv4Va/o47tards6tdkaV5267rXZA7ndvnov0TmZFNwDMQz9tRZJ
+ov07V7kriLS47xD/eDH7IyEOWYsgoU3N1J1GZKCYSRxZ3Wh6AiZy211PYwuJpP3x
+ugUCAwEAAaNmMGQwHQYDVR0OBBYEFDXB8g347TUPMvCNXTBSRQpVRvroMB8GA1Ud
+IwQYMBaAFOOqggO/I6PkIyJZqJ16mbDbtiXxMBIGA1UdEwEB/wQIMAYBAf8CAQAw
+DgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAiyaCtGnPZRsfGD69y
+jkPptc6cwa8icyF9iiJwdngjvdMTCOJHhUAtzGTOuUITJEh0OJYzabB+EUgHmZWe
+6hwrWCzhJQysDktdsARQOB91Vi19VyDrcHPxnn43zObnbkLpFvZXg3Q3/S+eiTn/
+UWMg7f2tQjaCdj6xx1DGTiJmZBRI/CG24EWzYy+H7/MBNFuW3+1CdoDuPR3lkbWm
+YFJbvkOaWR8+faL6o5u7IagKCSmMaNDjRQA8/LKwJ8waD61Hw4S4H465I16UVCT4
+d226anZIfz7N3/NbVw0B8emJP1ZtVty1vDPEx/6A7+sXfgAYgjfMeiHhGHs17i2d
+7EvdwxlyvKq/iQkLMzkyAkA5kpUbZ/kpOQh8sR9JHxv3QEz0clRvRIwlJU5W+Pa1
+e3dNYTDR9x0fBaLwPUIc5RnnSZ5Aws2qxnp7yYrQzxTtLd3IoDU4BuuyBE+/Pauk
+bbfJUnr+e9Pwt+OXqrECnhxz+f0FDAMlX0CEe7Vlx8p37roBiT4sf3anXrNyrUZM
+QWQFLs9H3+yooEJJWTgs7QjFZ0l5LIQyTv1I4UmGBgEWlW8UNIJhvAeq1ykY+WZw
+At9JDlNwiAbFbFoMqGkVZDko1foTE8KUJfgth63ZmdWw1yzX8H9+zDlhpHCehJsJ
+68Rk7INjBNZr6IxpVViGLsW1qTCCBbgwggOgoAMCAQICAhAAMA0GCSqGSIb3DQEB
+CwUAMGkxCzAJBgNVBAYTAlVLMRAwDgYDVQQIDAdFbmdsYW5kMR8wHQYDVQQKDBZY
+bWxzZWN1cml0eSBFQ0RTQSBUZXN0MScwJQYDVQQDDB5YbWxzZWN1cml0eSBFQ0RT
+QSBUZXN0IFJvb3QgQ0EwIBcNMTgwNjA2MTUyMDIxWhgPMjExODA1MTMxNTIwMjFa
+MGsxCzAJBgNVBAYTAlVLMRAwDgYDVQQIDAdFbmdsYW5kMR8wHQYDVQQKDBZYbWxz
+ZWN1cml0eSBFQ0RTQSBUZXN0MSkwJwYDVQQDDCBYbWxzZWN1cml0eSBJbnRlcm1l
+ZGlhdGUgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKlB
+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
+BwMCMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln
+aWNlcnQuY29tMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0
+LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwPQYDVR0gBDYw
+NDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv
+bS9DUFMwHQYDVR0OBBYEFD3TUKXWoK3u80pgCmXTIdT4+NYPMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBCwUAA4IBAQCdttCQhuGG
+Au3FoPA0HHTBjXbMhgqo8EqKQtY/yKlNrXwIrea2ULiiGk2IB7EpIdzn2sY8IeDj
+EUlwrHodAaTKETpXq31XKkB0/dMdhRhQ31dHdaF9VSAuRzdQcox/ghvSYo8tA1ra
+w8ihzixSogBj63O6cchJJyOXZIWeOA6tY2g8ulKBWHmjLAzf3m3rMfK6oHxs8SzU
+4b13hDcDzjK1yJqBGkqSTjtGmoX+g6L5noyjzA1esz3PBHiPFBR7MpzHAKZcxLWh
+VY1aVmikInCqPIFx2Z2oRTv05faiUd3He2Lobwx067ja+L+HDXlQkZCbGDuRWSfx
+NSgTqyZ+1fd6MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG
+9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
+FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9i
+YWwgUm9vdCBDQTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJ
+BgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lD
+ZXJ0IFNIQTIgU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAK
+c24RmDYXZK83nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yr
+BvSqXUu3R0bdKpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TX
+vi/TC2rSsd9f/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdI
+kARFdRrdNzGXkujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+gu
+qw9ypzAO+sf0/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB
+/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggr
+BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1
+oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD
+QS5jcmwwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEds
+b2JhbFJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEW
+HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHV
+LyjnjUY4tCzhxtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0G
+CSqGSIb3DQEBCwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHg
+l4+mUwnNqipl5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZg
+THbO7Djc1lGA8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB
+40f/1LkAtDdC2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8Z
+DOo0rwAhaPitc+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4
+d60tbvVS3bR0j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLzMIIEXDCCA0SgAwIBAgIN
+AeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMK
+R2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEyMTUwMDAwNDJaMFQxCzAJ
+BgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3QgU2VydmljZXMxJTAjBgNV
+BAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzMwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDKUkvqHv/OJGuo2nIYaNVWXQ5IWi01CXZaz6TIHLGp
+/lOJ+600/4hbn7vn6AAB3DVzdQOts7G5pH0rJnnOFUAK71G4nzKMfHCGUksW/mon
+a+Y2emJQ2N+aicwJKetPKRSIgAuPOB6Aahh8Hb2XO3h9RUk2T0HNouB2VzxoMXlk
+yW7XUR5mw6JkLHnA52XDVoRTWkNty5oCINLvGmnRsJ1zouAqYGVQMc/7sy+/EYhA
+LrVJEA8KbtyX+r8snwU5C1hUrwaW6MWOARa8qBpNQcWTkaIeoYvy/sGIJEmjR0vF
+EwHdp1cSaWIr6/4g72n7OqXwfinu7ZYW97EfoOSQJeAzAgMBAAGjggEzMIIBLzAO
+BgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIG
+A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHfCuFCaZ3Z2sS3ChtCDoH6mfrpL
+MB8GA1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYuMDUGCCsGAQUFBwEBBCkw
+JzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8E
+KzApMCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYD
+VR0gBDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29v
+Zy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAHLeJluRT7bvs26gyAZ8s
+o81trUISd7O45skDUmAge1cnxhG1P2cNmSxbWsoiCt2eux9LSD+PAj2LIYRFHW31
+/6xoic1k4tbWXkDCjir37xTTNqRAMPUyFRWSdvt+nlPqwnb8Oa2I/maSJukcxDjN
+SfpDh/Bd1lZNgdd/8cLdsE3+wypufJ9uXO1iQpnh9zbuFIwsIONGl1p3A8CgxkqI
+/UAih3JaGOqcpcdaCIzkBaR9uYQ1X4k2Vg5APRLouzVy7a8IVk6wuy6pm+T7HT4L
+Y8ibS5FEZlfAFLSW8NwsVz9SBK2Vqn1N0PIMn5xA6NZVc7o835DLAFshEWfC7TIe
+3jCCBFMwggI7oAMCAQICAhAAMA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNVBAYTAlVL
+MRAwDgYDVQQIDAdFbmdsYW5kMR8wHQYDVQQKDBZYbWxzZWN1cml0eSBFQ0RTQSBU
+ZXN0MSkwJwYDVQQDDCBYbWxzZWN1cml0eSBJbnRlcm1lZGlhdGUgUm9vdCBDQTAg
+Fw0xODA2MDYxNTIwMjFaGA8yMTE4MDUxMzE1MjAyMVowbzELMAkGA1UEBhMCVUsx
+EDAOBgNVBAgMB0VuZ2xhbmQxHzAdBgNVBAoMFlhtbHNlY3VyaXR5IEVDRFNBIFRl
+c3QxLTArBgNVBAMMJFhtbHNlY3VyaXR5IEVDRFNBIFRlc3QgZXhhbXBsZSBBbGlj
+ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABARLFn7pnI5fqVyPKZsn+1aFSgoF
+NxwX30u97S9Ti3v0LkMhzCvJgCMRTRFE5Utzrg1tmNvAO1gl5Cn3VeRv/qWjgcUw
+gcIwCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBaAwMwYJYIZIAYb4QgENBCYW
+JE9wZW5TU0wgR2VuZXJhdGVkIENsaWVudCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU
+6iBLx5qDOXkoKU2kRXYBsRuOKEQwHwYDVR0jBBgwFoAU0EyW4PhS5umRVdHSnb88
+88RIMkcwDgYDVR0PAQH/BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
+BQcDBDANBgkqhkiG9w0BAQsFAAOCAgEACu+ViKlFl5euwbhuysQro10mplQXhocM
+EpLyN4ZwSkplKbyfQIDahoCU1GSVUr6r5/3oOOjeqHNqeRYpd2hGQbmLaDydTbLO
+7Eb/i9u4VIYKrSKQCz4Q5Z7Hc/8hD+YFuwN8xQdzQRE5tMqHQ2PmEYwYkt0ABbqA
+El0Ae5nII98ejz5b1S7a4wPSr4CLVhSUDBTUSglJxaT5ZTa/rhmUjgOg4cFgE+Qm
+OQuaD2VEy65eCWcjUY7r7ZNP6+JbHVBW8DxiWvBd2YZwh4A4TwxUwRwcOgDMh8Z8
+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
+2kKXeAYV3wwAzKqplc7KW07VFFNNdjO3nQbVSYAR3ZIMfoAOqPxPTgjRSKumxDtv
+gZqwmiZZAG4K/2NjrmsA593uZYfhEOZWfY/hcJVnr76gKavYIwRF+hGxUi3fGDHk
+665Xgx0BxUHDosyRDPolGn3aQQY8wT3HXCcNFyeSznzOcK+ixlETAtj+y1arZ4ts
+4pnl0ImqILjEZxrmXTAkRO51TlYt0iA8NQVDa1Ne64Fy2N3OHz4XJzo3aoynf5Ta
+bakQCsh3/prFpCGMYkQMkxXonTdaJnyX/0aMiVfYdAZupG8cAvuRQSQ/i1k5SLAY
+ai1qQW8kmJVYPKdWmEvyBNqZHWVpNiG3SZka1nklMxzCkTfv7Z2Ix8DL+GqM5cNz
+I0DDfG0sOVfqLlcraumu7wZpY+KRGSBN9EF1ZZ9GOX7SwTn57U3yYd0xMIIFujCC
+A6KgAwIBAgIJAMtBg6xEFRDTMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVL
+MRAwDgYDVQQIDAdFbmdsYW5kMR8wHQYDVQQKDBZYbWxzZWN1cml0eSBFQ0RTQSBU
+ZXN0MScwJQYDVQQDDB5YbWxzZWN1cml0eSBFQ0RTQSBUZXN0IFJvb3QgQ0EwIBcN
+MTgwNjA2MTUyMDIxWhgPMjExODA1MTMxNTIwMjFaMGkxCzAJBgNVBAYTAlVLMRAw
+DgYDVQQIDAdFbmdsYW5kMR8wHQYDVQQKDBZYbWxzZWN1cml0eSBFQ0RTQSBUZXN0
+MScwJQYDVQQDDB5YbWxzZWN1cml0eSBFQ0RTQSBUZXN0IFJvb3QgQ0EwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjKXY/LOLDioXDCWBi3GLP29BMDoYx
+J0tkL9Pdir7mBACxRshI9K/eHfzzBURDWycUfW9jU9xPtt2NfJFB3TfUjet4uHkr
+f2K9oZW9QxloVvBSAMPR5393o/cSrcijJ1BA77hilZJQ75t8xOgqBu5uxLfR3yS2
+GHnZAqckavR9y7oQEbmf/b1b+Fa1WWz21RuT82E02M0Ew2/NpvrP7dpkgovyvLPz
+J/pDrdTWOzzYmvNxuKRnHsaDdBSPvgsGmokbZr5GevK5CUYhSumpcD+orZVelFxI
+Fv+KAMAZGlIyyW6Ipv5fs4fGORLJy0h1z2SYzNz41bqnWZsDCruZmEI4RCZkCfq2
+7gEoPQVRjP+RsgpZmnuI2Deyw33Uh/pLtUYf3bjOPnKRThRqzDl7JC27sRhgdUDM
+2KLOPC7IVMG+u94ejOvzSJ5zVdujNvki5OEscN4xPWUDYj/y3QOnDp8MarCd7al4
+P+Dk3niNnkFMLFSl+gbbLjDNcrabtVqCnd/dmgjwiU9k80oNa0jKx7pdKPqPvxKM
+e5xffmkDp9XFdKl7qeDprk5KQ9PtCO00JTVQGhyxapmMuUsJgezpGQSqF5wAKrNm
+dcdHWtFeZDq1IoLMQUS9uMCzzHV5tAfFDX/GnAz2xnPq88RW7nt9LFjzWA8ZsTYf
+/LPjaO+tYim8wQIDAQABo2MwYTAdBgNVHQ4EFgQUIDesPjHcCxXnc1U8kKP6BXGA
+WtUwHwYDVR0jBBgwFoAUIDesPjHcCxXnc1U8kKP6BXGAWtUwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAByhIRpqnRqr
+z/NrI2+LsQawI5PYFyyA8QDxHJveId8DX7OIJDqoXxdl0pqhPSli+2f1ZaLzfTfY
+av1BT2+ALcVY1DDz4RHSUg1YLk6n+1IPeq4hSAf7JVa13tA8tyK7ghjZMCIzX08Z
+Ux9Wz5FlnGSC/jFg2qRjjlZyHQB4N9mLtPp83OEuQBuFJ2LMd6dHcDDpERjrRGpH
+tLFxYnLKgT745h0A/k/HjZLKs46xJBO1y8ZruOoNKklsTkiysGImhRW4KnLJ5iSS
+/V6vzfaCGcDxSSYlbIT1twEN1lRcCuPlPmm7LgV/X12lACg+UR12/dcJnCe94x4E
+QaydT0wsAzT5WSNh69UOrRp0sDJrKtehhQ+7oGeIqTYQNpnmvA3L3MssRvcyw9wB
+ZUdAAw0Jr3jsgy0wZuYIFSbEUWzTlyhkL2Rhp9zzq4f0AW61m+yDb8QXkPnWJPln
+NrKqKYGTfzQNcMSIkcLiDnAmsBeZOze+iXpnuzZSWqlkPQfGhlFRkJ4jm63H15cX
+Hz2OE7zr/HoMJCxXXUbFVIyHDL2i9GbShHr+DVIM9OgBJ6UEPNEN2RZo4vncNCnQ
+zRZe4H1bvaGnh0SUKoLiE2Jy93LBUKrSygHLOtweerXL2dtHad2qi+SQjWXjYBUr
+Y3U3LDo+kQfo7hfVZ/HdrhK7ldhXbz7nMQA=
+-----END PKCS7-----
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index 15cec21afd29..39d4380375e7 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -165,6 +165,13 @@ void SigningTest::setUp()
     setenv("MOZILLA_CERTIFICATE_FOLDER", aTargetPath.toUtf8().getStr(), 1);
 #endif
 
+#ifdef _WIN32
+    // CryptoAPI test certificates
+    osl::File::copy(aSourceDir + "test.p7b", aTargetDir + "test.p7b");
+    OUString caVar("LIBO_TEST_CRYPTOAPI_PKCS7");
+    osl_setEnvironment(caVar.pData, aTargetPath.pData);
+#endif
+
     // Initialize crypto after setting up the environment variables.
     
mxComponentContext.set(comphelper::getComponentContext(getMultiServiceFactory()));
     mxDesktop.set(frame::Desktop::create(mxComponentContext));
@@ -461,7 +468,8 @@ void SigningTest::testODFX509CertificateChain()
     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());
+        // CryptoAPI puts a space after comma, NSS does not...
+        infos[0].Signer->getSubjectName().replaceAll(", ", ","));
 }
 
 void SigningTest::testODFDoubleX509Data()
@@ -530,9 +538,15 @@ void SigningTest::testODFDoubleX509Certificate()
     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));
+    bool const nTemp((nActual == SignatureState::NOTVALIDATED
+                      || nActual == SignatureState::OK
+#if defined(_WIN32)
+                      // oddly BCryptVerifySignature returns 
STATUS_INVALID_SIGNATURE
+                      // while the same succeeds with NSS 
_SGN_VerifyPKCS1DigestInfo
+                      || nActual == SignatureState::BROKEN
+#endif
+                      ));
+    
CPPUNIT_ASSERT_MESSAGE((OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
 nTemp);
     uno::Sequence<security::DocumentSignatureInformation> const infos(
         pObjectShell->ImplAnalyzeSignature(false));
     CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
diff --git 
a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx 
b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
index 75758d8f9ca3..9ec26b6e6486 100644
--- a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
+++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
@@ -792,6 +792,61 @@ HCERTSTORE getCertStoreForIntermediatCerts(
     return store;
 }
 
+static bool CheckUnitTestStore(PCCERT_CHAIN_CONTEXT const pChainContext, DWORD 
ignoreFlags)
+{
+    bool ret = false;
+    OUString const v("LIBO_TEST_CRYPTOAPI_PKCS7");
+    OUString var;
+    if (osl_Process_E_None != osl_getEnvironment(v.pData, &var.pData))
+    {
+        return ret;
+    }
+    if (pChainContext->cChain == 0)
+    {
+        return ret;
+    }
+    PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0];
+    // check if untrusted root is the only problem
+    if (pSimpleChain->TrustStatus.dwErrorStatus & 
~(CERT_TRUST_IS_UNTRUSTED_ROOT | ignoreFlags))
+    {
+        return ret;
+    }
+
+    // leak this store, re-opening is a waste of time in tests
+    static HCERTSTORE const hExtra = CertOpenStore(
+            CERT_STORE_PROV_FILENAME,
+            PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+            NULL,
+            CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
+            OUString(var + "test.p7b").getStr());
+    assert(hExtra != NULL);
+    if (pSimpleChain->cElement < 1)
+    {
+        SAL_WARN("xmlsecurity.xmlsec", "unexpected empty chain");
+        return ret;
+    }
+    PCCERT_CONTEXT const 
pRoot(pSimpleChain->rgpElement[pSimpleChain->cElement-1]->pCertContext);
+    PCCERT_CONTEXT const pIssuerCert = CertFindCertificateInStore(
+            hExtra,
+            PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+            0,
+            CERT_FIND_SUBJECT_NAME,
+            &pRoot->pCertInfo->Subject,
+            NULL);
+    if (pIssuerCert)
+    {
+        // check that it signed itself
+        DWORD flags = CERT_STORE_SIGNATURE_FLAG;
+        BOOL result = CertVerifySubjectCertificateContext(pRoot, pIssuerCert, 
&flags);
+        if (result == TRUE && flags == 0)
+        {
+            ret = true;
+        }
+    }
+    CertFreeCertificateContext(pIssuerCert);
+    return ret;
+}
+
 //We return only valid or invalid, as long as the API documentation expresses
 //explicitly that all validation steps are carried out even if one or several
 //errors occur. See also
@@ -895,7 +950,8 @@ sal_Int32 
SecurityEnvironment_MSCryptImpl::verifyCertificate(
             DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
                 CERT_TRUST_IS_OFFLINE_REVOCATION;
             DWORD otherErrorsMask = ~revocationFlags;
-            if( !(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask))
+            if (!(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask)
+                || CheckUnitTestStore(pChainContext, revocationFlags))
 
             {
                 //No errors except maybe those caused by missing revocation 
information
@@ -924,6 +980,11 @@ sal_Int32 
SecurityEnvironment_MSCryptImpl::verifyCertificate(
                         SAL_INFO("xmlsecurity.xmlsec", "Certificate is 
valid.");
                         validity = css::security::CertificateValidity::VALID;
                     }
+                    else if (CheckUnitTestStore(pChainContext, 0))
+                    {
+                        SAL_INFO("xmlsecurity.xmlsec", "root certificate found 
in extra test store");
+                        validity = css::security::CertificateValidity::VALID;
+                    }
                     else
                     {
                         SAL_INFO("xmlsecurity.xmlsec", "Certificate is 
invalid.");
commit d6ad08715997a35a0cde391d45593812d675b2c0
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Feb 26 17:29:37 2021 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 19:58:42 2022 +0000

    xmlsecurity: add tests for multiple X509Data/X509Certificate
    
    (cherry picked from commit abc697f52fdffa63bd92c26b39df383bc8dbbd78)
    
    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 688d3efc4180..15cec21afd29 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -22,6 +22,7 @@
 #include <com/sun/star/embed/XTransactedObject.hpp>
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
 #include <com/sun/star/io/TempFile.hpp>
 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
@@ -73,6 +74,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.
@@ -109,6 +115,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);
@@ -430,6 +441,105 @@ 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->ImplAnalyzeSignature(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->ImplAnalyzeSignature(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
+void SigningTest::testODFTripleX509Data()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_signed_by_attacker_manipulated_triple.odt");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    SignatureState nActual = pObjectShell->GetDocumentSignatureState();
+    // here, libxmlsec will pick the 1st X509Data but signing key is the 2nd
+    
CPPUNIT_ASSERT_EQUAL_MESSAGE((OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
+                                 SignatureState::BROKEN, nActual);
+    uno::Sequence<security::DocumentSignatureInformation> const infos(
+        pObjectShell->ImplAnalyzeSignature(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
+void SigningTest::testODFMacroDoubleX509Data()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_macros_signed_by_attacker_manipulated.odt");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    SignatureState nActual = pObjectShell->GetScriptingSignatureState();
+    CPPUNIT_ASSERT_MESSAGE(
+        
(OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
+        (nActual == SignatureState::NOTVALIDATED || nActual == 
SignatureState::OK));
+    uno::Sequence<security::DocumentSignatureInformation> const infos(
+        pObjectShell->ImplAnalyzeSignature(true));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
+void SigningTest::testODFDoubleX509Certificate()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "02_doc_signed_by_attacker_manipulated2.odt");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    SignatureState nActual = pObjectShell->GetDocumentSignatureState();
+    CPPUNIT_ASSERT_MESSAGE(
+        
(OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()),
+        (nActual == SignatureState::NOTVALIDATED || nActual == 
SignatureState::OK));
+    uno::Sequence<security::DocumentSignatureInformation> const infos(
+        pObjectShell->ImplAnalyzeSignature(false));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength());
+    CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, 
infos[0].CertificateStatus);
+    CPPUNIT_ASSERT(!infos[0].Signer.is());
+}
+
 void SigningTest::testOOXMLPartial()
 {
     createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx");
commit 54ba1d372ff58c699e1c8bb39594b67eafc4fdd5
Author:     Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>
AuthorDate: Wed Mar 30 19:54:52 2022 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 19:58:12 2022 +0000

    Initialize crypto after setting up the environment variables
    
    Change-Id: I50f313fb2eb6c3ca020f5b2a8f3b69e3e5ea820d

diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index dac23ee71e7a..688d3efc4180 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -142,11 +142,6 @@ void SigningTest::setUp()
 {
     test::BootstrapFixture::setUp();
 
-    
mxComponentContext.set(comphelper::getComponentContext(getMultiServiceFactory()));
-    mxDesktop.set(frame::Desktop::create(mxComponentContext));
-    mxSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext);
-    mxSecurityContext = mxSEInitializer->createSecurityContext(OUString());
-
 #ifndef _WIN32
     // Set up cert8.db in workdir/CppunitTest/
     OUString aSourceDir = m_directories.getURLFromSrc(DATA_DIRECTORY);
@@ -158,6 +153,12 @@ void SigningTest::setUp()
     osl::FileBase::getSystemPathFromFileURL(aTargetDir, aTargetPath);
     setenv("MOZILLA_CERTIFICATE_FOLDER", aTargetPath.toUtf8().getStr(), 1);
 #endif
+
+    // Initialize crypto after setting up the environment variables.
+    
mxComponentContext.set(comphelper::getComponentContext(getMultiServiceFactory()));
+    mxDesktop.set(frame::Desktop::create(mxComponentContext));
+    mxSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext);
+    mxSecurityContext = mxSEInitializer->createSecurityContext(OUString());
 }
 
 void SigningTest::tearDown()
commit ccc3520ba1c66203afc5bb8cac3d60f9d3bbc38a
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Feb 26 17:24:10 2021 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 18:34:59 2022 +0000

    xmlsecurity: add test for timestamps
    
    Change-Id: I6ce64ca7c59639684779144ed0ed8d36c4aca32b
    (cherry picked from commit 6b14fb23cd48733578db3477393e50f08f087c49)

diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx
index 88ced5bce483..41fd1be00e19 100644
--- a/include/sfx2/objsh.hxx
+++ b/include/sfx2/objsh.hxx
@@ -743,7 +743,7 @@ public:
     // configuration items
     SAL_DLLPRIVATE SignatureState ImplGetSignatureState( bool 
bScriptingContent = false );
 
-    SAL_DLLPRIVATE css::uno::Sequence< 
css::security::DocumentSignatureInformation >
+    /*SAL_DLLPRIVATE*/ css::uno::Sequence< 
css::security::DocumentSignatureInformation >
         ImplAnalyzeSignature(
             bool bScriptingContent,
             const css::uno::Reference< 
css::security::XDocumentDigitalSignatures >& xSigner
diff --git 
a/xmlsecurity/qa/unit/signing/data/02_doc_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 4c83cd36928c..dac23ee71e7a 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -72,6 +72,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.
@@ -107,6 +108,7 @@ public:
     CPPUNIT_TEST(testODFBroken);
     CPPUNIT_TEST(testODFNo);
     CPPUNIT_TEST(testODFBroken);
+    CPPUNIT_TEST(testODFUnsignedTimestamp);
     CPPUNIT_TEST(testOOXMLPartial);
     CPPUNIT_TEST(testOOXMLBroken);
     CPPUNIT_TEST(testOOXMLDescription);
@@ -405,6 +407,28 @@ void SigningTest::testODFNo()
     CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::NOSIGNATURES), 
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->ImplAnalyzeSignature(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 c3c48cf14612c09bf18bd30bf4ca105f52802a8d
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Apr 7 17:00:43 2021 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 18:34:59 2022 +0000

    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>
    (cherry picked from commit 8aaa18a8ae094c34009a8f746a4297b328873a90)
    
    Change-Id: I3d319a2f74dbec17b73f1c7bb8f4efe4e335f0ac

diff --git 
a/external/libxmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
 
b/external/libxmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
new file mode 100644
index 000000000000..51607ca6ee73
--- /dev/null
+++ 
b/external/libxmlsec/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/libxmlsec/UnpackedTarball_xmlsec.mk 
b/external/libxmlsec/UnpackedTarball_xmlsec.mk
index edb92b434c65..42f785dd3892 100644
--- a/external/libxmlsec/UnpackedTarball_xmlsec.mk
+++ b/external/libxmlsec/UnpackedTarball_xmlsec.mk
@@ -14,6 +14,7 @@ xmlsec_patches += xmlsec1-vc.patch.1
 xmlsec_patches += xmlsec1-1.2.14_fix_extern_c.patch.1
 # Backport of <https://github.com/lsh123/xmlsec/pull/112>.
 xmlsec_patches += xmlsec1-mscrypto-fix-signing-regression.patch.1
+xmlsec_patches += 
0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
 
 $(eval $(call gb_UnpackedTarball_UnpackedTarball,xmlsec))
 
commit e6e37d826b1bdcfec4d42b9e56b1e0c2c773dcd3
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Mar 30 17:37:31 2021 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Mar 30 18:34:59 2022 +0000

    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)
    
    (cherry picked from commit f6f36865b06b64cd36c71779ed66afe4d515aa06)
    
    Change-Id: I56e39d9609db8fcad50ca1632ff482c1f0a30ff5

diff --git a/include/xmloff/xmlnmspe.hxx b/include/xmloff/xmlnmspe.hxx
index 763338069d5e..2dffcc7ac73d 100644
--- a/include/xmloff/xmlnmspe.hxx
+++ b/include/xmloff/xmlnmspe.hxx
@@ -107,6 +107,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 f09f7cd97386..a7c893bf88b6 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -11,27 +11,1243 @@
 #include "ooxmlsecparser.hxx"
 #include "xmlsignaturehelper.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)
+        {
+        }
+

... etc. - the rest is truncated

Reply via email to