summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2024-09-23 13:58:25 +0200
committerMiklos Vajna <vmiklos@collabora.com>2024-09-23 17:49:28 +0200
commit90beea9a9a9ab1a5d4a154704acabadfc83870c9 (patch)
treefffab1969fd86caa29a76c65b62ecdd8a045b391
parent2be38378f1e1b939986403aa766d6783c234ef0a (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.cxx35
-rw-r--r--include/sfx2/lokhelper.hxx9
-rw-r--r--sfx2/qa/cppunit/view.cxx17
-rw-r--r--sfx2/source/view/lokhelper.cxx69
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())