Makefile.in | 2 RepositoryExternal.mk | 26 dev/null |binary external/coinmp/UnpackedTarball_coinmp.mk | 2 external/coinmp/configure-exit.patch | 33 external/coinmp/register.patch | 369 ++++++++++ solenv/gbuild/platform/com_GCC_defs.mk | 4 xmlsecurity/CppunitTest_xmlsecurity_pdfsigning.mk | 8 xmlsecurity/CppunitTest_xmlsecurity_signing.mk | 9 xmlsecurity/inc/biginteger.hxx | 11 xmlsecurity/inc/xmlsec-wrapper.h | 4 xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx | 37 - 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/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 | 174 ++++ xmlsecurity/source/component/documentdigitalsignatures.cxx | 13 xmlsecurity/source/helper/xmlsignaturehelper.cxx | 6 xmlsecurity/source/helper/xsecverify.cxx | 6 xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx | 63 + xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx | 92 ++ xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx | 4 xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx | 95 ++ xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx | 4 31 files changed, 1180 insertions(+), 36 deletions(-)
New commits: commit 59e239eb6210e10b75b097810c02f90ab7e0715b 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 Apr 6 20:46:38 2022 +0200 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 928b1d67aed8..385f5121d14c 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -647,8 +647,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 d8173087b2c987cd6a077ccfe893d3a5044461d0 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 Apr 6 20:43:53 2022 +0200 only use X509Data Change-Id: I52e6588f5fac04bb26d77c1f3af470db73e41f72 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 0268fd5a52c11f5701b10c9f9a92681c56254f17) diff --git a/xmlsecurity/inc/xmlsec-wrapper.h b/xmlsecurity/inc/xmlsec-wrapper.h index c060c8bf23b8..2d06dcfdd549 100644 --- a/xmlsecurity/inc/xmlsec-wrapper.h +++ b/xmlsecurity/inc/xmlsec-wrapper.h @@ -43,6 +43,10 @@ #include <xmlsec/nss/app.h> #include <xmlsec/nss/crypto.h> #include <xmlsec/nss/pkikeys.h> +#include <xmlsec/nss/x509.h> +#endif +#ifdef XMLSEC_CRYPTO_MSCRYPTO +#include <xmlsec/mscng/x509.h> #endif #endif diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx index 6b16efd46752..a3a04b5c1241 100644 --- a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx +++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx @@ -229,6 +229,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 xmlSecMSCngKeyDataX509GetKlass()) < 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 e50daa47e868..c4e21d791c2d 100644 --- a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx +++ b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx @@ -244,6 +244,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.get() , pNode ); commit a55ef494199f02bea728c83f37ab3a02690d6b17 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 Apr 6 20:39:55 2022 +0200 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) Change-Id: I4f72900738d1f5313146bbda7320a8f44319ebc8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124420 Tested-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit ee48ce9886d884730a91c695b5d0668c6d90c740) diff --git a/xmlsecurity/CppunitTest_xmlsecurity_signing.mk b/xmlsecurity/CppunitTest_xmlsecurity_signing.mk index 846bd9ba84e9..8255ad3256cf 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 8b4d8a9143b5..1e6b3f4a876e 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 36f1de88b6d3..d2ff4e180493 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -50,6 +50,7 @@ #include <documentsignaturehelper.hxx> #include <xmlsignaturehelper.hxx> #include <documentsignaturemanager.hxx> +#include <biginteger.hxx> #include <certificate.hxx> #include <xsecctl.hxx> #include <sfx2/docfile.hxx> @@ -802,6 +803,21 @@ CPPUNIT_TEST_FIXTURE(SigningTest, testODFDoubleX509Certificate) CPPUNIT_ASSERT(!infos[0].Signer.is()); } +CPPUNIT_TEST_FIXTURE(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 +} + /// Test a typical OOXML where a number of (but not all) streams are signed. void SigningTest::testOOXMLPartial() { diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index fd8648d26c8a..928b1d67aed8 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -647,7 +647,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 adb387d0879e..ad3b12ca3a32 100644 --- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx +++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx @@ -44,6 +44,7 @@ #include <comphelper/ofopxmlhelper.hxx> #include <comphelper/sequence.hxx> #include <tools/diagnose_ex.h> +#include <rtl/ustrbuf.hxx> #include <sal/log.hxx> #include <boost/optional.hpp> @@ -610,7 +611,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 { @@ -643,7 +644,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 edb12d641cb9..c5c253b86f66 100644 --- a/xmlsecurity/source/helper/xsecverify.cxx +++ b/xmlsecurity/source/helper/xsecverify.cxx @@ -272,7 +272,7 @@ void XSecController::setX509Data( auto iter = rX509IssuerSerials.begin(); while (iter != rX509IssuerSerials.end()) { - if (xmlsecurity::EqualDistinguishedNames(issuerName, iter->first) + if (xmlsecurity::EqualDistinguishedNames(issuerName, iter->first, xmlsecurity::COMPAT_2ND) && serialNumber == iter->second) { data.back().X509IssuerName = iter->first; @@ -420,7 +420,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; @@ -443,7 +443,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 b5f779db3029..d3e2c5008258 100644 --- a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx +++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx @@ -32,6 +32,7 @@ #include "oid.hxx" #include <rtl/locale.h> +#include <rtl/ustrbuf.hxx> #include <osl/nlsupport.h> #include <osl/process.h> #include <o3tl/char16_t2wchar_t.hxx> @@ -677,6 +678,67 @@ Sequence<OUString> SAL_CALL X509Certificate_MSCryptImpl::getSupportedServiceName 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; @@ -699,22 +761,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 db9ac25b2cbc..50caf51081f2 100644 --- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx +++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx @@ -29,6 +29,8 @@ #include <comphelper/servicehelper.hxx> #include <cppuhelper/supportsservice.hxx> #include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> #include "x509certificate_nssimpl.hxx" #include <biginteger.hxx> @@ -549,22 +551,103 @@ Sequence<OUString> SAL_CALL X509Certificate_NssImpl::getSupportedServiceNames() 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 a5ae1d94e6a457349acee19dfb963d70abf25fff 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 Apr 6 20:29:49 2022 +0200 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) Change-Id: I4f634cf5da1707fb628e63cd0cdafebdf4fc903f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123838 Tested-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 0f3431026dbff0251efeb0b92be335841a08cc5d) diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index 1fefe339ec2f..da4aad2d956f 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -3432,6 +3432,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)) @@ -3501,6 +3506,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 e9c80db4b8a9..846bd9ba84e9 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 75cd771844a2..2341c315ee35 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 <com/sun/star/security/DocumentSignatureInformation.hpp> @@ -137,6 +141,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 f63e8da729bd..36f1de88b6d3 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -14,6 +14,10 @@ #include <cstdlib> +#ifndef _WIN32 +#include <secoid.h> +#endif + #include <test/bootstrapfixture.hxx> #include <unotest/macros_test.hxx> #include <test/xmltesttools.hxx> @@ -252,6 +256,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 9905c0d0f062c291124c9aa3e190dea0913adb2f 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 Apr 6 20:29:00 2022 +0200 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) Change-Id: I00aa20703e117ebf583c3331b84e966c2cfc78cd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123837 Tested-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 755155498b13c8724831276808c930adba891f5c) diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index 2dc0f7d59eb0..75cd771844a2 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -132,9 +132,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 5330d45b46cc..f63e8da729bd 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -201,9 +201,10 @@ void SigningTest::setUp() OUString aTargetDir = m_directories.getURLFromWorkdir("CppunitTest/xmlsecurity_signing.test.user"); - // Set up cert8.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"); // Make gpg use our own defined setup & keys osl::File::copy(aSourceDir + "pubring.gpg", aTargetDir + "/pubring.gpg"); commit 3e55ecdda3fc7ecb9dec08a5b3260020d4f9a85f 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 Apr 6 20:27:21 2022 +0200 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 "\n"; }' | 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) Change-Id: Ic9865e0b5783211c2128ce0327c4583b7784ff62 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123836 Tested-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 7c622c58cda433964dd73544d56a81a7c88e3f5d) diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index 894aca99a26a..2dc0f7d59eb0 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -12,6 +12,7 @@ #include <comphelper/processfactory.hxx> #include <osl/file.hxx> +#include <osl/process.h> #include <sal/log.hxx> #include <test/bootstrapfixture.hxx> #include <tools/datetime.hxx> @@ -119,15 +120,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 91d1def56230..5330d45b46cc 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -214,8 +214,15 @@ void SigningTest::setUp() 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 OUString mozCertVar("MOZILLA_CERTIFICATE_FOLDER"); osl_setEnvironment(mozCertVar.pData, aTargetPath.pData); +#endif OUString gpgHomeVar("GNUPGHOME"); osl_setEnvironment(gpgHomeVar.pData, aTargetPath.pData); @@ -697,7 +704,8 @@ CPPUNIT_TEST_FIXTURE(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(", ", ",")); } CPPUNIT_TEST_FIXTURE(SigningTest, testODFDoubleX509Data) @@ -766,9 +774,15 @@ CPPUNIT_TEST_FIXTURE(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->GetDocumentSignatureInformation(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 f339c1be480d..09ac700105b5 100644 --- a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx +++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx @@ -774,6 +774,61 @@ static 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 @@ -877,7 +932,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 @@ -906,6 +962,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 8004a416b6ebebadb26eed555de3398d181dec03 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 Apr 6 20:24:10 2022 +0200 xmlsecurity: add tests for multiple X509Data/X509Certificate Change-Id: If50ae8156f81c1053aa8fbfc3148da64bb8e1442 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123438 Tested-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 956c638025e3c0bbe816f710da64769cf5874f4f) 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 ff56ab953531..91d1def56230 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -24,6 +24,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/security/DocumentDigitalSignatures.hpp> #include <com/sun/star/security/XDocumentDigitalSignatures.hpp> #include <com/sun/star/xml/crypto/SEInitializer.hpp> @@ -676,6 +677,105 @@ CPPUNIT_TEST_FIXTURE(SigningTest, testODFUnsignedTimestamp) CPPUNIT_ASSERT_EQUAL(sal_Int32(18183742), infos[0].SignatureTime); } +CPPUNIT_TEST_FIXTURE(SigningTest, testODFX509CertificateChain) +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "signed_with_x509certificate_chain.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + CPPUNIT_ASSERT_MESSAGE( + (OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()), + (nActual == SignatureState::NOTVALIDATED || nActual == SignatureState::OK)); + uno::Sequence<security::DocumentSignatureInformation> const infos( + pObjectShell->GetDocumentSignatureInformation(false)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength()); + // check that the signing certificate was picked, not one of the 2 CA ones + CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::VALID, infos[0].CertificateStatus); + CPPUNIT_ASSERT(infos[0].Signer.is()); + CPPUNIT_ASSERT_EQUAL( + OUString("CN=Xmlsecurity RSA Test example Alice,O=Xmlsecurity RSA Test,ST=England,C=UK"), + infos[0].Signer->getSubjectName()); +} + +CPPUNIT_TEST_FIXTURE(SigningTest, testODFDoubleX509Data) +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "02_doc_signed_by_attacker_manipulated.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + CPPUNIT_ASSERT_MESSAGE( + (OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()), + (nActual == SignatureState::NOTVALIDATED || nActual == SignatureState::OK)); + uno::Sequence<security::DocumentSignatureInformation> const infos( + pObjectShell->GetDocumentSignatureInformation(false)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength()); + CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, infos[0].CertificateStatus); + CPPUNIT_ASSERT(!infos[0].Signer.is()); +} + +CPPUNIT_TEST_FIXTURE(SigningTest, testODFTripleX509Data) +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "02_doc_signed_by_attacker_manipulated_triple.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + // here, libxmlsec will pick the 1st X509Data but signing key is the 2nd + CPPUNIT_ASSERT_EQUAL_MESSAGE((OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()), + SignatureState::BROKEN, nActual); + uno::Sequence<security::DocumentSignatureInformation> const infos( + pObjectShell->GetDocumentSignatureInformation(false)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength()); + CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, infos[0].CertificateStatus); + CPPUNIT_ASSERT(!infos[0].Signer.is()); +} + +CPPUNIT_TEST_FIXTURE(SigningTest, testODFMacroDoubleX509Data) +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "02_doc_macros_signed_by_attacker_manipulated.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + SignatureState nActual = pObjectShell->GetScriptingSignatureState(); + CPPUNIT_ASSERT_MESSAGE( + (OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()), + (nActual == SignatureState::NOTVALIDATED || nActual == SignatureState::OK)); + uno::Sequence<security::DocumentSignatureInformation> const infos( + pObjectShell->GetDocumentSignatureInformation(true)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength()); + CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, infos[0].CertificateStatus); + CPPUNIT_ASSERT(!infos[0].Signer.is()); +} + +CPPUNIT_TEST_FIXTURE(SigningTest, testODFDoubleX509Certificate) +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "02_doc_signed_by_attacker_manipulated2.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + CPPUNIT_ASSERT_MESSAGE( + (OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()), + (nActual == SignatureState::NOTVALIDATED || nActual == SignatureState::OK)); + uno::Sequence<security::DocumentSignatureInformation> const infos( + pObjectShell->GetDocumentSignatureInformation(false)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength()); + CPPUNIT_ASSERT_EQUAL(security::CertificateValidity::INVALID, infos[0].CertificateStatus); + CPPUNIT_ASSERT(!infos[0].Signer.is()); +} + /// Test a typical OOXML where a number of (but not all) streams are signed. void SigningTest::testOOXMLPartial() { commit 068bf3693ff57acdf87b480ceddbf17edfcddb0c 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 Apr 6 20:20:36 2022 +0200 xmlsecurity: add test for timestamps Change-Id: I6ce64ca7c59639684779144ed0ed8d36c4aca32b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123437 Tested-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 3aabce61782c9561a0e1680fe1ecc58ac87be0ee) 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 1853b5eead8c..ff56ab953531 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -62,6 +62,7 @@ char const DATA_DIRECTORY[] = "/xmlsecurity/qa/unit/signing/data/"; /// Testsuite for the document signing feature. class SigningTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools { +protected: uno::Reference<uno::XComponentContext> mxComponentContext; uno::Reference<lang::XComponent> mxComponent; uno::Reference<xml::crypto::XSEInitializer> mxSEInitializer; @@ -178,7 +179,7 @@ public: CPPUNIT_TEST(testPreserveMacroTemplateSignature10); CPPUNIT_TEST_SUITE_END(); -private: +protected: void createDoc(const OUString& rURL); void createCalc(const OUString& rURL); uno::Reference<security::XCertificate> @@ -653,6 +654,29 @@ void SigningTest::testODFNo() static_cast<int>(pObjectShell->GetDocumentSignatureState())); } +// document has one signed timestamp and one unsigned timestamp +CPPUNIT_TEST_FIXTURE(SigningTest, testODFUnsignedTimestamp) +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "02_doc_signed_by_trusted_person_manipulated.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + CPPUNIT_ASSERT_MESSAGE( + (OString::number(/*o3tl::underlyingEnumValue(*/(int)nActual/*)*/).getStr()), + (nActual == SignatureState::NOTVALIDATED || nActual == SignatureState::OK)); + uno::Sequence<security::DocumentSignatureInformation> const infos( + pObjectShell->GetDocumentSignatureInformation(false)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), infos.getLength()); + // was: 66666666 + CPPUNIT_ASSERT_EQUAL(sal_Int32(20210126), infos[0].SignatureDate); + // was: 0 + CPPUNIT_ASSERT_EQUAL(sal_Int32(18183742), infos[0].SignatureTime); +} + +/// Test a typical OOXML where a number of (but not all) streams are signed. void SigningTest::testOOXMLPartial() { createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial.docx"); commit 0537731048d79f77b5557a1829836fb2bd0031b5 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Thu Mar 11 20:23:31 2021 +0000 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Wed Apr 6 19:50:20 2022 +0200 do same set error state as ReadAndVerifySignature does this function is nearly exactly the same as ReadAndVerifySignature except it doesn't set error-state on exception during parse Change-Id: Ife881f639a11d3185920ca62cc2cd22812fae36d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112366 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112412 (cherry picked from commit 52a23d595b820cab27d76d0e7c129f2757c762d6) (cherry picked from commit ed6db8f42484f135137939cf38dc40fc3f0913b1) diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx index 9f35130df47c..adb387d0879e 100644 --- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx +++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx @@ -408,6 +408,7 @@ bool XMLSignatureHelper::ReadAndVerifySignatureStorageStream(const css::uno::Ref catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper"); + mbError = true; } mpXSecController->releaseSignatureReader(); commit b3ae92e082c3821082a30545a46000841312a9a1 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Wed Jun 17 14:54:06 2020 +0100 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Wed Apr 6 19:05:16 2022 +0200 allow building as root inside a container without complaint add a check for $container Change-Id: Ib6921c6d771622fb5f4acb82d10aa6fb34e1bbac Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96538 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit e19b67dcf5e987e58ce4252d8d1c8313d111df85) diff --git a/Makefile.in b/Makefile.in index c3724534e530..9fd266106cb3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -60,7 +60,7 @@ else # MAKE_RESTARTS all: build check-if-root: - @if test ! `uname` = 'Haiku' -a `id -u` = 0 && ! grep -q 'lxc\|docker' /proc/self/cgroup && ! grep -q 'libpod_parent' /proc/self/cgroup; then \ + @if test ! `uname` = 'Haiku' -a `id -u` = 0 && test -z $$container && ! grep -q 'lxc\|docker' /proc/self/cgroup && ! grep -q 'libpod_parent' /proc/self/cgroup; then \ echo; \ echo 'Building LibreOffice as root is a very bad idea, use a regular user.'; \ echo; \ commit ac7b16f82a9a48e90583eee5922de7368f743654 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Sat Jan 4 14:52:40 2020 +0000 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Wed Apr 6 19:04:15 2022 +0200 allow root under podman Change-Id: I66dc674aab8dc86c95495754400c5e64b2583599 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86223 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit 6fbfb54086c10f0107dc7026eaeffd177eda56c3) diff --git a/Makefile.in b/Makefile.in index 393e94fda331..c3724534e530 100644 --- a/Makefile.in +++ b/Makefile.in @@ -60,7 +60,7 @@ else # MAKE_RESTARTS all: build check-if-root: - @if test ! `uname` = 'Haiku' -a `id -u` = 0 && ! grep -q 'lxc\|docker' /proc/self/cgroup; then \ + @if test ! `uname` = 'Haiku' -a `id -u` = 0 && ! grep -q 'lxc\|docker' /proc/self/cgroup && ! grep -q 'libpod_parent' /proc/self/cgroup; then \ echo; \ echo 'Building LibreOffice as root is a very bad idea, use a regular user.'; \ echo; \ commit 35adbb0b38fb0a96e29e651cf5c701ddb2074c76 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri Nov 12 17:23:48 2021 +0100 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Wed Apr 6 18:52:01 2022 +0200 Revert "Comment out failing unit test" This reverts commit df1033d3e5692ea11dc2ac9ea08e8a245996dab1. diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index 2ee0f54e2832..894aca99a26a 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -454,9 +454,8 @@ void PDFSigningTest::testBadCertP1() // - Expected: 0 (SecurityOperationStatus_UNKNOWN) // - Actual : 1 (SecurityOperationStatus_OPERATION_SUCCEEDED) // i.e. annotation after a P1 signature was not considered as a bad modification. - // FIXME This fails for some reason... - //CPPUNIT_ASSERT_EQUAL(xml::crypto::SecurityOperationStatus::SecurityOperationStatus_UNKNOWN, - // rInformation.nStatus); + CPPUNIT_ASSERT_EQUAL(xml::crypto::SecurityOperationStatus::SecurityOperationStatus_UNKNOWN, + rInformation.nStatus); } /// Test writing a PAdES signature. commit f9d8a81f7e93c816a55d5ab04c427f7f6a47c460 Author: Stephan Bergmann <sberg...@redhat.com> AuthorDate: Thu Oct 1 11:50:40 2020 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Wed Apr 6 18:52:01 2022 +0200 exteranl/coinmp: Fix build with recent GCC 11 trunk It had started to fail for me now with > ~/gcc/trunk/inst/bin/g++ -DHAVE_CONFIG_H -I. -I. -O -MT CoinFinite.lo -MD -MP -MF .deps/CoinFinite.Tpo -c CoinFinite.cpp -fPIC -DPIC -o .libs/CoinFinite.o > CoinFinite.cpp: In function 'bool CoinFinite(double)': > CoinFinite.cpp:38:19: error: 'DBL_MAX' was not declared in this scope > 38 | return val != DBL_MAX && val != -DBL_MAX; > | ^~~~~~~ > CoinFinite.cpp:8:1: note: 'DBL_MAX' is defined in header '<cfloat>'; did you forget to '#include <cfloat>'? > 7 | #include "CoinUtilsConfig.h" > +++ |+#include <cfloat> > 8 | because of a missing -DCOINUTILS_BUILD. Which in turn was caused by workdir/UnpackedTarball/coinmp/CoinUtils/configure (see workdir/UnpackedTarball/coinmp/CoinUtils/config.log), which first tries to determine an ac_declaration that would apparently be a suitable declaration of `exit` without actually including <stdlib.h> in a C++ file. It settles on > configure:3551: ~/gcc/trunk/inst/bin/g++ -c -g -O2 conftest.cc >&5 > conftest.cc:15:17: warning: 'void std::exit(int)' has not been declared within 'std' > 15 | extern "C" void std::exit (int) throw (); using std::exit; > | ^~~ > <built-in>: note: only here as a 'friend' > configure:3557: $? = 0 (which generates a warning, but no error with the given g++ invocation). The determined ac_declaration value is then included in confdefs.h, causing the later > configure:4014: ~/gcc/trunk/inst/bin/g++ -o conftest -O3 -pipe -DNDEBUG -pedantic-errors -Wparentheses -Wreturn-type -Wcast-qual -Wall -Wpointer-arith -Wwrite-strings -Wconversion -Wno-unknown-pragmas -Wno-long-long -DCOINUTILS_BUILD -Wl,-z,origin -Wl,-rpath,\$$ORIGIN conftest.cc >&5 > conftest.cc:15:17: error: 'void std::exit(int)' has not been declared within 'std' > 15 | extern "C" void std::exit (int) throw (); using std::exit; > | ^~~ > <built-in>: note: only here as a 'friend' > configure:4020: $? = 1 > configure: failed program was: > | /* confdefs.h. */ > | > | #define PACKAGE_NAME "CoinUtils" > | #define PACKAGE_TARNAME "coinutils" > | #define PACKAGE_VERSION "2.9.11" > | #define PACKAGE_STRING "CoinUtils 2.9.11" > | #define PACKAGE_BUGREPORT "http://projects.coin-or.org/CoinUtils" > | #define COINUTILS_VERSION "2.9.11" > | #define COINUTILS_VERSION_MAJOR 2 > | #define COINUTILS_VERSION_MINOR 9 > | #define COINUTILS_VERSION_RELEASE 11 > | #define COIN_COINUTILS_VERBOSITY 0 > | #define COIN_COINUTILS_CHECKLEVEL 0 > | #ifdef __cplusplus > | extern "C" void std::exit (int) throw (); using std::exit; > | #endif > | /* end confdefs.h. */ > | > | int > | main () > | { > | int i=0; i++; > | ; > | return 0; > | } > configure:4045: WARNING: The flags CXXFLAGS="-O3 -pipe -DNDEBUG -pedantic-errors -Wparentheses -Wreturn-type -Wcast-qual -Wall -Wpointer-arith -Wwrite-strings -Wconversion -Wno-unknown-pragmas -Wno-long-long -DCOINUTILS_BUILD" do not work. I will now just try '-O', but you might want to set CXXFLAGS manually. to fail, because its g++ invocation including -pedantic-errors turns that > 'void std::exit(int)' has not been declared within 'std' warning into an error. There were similar build failures in the Cgl, > ~/gcc/trunk/inst/bin/g++ -DHAVE_CONFIG_H -I. -I. -I~/lo/core/workdir/UnpackedTarball/coinmp/CoinUtils/src -DCOIN_HAS_CLP -O -MT ClpCholeskyDense.lo -MD -MP -MF .deps/ClpCholeskyDense.Tpo -c ClpCholeskyDense.cpp -fPIC -DPIC -o .libs/ClpCholeskyDense.o > In file included from ClpCholeskyDense.cpp:11: > ClpHelperFunctions.hpp:16:4: error: #error "don't have header file for math" > 16 | # error "don't have header file for math" > | ^~~~~ > In file included from ClpCholeskyDense.cpp:11: > ClpHelperFunctions.hpp: In function 'double CoinSqrt(double)': > ClpHelperFunctions.hpp:81:13: error: 'sqrt' was not declared in this scope > 81 | return sqrt(x); > | ^~~~ and Clp, > ~/gcc/trunk/inst/bin/g++ -DHAVE_CONFIG_H -I. -I. -I.. -I./.. -I./../CglGomory -I~/lo/core/workdir/UnpackedTarball/coinmp/CoinUtils/src -I~/lo/core/workdir/UnpackedTarball/coinmp/Osi/src/Osi -I~/lo/core/workdir/UnpackedTarball/coinmp/CoinUtils/src -I~/lo/core/workdir/UnpackedTarball/coinmp/Clp/src/OsiClp -I~/lo/core/workdir/UnpackedTarball/coinmp/Clp/src -I~/lo/core/workdir/UnpackedTarball/coinmp/CoinUtils/src -I~/lo/core/workdir/UnpackedTarball/coinmp/Osi/src/Osi -O -MT CglLandPValidator.lo -MD -MP -MF .deps/CglLandPValidator.Tpo -c CglLandPValidator.cpp -fPIC -DPIC -o .libs/CglLandPValidator.o > CglLandPValidator.cpp: In member function 'int LAP::Validator::cleanCut(OsiRowCut&, const double*, const OsiSolverInterface&, const CglParam&, const double*, const double*)': > CglLandPValidator.cpp:66:22: error: 'fabs' was not declared in this scope; did you mean 'labs'? > 66 | double val = fabs(elems[i]); > | ^~~~ > | labs > CglLandPValidator.cpp: In member function 'int LAP::Validator::cleanCut2(OsiRowCut&, const double*, const OsiSolverInterface&, const CglParam&, const double*, const double*)': > CglLandPValidator.cpp:189:23: error: 'fabs' was not declared in this scope; did you mean 'labs'? > 189 | double smallest = fabs(rhs); > | ^~~~ > | labs subdirectories, and which happened to get solved by the same approach of removing problematic ac_declaration values from configure. I am not sure what all that magic of determining that ac_declaration value is supposed to be good for. There appears to be no trace of it in the corresponding configure.ac sources, so it likely was automatically added by some dated autotools (all three configure files mention "Generated by GNU Autoconf 2.59"). At least on a cursory look, the determined ac_declaration appears to only be used in configure itself, and not leak into the actual coinmp build stage, so dropping the problematic ac_declaration values is hopefully harmless. These three subdirectories were all that failed for me, but there might still be silent issues in other subdirectories when a problematic ac_declaration value would negatively affect other configure checks. (An alternative approach could be to regenerate all the configure files from their configure.ac sources with a recent autotools. But at least some of the existing external/coinmp/*.patch* already change such configure files, which would need to be adapted.) Change-Id: I0a33b0f654800e8288d3ca28e26a64efc23a3f6b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103756 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sberg...@redhat.com> (cherry picked from commit 762aacc4e055fffbc605be81f66f2274dccb4be8) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114999 Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 802b76340082e817efe67a5be4a021cb998a28a2) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115502 Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de> Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> (cherry picked from commit 14b706520cc45a5b4b20da58deda5802384270f0) diff --git a/external/coinmp/UnpackedTarball_coinmp.mk b/external/coinmp/UnpackedTarball_coinmp.mk index c1f3df9866b1..a918effb1203 100644 --- a/external/coinmp/UnpackedTarball_coinmp.mk +++ b/external/coinmp/UnpackedTarball_coinmp.mk @@ -41,6 +41,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,coinmp,\ external/coinmp/rpath.patch \ external/coinmp/libtool.patch \ external/coinmp/register.patch \ + external/coinmp/configure-exit.patch \ )) # vim: set noet sw=4 ts=4: diff --git a/external/coinmp/configure-exit.patch b/external/coinmp/configure-exit.patch new file mode 100644 index 000000000000..0a81b8073fd2 --- /dev/null +++ b/external/coinmp/configure-exit.patch @@ -0,0 +1,33 @@ +--- Cgl/configure ++++ Cgl/configure +@@ -3501,8 +3501,6 @@ + fi + for ac_declaration in \ + '' \ +- 'extern "C" void std::exit (int) throw (); using std::exit;' \ +- 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +--- Clp/configure ++++ Clp/configure +@@ -3528,8 +3528,6 @@ + fi + for ac_declaration in \ + '' \ +- 'extern "C" void std::exit (int) throw (); using std::exit;' \ +- 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +--- CoinUtils/configure ++++ CoinUtils/configure +@@ -3527,8 +3527,6 @@ + fi + for ac_declaration in \ + '' \ +- 'extern "C" void std::exit (int) throw (); using std::exit;' \ +- 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' commit c967ff04fcb8001c194eea1157b247751238068d Author: Stephan Bergmann <sberg...@redhat.com> AuthorDate: Mon Jul 20 16:23:18 2020 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Wed Apr 6 18:52:01 2022 +0200 external/coinmp: C++17 no longer supports "register" ...and GCC 11 trunk g++ now defaults to C++17, so compilation started to fail with that compiler Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99082 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sberg...@redhat.com> (cherry picked from commit ad607d898f9826c6fa144783c93541a10ad4740c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114998 Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 656085bf2757437a088058871573385ff45f8ef5) Change-Id: I792e4c7ff59ad88e5571163d5b2362fdb349667d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115501 Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de> Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> (cherry picked from commit 841534cb8404a379207165aa5dc4496d6cb98319) diff --git a/external/coinmp/UnpackedTarball_coinmp.mk b/external/coinmp/UnpackedTarball_coinmp.mk index 35cfbfcdbae8..c1f3df9866b1 100644 --- a/external/coinmp/UnpackedTarball_coinmp.mk +++ b/external/coinmp/UnpackedTarball_coinmp.mk @@ -40,6 +40,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,coinmp,\ external/coinmp/ubsan.patch.0 \ external/coinmp/rpath.patch \ external/coinmp/libtool.patch \ + external/coinmp/register.patch \ )) # vim: set noet sw=4 ts=4: diff --git a/external/coinmp/register.patch b/external/coinmp/register.patch new file mode 100644 index 000000000000..cf4ca4d06c01 --- /dev/null +++ b/external/coinmp/register.patch @@ -0,0 +1,369 @@ +--- CoinUtils/src/CoinHelperFunctions.hpp ++++ CoinUtils/src/CoinHelperFunctions.hpp +@@ -41,7 +41,7 @@ + handled correctly. */ + + template <class T> inline void +-CoinCopyN(register const T* from, const int size, register T* to) ++CoinCopyN(const T* from, const int size, T* to) + { + if (size == 0 || from == to) + return; +@@ -52,10 +52,10 @@ + "CoinCopyN", ""); + #endif + +- register int n = (size + 7) / 8; ++ int n = (size + 7) / 8; + if (to > from) { +- register const T* downfrom = from + size; +- register T* downto = to + size; ++ const T* downfrom = from + size; ++ T* downto = to + size; + // Use Duff's device to copy + switch (size % 8) { + case 0: do{ *--downto = *--downfrom; +@@ -99,7 +99,7 @@ + the difference down to int. -- lh, 100823 -- + */ + template <class T> inline void +-CoinCopy(register const T* first, register const T* last, register T* to) ++CoinCopy(const T* first, const T* last, T* to) + { + CoinCopyN(first, static_cast<int>(last-first), to); + } +@@ -114,7 +114,7 @@ + Note JJF - the speed claim seems to be false on IA32 so I have added + CoinMemcpyN which can be used for atomic data */ + template <class T> inline void +-CoinDisjointCopyN(register const T* from, const int size, register T* to) ++CoinDisjointCopyN(const T* from, const int size, T* to) + { + #ifndef _MSC_VER + if (size == 0 || from == to) +@@ -135,7 +135,7 @@ + throw CoinError("overlapping arrays", "CoinDisjointCopyN", ""); + #endif + +- for (register int n = size / 8; n > 0; --n, from += 8, to += 8) { ++ for (int n = size / 8; n > 0; --n, from += 8, to += 8) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; +@@ -167,8 +167,8 @@ + are copied at a time. The source array is given by its first and "after + last" entry; the target array is given by its first entry. */ + template <class T> inline void +-CoinDisjointCopy(register const T* first, register const T* last, +- register T* to) ++CoinDisjointCopy(const T* first, const T* last, ++ T* to) + { + CoinDisjointCopyN(first, static_cast<int>(last - first), to); + } +@@ -256,7 +256,7 @@ + alternative coding if USE_MEMCPY defined*/ + #ifndef COIN_USE_RESTRICT + template <class T> inline void +-CoinMemcpyN(register const T* from, const int size, register T* to) ++CoinMemcpyN(const T* from, const int size, T* to) + { + #ifndef _MSC_VER + #ifdef USE_MEMCPY +@@ -296,7 +296,7 @@ + throw CoinError("overlapping arrays", "CoinMemcpyN", ""); + #endif + +- for (register int n = size / 8; n > 0; --n, from += 8, to += 8) { ++ for (int n = size / 8; n > 0; --n, from += 8, to += 8) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; +@@ -343,8 +343,8 @@ + are copied at a time. The source array is given by its first and "after + last" entry; the target array is given by its first entry. */ + template <class T> inline void +-CoinMemcpy(register const T* first, register const T* last, +- register T* to) ++CoinMemcpy(const T* first, const T* last, ++ T* to) + { + CoinMemcpyN(first, static_cast<int>(last - first), to); + } +@@ -358,7 +358,7 @@ + Note JJF - the speed claim seems to be false on IA32 so I have added + CoinZero to allow for memset. */ + template <class T> inline void +-CoinFillN(register T* to, const int size, register const T value) ++CoinFillN(T* to, const int size, const T value) + { + if (size == 0) + return; +@@ -369,7 +369,7 @@ + "CoinFillN", ""); + #endif + #if 1 +- for (register int n = size / 8; n > 0; --n, to += 8) { ++ for (int n = size / 8; n > 0; --n, to += 8) { + to[0] = value; + to[1] = value; + to[2] = value; +@@ -413,7 +413,7 @@ + entries are filled at a time. The array is given by its first and "after + last" entry. */ + template <class T> inline void +-CoinFill(register T* first, register T* last, const T value) ++CoinFill(T* first, T* last, const T value) + { + CoinFillN(first, last - first, value); + } +@@ -427,7 +427,7 @@ + Note JJF - the speed claim seems to be false on IA32 so I have allowed + for memset as an alternative */ + template <class T> inline void +-CoinZeroN(register T* to, const int size) ++CoinZeroN(T* to, const int size) + { + #ifdef USE_MEMCPY + // Use memset - seems faster on Intel with gcc +@@ -448,7 +448,7 @@ + "CoinZeroN", ""); + #endif + #if 1 +- for (register int n = size / 8; n > 0; --n, to += 8) { ++ for (int n = size / 8; n > 0; --n, to += 8) { + to[0] = 0; + to[1] = 0; + to[2] = 0; +@@ -519,7 +519,7 @@ + entries are filled at a time. The array is given by its first and "after + last" entry. */ + template <class T> inline void +-CoinZero(register T* first, register T* last) ++CoinZero(T* first, T* last) + { + CoinZeroN(first, last - first); + } +@@ -545,7 +545,7 @@ + This function was introduced because for some reason compiler tend to + handle the <code>max()</code> function differently. */ + template <class T> inline T +-CoinMax(register const T x1, register const T x2) ++CoinMax(const T x1, const T x2) + { + return (x1 > x2) ? x1 : x2; + } +@@ -556,7 +556,7 @@ + This function was introduced because for some reason compiler tend to + handle the min() function differently. */ + template <class T> inline T +-CoinMin(register const T x1, register const T x2) ++CoinMin(const T x1, const T x2) + { + return (x1 < x2) ? x1 : x2; + } +@@ -578,7 +578,7 @@ + according to operator<. The array is given by a pointer to its first entry + and by its size. */ + template <class T> inline bool +-CoinIsSorted(register const T* first, const int size) ++CoinIsSorted(const T* first, const int size) + { + if (size == 0) + return true; +@@ -590,7 +590,7 @@ + #if 1 + // size1 is the number of comparisons to be made + const int size1 = size - 1; +- for (register int n = size1 / 8; n > 0; --n, first += 8) { ++ for (int n = size1 / 8; n > 0; --n, first += 8) { + if (first[8] < first[7]) return false; + if (first[7] < first[6]) return false; + if (first[6] < first[5]) return false; +@@ -627,7 +627,7 @@ + according to operator<. The array is given by its first and "after + last" entry. */ + template <class T> inline bool +-CoinIsSorted(register const T* first, register const T* last) ++CoinIsSorted(const T* first, const T* last) + { + return CoinIsSorted(first, static_cast<int>(last - first)); + } +@@ -638,7 +638,7 @@ + etc. For speed 8 entries are filled at a time. The array is given by a + pointer to its first entry and its size. */ + template <class T> inline void +-CoinIotaN(register T* first, const int size, register T init) ++CoinIotaN(T* first, const int size, T init) + { + if (size == 0) + return; +@@ -648,7 +648,7 @@ + throw CoinError("negative number of entries", "CoinIotaN", ""); + #endif + #if 1 +- for (register int n = size / 8; n > 0; --n, first += 8, init += 8) { ++ for (int n = size / 8; n > 0; --n, first += 8, init += 8) { + first[0] = init; + first[1] = init + 1; + first[2] = init + 2; +@@ -706,7 +706,7 @@ + integer array specified by the last two arguments (again, first and "after + last" entry). */ + template <class T> inline T * +-CoinDeleteEntriesFromArray(register T * arrayFirst, register T * arrayLast, ++CoinDeleteEntriesFromArray(T * arrayFirst, T * arrayLast, + const int * firstDelPos, const int * lastDelPos) + { + int delNum = static_cast<int>(lastDelPos - firstDelPos); +--- CoinUtils/src/CoinModelUseful2.cpp ++++ CoinUtils/src/CoinModelUseful2.cpp +@@ -917,8 +917,8 @@ + + int position=0; + int nEof=0; // Number of time send of string +- register int yystate; +- register int yyn; ++ int yystate; ++ int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; ... etc. - the rest is truncated