diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2024-09-23 13:58:25 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2024-09-23 17:49:28 +0200 |
commit | 90beea9a9a9ab1a5d4a154704acabadfc83870c9 (patch) | |
tree | fffab1969fd86caa29a76c65b62ecdd8a045b391 | |
parent | 2be38378f1e1b939986403aa766d6783c234ef0a (diff) |
cool#9992 lok doc sign: handle .uno:SignatureCert/Key/Ca view options
The desktop way to sign documents is to manually import a .p12 file into
your Firefox user profile, and then the signing key is available in all
views. The LOK case wants per-view signing certificates, set in a way
similar to the name of the user.
Start implementing this by:
1) Extending initializeForRendering() to have JSON entries for the
signing cert/key/ca chain.
2) Importing the CA chain as trusted certificates, using a new
SfxLokHelper::extractCertificates() + test for this.
3) Marking a certificate as trusted is tricky, extract
SfxLokHelper::addCertificate() from the existing doc_addCertificate()
to do this.
4) Parsing the signing certificate, but just warn if that fails, still
need to connect that to the SfxViewShell later.
Change-Id: I00e40b3cdd68dbe8994f28861dc7b0f578189643
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173806
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r-- | desktop/source/lib/init.cxx | 35 | ||||
-rw-r--r-- | include/sfx2/lokhelper.hxx | 9 | ||||
-rw-r--r-- | sfx2/qa/cppunit/view.cxx | 17 | ||||
-rw-r--r-- | sfx2/source/view/lokhelper.cxx | 69 |
4 files changed, 123 insertions, 7 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index f35a7fdb7757..557336b088f4 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -4699,8 +4699,37 @@ static void doc_initializeForRendering(LibreOfficeKitDocument* pThis, if (pDoc) { doc_iniUnoCommands(); - pDoc->initializeForTiledRendering( - comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments))); + std::vector<beans::PropertyValue> aArgs = jsonToPropertyValuesVector(pArguments); + std::string aSignatureCert; + std::string aSignatureKey; + for (const auto& rArg : aArgs) + { + if (rArg.Name == ".uno:SignatureCert" && rArg.Value.has<OUString>()) + { + aSignatureCert = rArg.Value.get<OUString>().toUtf8(); + } + else if (rArg.Name == ".uno:SignatureKey" && rArg.Value.has<OUString>()) + { + aSignatureKey = rArg.Value.get<OUString>().toUtf8(); + } + else if (rArg.Name == ".uno:SignatureCa" && rArg.Value.has<OUString>()) + { + std::string aSignatureCa; + aSignatureCa = rArg.Value.get<OUString>().toUtf8(); + std::vector<std::string> aCerts = SfxLokHelper::extractCertificates(aSignatureCa); + SfxLokHelper::addCertificates(aCerts); + } + } + if (!aSignatureCert.empty() && !aSignatureKey.empty()) + { + uno::Reference<security::XCertificate> xCertificate = SfxLokHelper::getSigningCertificate(aSignatureCert, aSignatureKey); + if (!xCertificate.is()) + { + SAL_WARN("lok", "doc_initializeForRendering: cert/key didn't result in an XCertificate"); + } + } + + pDoc->initializeForTiledRendering(comphelper::containerToSequence(aArgs)); } } @@ -7281,7 +7310,7 @@ static bool doc_addCertificate(LibreOfficeKitDocument* pThis, std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.getArray()); } - uno::Reference<security::XCertificate> xCertificate = xCertificateCreator->addDERCertificateToTheDatabase(aCertificateSequence, u"TCu,Cu,Tu"_ustr); + uno::Reference<security::XCertificate> xCertificate = SfxLokHelper::addCertificate(xCertificateCreator, aCertificateSequence); if (!xCertificate.is()) return false; diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx index 195f2a7b3dba..bdf7d0816786 100644 --- a/include/sfx2/lokhelper.hxx +++ b/include/sfx2/lokhelper.hxx @@ -12,6 +12,7 @@ #include <com/sun/star/ui/XAcceleratorConfiguration.hpp> #include <com/sun/star/security/XCertificate.hpp> +#include <com/sun/star/xml/crypto/XCertificateCreator.hpp> #include <vcl/IDialogRenderable.hxx> #include <vcl/ITiledRenderable.hxx> @@ -238,7 +239,15 @@ public: static void notifyLog(const std::ostringstream& stream); + /// Extracts base64 data inside begin/end markers. static std::string extractCertificate(const std::string& rCert); + /// Extracts multiple certificates in base64 from inside begin/end markers. + static std::vector<std::string> extractCertificates(const std::string& rCerts); + /// Takes a single CA certificate to add them to the list of trusted certificates. + static css::uno::Reference<css::security::XCertificate> addCertificate(const css::uno::Reference<css::xml::crypto::XCertificateCreator>& xCertificateCreator, const css::uno::Sequence<sal_Int8>& rCert); + /// Takes a CA chain to add them to the list of trusted certificates. + static void addCertificates(const std::vector<std::string>& rCerts); + /// Parses a private key + certificate pair. static css::uno::Reference<css::security::XCertificate> getSigningCertificate(const std::string& rCert, const std::string& rKey); private: diff --git a/sfx2/qa/cppunit/view.cxx b/sfx2/qa/cppunit/view.cxx index 9141e4fba36b..8248a502e012 100644 --- a/sfx2/qa/cppunit/view.cxx +++ b/sfx2/qa/cppunit/view.cxx @@ -19,6 +19,7 @@ #include <svl/intitem.hxx> #include <sfx2/request.hxx> #include <sfx2/bindings.hxx> +#include <sfx2/lokhelper.hxx> using namespace com::sun::star; @@ -61,6 +62,22 @@ CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testReloadPage) CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), nPage); } +CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testLokHelperExtractCertificates) +{ + std::string signatureCa = R"(-----BEGIN CERTIFICATE----- +foo +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +bar +-----END CERTIFICATE-----)"; + + std::vector<std::string> aRet = SfxLokHelper::extractCertificates(signatureCa); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aRet.size()); + CPPUNIT_ASSERT_EQUAL(std::string("\nfoo\n"), aRet[0]); + CPPUNIT_ASSERT_EQUAL(std::string("\nbar\n"), aRet[1]); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx index 8f6c2625002b..136b72357ea2 100644 --- a/sfx2/source/view/lokhelper.cxx +++ b/sfx2/source/view/lokhelper.cxx @@ -828,14 +828,16 @@ void SfxLokHelper::notifyLog(const std::ostringstream& stream) } } -std::string SfxLokHelper::extractCertificate(const std::string & certificate) +namespace +{ +std::string extractCertificateWithOffset(const std::string& certificate, size_t& rOffset) { static constexpr std::string_view header("-----BEGIN CERTIFICATE-----"); static constexpr std::string_view footer("-----END CERTIFICATE-----"); std::string result; - size_t pos1 = certificate.find(header); + size_t pos1 = certificate.find(header, rOffset); if (pos1 == std::string::npos) return result; @@ -844,9 +846,34 @@ std::string SfxLokHelper::extractCertificate(const std::string & certificate) return result; pos1 = pos1 + header.length(); - pos2 = pos2 - pos1; + size_t len = pos2 - pos1; - return certificate.substr(pos1, pos2); + rOffset = pos2; + return certificate.substr(pos1, len); +} +} + +std::string SfxLokHelper::extractCertificate(const std::string & certificate) +{ + size_t nOffset = 0; + return extractCertificateWithOffset(certificate, nOffset); +} + +std::vector<std::string> SfxLokHelper::extractCertificates(const std::string& rCerts) +{ + std::vector<std::string> aRet; + size_t nOffset = 0; + while (true) + { + std::string aNext = extractCertificateWithOffset(rCerts, nOffset); + if (aNext.empty()) + { + break; + } + + aRet.push_back(aNext); + } + return aRet; } namespace @@ -922,6 +949,40 @@ css::uno::Reference<css::security::XCertificate> SfxLokHelper::getSigningCertifi return xCertificate; } +uno::Reference<security::XCertificate> SfxLokHelper::addCertificate( + const css::uno::Reference<css::xml::crypto::XCertificateCreator>& xCertificateCreator, + const css::uno::Sequence<sal_Int8>& rCert) +{ + // Trust arg is handled by CERT_DecodeTrustString(), see 'man certutil'. + return xCertificateCreator->addDERCertificateToTheDatabase(rCert, u"TCu,Cu,Tu"_ustr); +} + +void SfxLokHelper::addCertificates(const std::vector<std::string>& rCerts) +{ + uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); + uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xContext); + uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString()); + if (!xSecurityContext.is()) + { + return; + } + + uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment(); + uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY); + if (!xCertificateCreator.is()) + { + return; + } + + for (const auto& rCert : rCerts) + { + uno::Sequence<sal_Int8> aCertificateSequence; + OUString aBase64OUString = OUString::fromUtf8(rCert); + comphelper::Base64::decode(aCertificateSequence, aBase64OUString); + addCertificate(xCertificateCreator, aCertificateSequence); + } +} + void SfxLokHelper::notifyUpdate(SfxViewShell const* pThisView, int nType) { if (DisableCallbacks::disabled()) |