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