diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2018-12-31 12:27:39 +0100 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2019-01-01 09:53:20 +0100 |
commit | a8cb7cf68ff661b502e7c006fe4330098b5b0944 (patch) | |
tree | 46d06e2508f830b7e85c012eabc7891c52598814 /desktop | |
parent | 588dc2808c79da714cc107548631a65a7ddfe5d0 (diff) |
lok: add signDocument to "Office" iface - to sign not opened docs.
LOKit function "signDocument" can sign document without the need
to open them. This is useful to sign PDF documents after they are
created from a currently opened (ODF, DOCX) document.
This adds DocumentDigner to sfx2, which could also be used in
desktop LibreOffice without opening them and in further tests.
Change-Id: Id6f242e817f594aa672f94f9c6f9b34e4035d46a
Reviewed-on: https://gerrit.libreoffice.org/65767
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'desktop')
-rw-r--r-- | desktop/qa/desktop_lib/test_desktop_lib.cxx | 63 | ||||
-rw-r--r-- | desktop/source/lib/init.cxx | 78 |
2 files changed, 141 insertions, 0 deletions
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 740e2d4fdecf..55d8c6761420 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -126,6 +126,7 @@ public: void testInsertCertificate_DER_ODT(); void testInsertCertificate_PEM_ODT(); void testInsertCertificate_PEM_DOCX(); + void testSignDocument_PEM_PDF(); void testABI(); CPPUNIT_TEST_SUITE(DesktopLOKTest); @@ -174,6 +175,7 @@ public: CPPUNIT_TEST(testInsertCertificate_DER_ODT); CPPUNIT_TEST(testInsertCertificate_PEM_ODT); CPPUNIT_TEST(testInsertCertificate_PEM_DOCX); + CPPUNIT_TEST(testSignDocument_PEM_PDF); CPPUNIT_TEST(testABI); CPPUNIT_TEST_SUITE_END(); @@ -2485,6 +2487,66 @@ void DesktopLOKTest::testInsertCertificate_PEM_DOCX() comphelper::LibreOfficeKit::setActive(false); } +void DesktopLOKTest::testSignDocument_PEM_PDF() +{ + comphelper::LibreOfficeKit::setActive(); + + // Load the document, save it into a temp file and load that file again + LibLODocument_Impl* pDocument = loadDoc("blank_text.odt"); + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(mxComponent.is()); + pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}"); + Scheduler::ProcessEventsToIdle(); + + std::vector<unsigned char> aCertificate; + std::vector<unsigned char> aPrivateKey; + + { + readFileIntoByteVector("test-cert-chain-1.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + { + readFileIntoByteVector("test-cert-chain-2.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + { + readFileIntoByteVector("test-cert-chain-3.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + CPPUNIT_ASSERT(pDocument->pClass->saveAs(pDocument, aTempFile.GetURL().toUtf8().getStr(), "pdf", nullptr)); + + closeDoc(); + + Scheduler::ProcessEventsToIdle(); + + readFileIntoByteVector("test-cert-signing.pem", aCertificate); + readFileIntoByteVector("test-PK-signing.pem", aPrivateKey); + + LibLibreOffice_Impl aOffice; + bool bResult = aOffice.m_pOfficeClass->signDocument(&aOffice, aTempFile.GetURL().toUtf8().getStr(), + aCertificate.data(), int(aCertificate.size()), + aPrivateKey.data(), int(aPrivateKey.size())); + + CPPUNIT_ASSERT(bResult); + + comphelper::LibreOfficeKit::setActive(false); +} + namespace { constexpr size_t classOffset(int i) @@ -2513,6 +2575,7 @@ void DesktopLOKTest::testABI() CPPUNIT_ASSERT_EQUAL(classOffset(8), offsetof(struct _LibreOfficeKitClass, setDocumentPassword)); CPPUNIT_ASSERT_EQUAL(classOffset(9), offsetof(struct _LibreOfficeKitClass, getVersionInfo)); CPPUNIT_ASSERT_EQUAL(classOffset(10), offsetof(struct _LibreOfficeKitClass, runMacro)); + CPPUNIT_ASSERT_EQUAL(classOffset(11), offsetof(struct _LibreOfficeKitClass, signDocument)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct _LibreOfficeKitDocumentClass, destroy)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct _LibreOfficeKitDocumentClass, saveAs)); diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 0537d3808d61..0ec67bc6618f 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -94,6 +94,7 @@ #include <sfx2/msgpool.hxx> #include <sfx2/dispatch.hxx> #include <sfx2/lokhelper.hxx> +#include <sfx2/DocumentSigner.hxx> #include <svx/dialmgr.hxx> #include <svx/dialogs.hrc> #include <svx/strings.hrc> @@ -1423,6 +1424,13 @@ static void lo_setDocumentPassword(LibreOfficeKit* pThis, static char* lo_getVersionInfo(LibreOfficeKit* pThis); static int lo_runMacro (LibreOfficeKit* pThis, const char* pURL); +static bool lo_signDocument(LibreOfficeKit* pThis, + const char* pUrl, + const unsigned char* pCertificateBinary, + const int nCertificateBinarySize, + const unsigned char* pPrivateKeyBinary, + const int nPrivateKeyBinarySize); + LibLibreOffice_Impl::LibLibreOffice_Impl() : m_pOfficeClass( gOfficeClass.lock() ) , maThread(nullptr) @@ -1445,6 +1453,7 @@ LibLibreOffice_Impl::LibLibreOffice_Impl() m_pOfficeClass->setDocumentPassword = lo_setDocumentPassword; m_pOfficeClass->getVersionInfo = lo_getVersionInfo; m_pOfficeClass->runMacro = lo_runMacro; + m_pOfficeClass->signDocument = lo_signDocument; gOfficeClass = m_pOfficeClass; } @@ -1672,6 +1681,75 @@ static int lo_runMacro(LibreOfficeKit* pThis, const char *pURL) return false; } +static bool lo_signDocument(LibreOfficeKit* /*pThis*/, + const char* pURL, + const unsigned char* pCertificateBinary, + const int nCertificateBinarySize, + const unsigned char* pPrivateKeyBinary, + const int nPrivateKeyBinarySize) +{ + OUString aURL(getAbsoluteURL(pURL)); + if (aURL.isEmpty()) + return false; + + if (!xContext.is()) + return false; + + uno::Sequence<sal_Int8> aCertificateSequence; + + std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize); + std::string aCertificateBase64String = extractCertificate(aCertificateString); + if (!aCertificateBase64String.empty()) + { + OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String.c_str()); + comphelper::Base64::decode(aCertificateSequence, aBase64OUString); + } + else + { + aCertificateSequence.realloc(nCertificateBinarySize); + std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.begin()); + } + + uno::Sequence<sal_Int8> aPrivateKeySequence; + std::string aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary), nPrivateKeyBinarySize); + std::string aPrivateKeyBase64String = extractPrivateKey(aPrivateKeyString); + if (!aPrivateKeyBase64String.empty()) + { + OUString aBase64OUString = OUString::createFromAscii(aPrivateKeyBase64String.c_str()); + comphelper::Base64::decode(aPrivateKeySequence, aBase64OUString); + } + else + { + aPrivateKeySequence.realloc(nPrivateKeyBinarySize); + std::copy(pPrivateKeyBinary, pPrivateKeyBinary + nPrivateKeyBinarySize, aPrivateKeySequence.begin()); + } + + uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xContext); + uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext; + xSecurityContext = xSEInitializer->createSecurityContext(OUString()); + if (!xSecurityContext.is()) + return false; + + uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment; + xSecurityEnvironment = xSecurityContext->getSecurityEnvironment(); + uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY); + + if (!xCertificateCreator.is()) + return false; + + uno::Reference<security::XCertificate> xCertificate; + xCertificate = xCertificateCreator->createDERCertificateWithPrivateKey(aCertificateSequence, aPrivateKeySequence); + + if (!xCertificate.is()) + return false; + + sfx2::DocumentSigner aDocumentSigner(aURL); + if (!aDocumentSigner.signDocument(xCertificate)) + return false; + + return true; +} + static void lo_registerCallback (LibreOfficeKit* pThis, LibreOfficeKitCallback pCallback, void* pData) |