[Libreoffice-commits] core.git: desktop/qa desktop/source include/LibreOfficeKit include/sfx2 sfx2/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Sun Oct 28 20:29:42 UTC 2018


 desktop/qa/desktop_lib/test_desktop_lib.cxx |    4 
 desktop/source/lib/init.cxx                 |   69 ++++++++++++++++
 include/LibreOfficeKit/LibreOfficeKit.h     |   10 ++
 include/LibreOfficeKit/LibreOfficeKit.hxx   |   19 ++++
 include/sfx2/docfile.hxx                    |    4 
 include/sfx2/objsh.hxx                      |    3 
 sfx2/source/doc/docfile.cxx                 |  117 ++++++++++++++++++++++++++++
 sfx2/source/doc/objserv.cxx                 |   79 ++++++++++++++++++
 8 files changed, 304 insertions(+), 1 deletion(-)

New commits:
commit 23a2312344ac961ead9ee14140c0b3e879bb7a41
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Mon Oct 15 10:09:15 2018 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Sun Oct 28 21:29:19 2018 +0100

    lokit: add funct. to insert, sign and verify signature
    
    A lot of signing code paths trigger a GUI dialog (to select the
    certificate for example) which aren't acceptable when triggering
    through the LOKit. This code paths needed to be duplicated and
    reworked to not trigger any GUI action.
    
    Change-Id: I2f0d6038fb1bcd00adcdf86e432f9df8858cc21c
    Reviewed-on: https://gerrit.libreoffice.org/61780
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 69f2b3ac2bfb..9a8d7b88b0b7 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -2299,10 +2299,12 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(39), offsetof(struct _LibreOfficeKitDocumentClass, setViewLanguage));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(40), offsetof(struct _LibreOfficeKitDocumentClass, postWindowExtTextInputEvent));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(41), offsetof(struct _LibreOfficeKitDocumentClass, getPartInfo));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(42), offsetof(struct _LibreOfficeKitDocumentClass, insertCertificate));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(43), offsetof(struct _LibreOfficeKitDocumentClass, getSignatureState));
 
     // Extending is fine, update this, and add new assert for the offsetof the
     // new method
-    CPPUNIT_ASSERT_EQUAL(documentClassOffset(42), sizeof(struct _LibreOfficeKitDocumentClass));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(44), sizeof(struct _LibreOfficeKitDocumentClass));
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index a2182e9ea2a8..2a13775dcc64 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -73,6 +73,13 @@
 #include <com/sun/star/document/XRedlinesSupplier.hpp>
 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
 
+#include <com/sun/star/xml/crypto/SEInitializer.hpp>
+#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
+#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
+#include <com/sun/star/security/XCertificate.hpp>
+
 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
 #include <com/sun/star/i18n/ScriptType.hpp>
@@ -682,6 +689,12 @@ static void doc_postWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
 
 static char* doc_getPartInfo(LibreOfficeKitDocument* pThis, int nPart);
 
+static bool doc_insertCertificate(LibreOfficeKitDocument* pThis,
+                                  const unsigned char* pCertificateBinary,
+                                  const int pCertificateBinarySize);
+
+static int doc_getSignatureState(LibreOfficeKitDocument* pThis);
+
 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent)
     : mxComponent(xComponent)
 {
@@ -742,6 +755,9 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
 
         m_pDocumentClass->getPartInfo = doc_getPartInfo;
 
+        m_pDocumentClass->insertCertificate = doc_insertCertificate;
+        m_pDocumentClass->getSignatureState = doc_getSignatureState;
+
         gDocumentClass = m_pDocumentClass;
     }
     pClass = m_pDocumentClass.get();
@@ -3584,6 +3600,59 @@ static void doc_postWindow(LibreOfficeKitDocument* /*pThis*/, unsigned nLOKWindo
     }
 }
 
+// CERTIFICATE AND DOCUMENT SIGNING
+static bool doc_insertCertificate(LibreOfficeKitDocument* /*pThis*/, const unsigned char* pCertificateBinary, const int nCertificateBinarySize)
+{
+    if (!xContext.is())
+        return false;
+
+    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::Sequence<sal_Int8> aCertificateSequence(nCertificateBinarySize);
+    std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.begin());
+
+    uno::Reference<security::XCertificate> xCertificate = xSecurityEnvironment->createCertificateFromRaw(aCertificateSequence);
+
+    if (!xCertificate.is())
+        return false;
+
+    printf("CERTIFICATE\n\tIssuerName: %s \n\tSubjectName: %s\n\tPK %s\n\n",
+            xCertificate->getIssuerName().toUtf8().getStr(),
+            xCertificate->getSubjectName().toUtf8().getStr(),
+            xCertificate->getSubjectPublicKeyAlgorithm().toUtf8().getStr());
+
+    SfxObjectShell* pDoc = SfxObjectShell::Current();
+    if (!pDoc)
+        return false;
+
+    return pDoc->SignDocumentContentUsingCertificate(xCertificate);
+}
+
+static int doc_getSignatureState(LibreOfficeKitDocument* pThis)
+{
+    LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+
+    if (!pDocument->mxComponent.is())
+        return int(SignatureState::UNKNOWN);
+
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
+    if (!pBaseModel)
+        return int(SignatureState::UNKNOWN);
+
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    if (!pObjectShell)
+        return int(SignatureState::UNKNOWN);
+
+    return int(pObjectShell->GetDocumentSignatureState());
+}
+
 static char* lo_getError (LibreOfficeKit *pThis)
 {
     SolarMutexGuard aGuard;
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h
index 0ae5c6ff1332..24aa496214a8 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -321,6 +321,16 @@ struct _LibreOfficeKitDocumentClass
                                   const int nTileHeight);
 #endif // IOS
 
+// CERTIFICATE AND SIGNING
+
+    /// @see lok::Document::insertCertificate().
+    bool (*insertCertificate) (LibreOfficeKitDocument* pThis,
+                                const unsigned char* pCertificateBinary,
+                                const int pCertificateBinarySize);
+
+    /// @see lok::Document::getSignatureState().
+    int (*getSignatureState) (LibreOfficeKitDocument* pThis);
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx
index 3568c861f083..d6e4bee6fa8e 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -578,6 +578,25 @@ public:
     }
 #endif // IOS
 
+    /**
+     *  Insert certificate (in binary form) to the certificate store.
+     */
+    bool insertCertificate(const unsigned char* pCertificateBinary,
+                           const int pCertificateBinarySize)
+    {
+        return mpDoc->pClass->insertCertificate(mpDoc, pCertificateBinary, pCertificateBinarySize);
+    }
+
+    /**
+     *  Verify signature of the document.
+     *
+     *  Check possible values in include/sfx2/signaturestate.hxx
+     */
+    int getSignatureState()
+    {
+        return mpDoc->pClass->getSignatureState(mpDoc);
+    }
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx
index 0abd7ba23c3a..7022d51743d9 100644
--- a/include/sfx2/docfile.hxx
+++ b/include/sfx2/docfile.hxx
@@ -273,6 +273,10 @@ public:
                       = css::uno::Reference<css::graphic::XGraphic>(),
                       const OUString& aComment = OUString());
 
+    SAL_DLLPRIVATE bool
+    SignDocumentContentUsingCertificate(bool bHasValidDocumentSignature,
+                 const css::uno::Reference<css::security::XCertificate>& xCertificate);
+
     // the following two methods must be used and make sense only during saving currently
     // TODO/LATER: in future the signature state should be controlled by the medium not by the document
     //             in this case the methods will be used generally, and might need to be renamed
diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx
index 54d97faf3162..4e0ba7ae2a84 100644
--- a/include/sfx2/objsh.hxx
+++ b/include/sfx2/objsh.hxx
@@ -361,6 +361,9 @@ public:
     bool HasValidSignatures();
     SignatureState              GetDocumentSignatureState();
     void                        SignDocumentContent(weld::Window* pDialogParent);
+
+    bool SignDocumentContentUsingCertificate(const css::uno::Reference<css::security::XCertificate>& xCertificate);
+
     void SignSignatureLine(weld::Window* pDialogParent, const OUString& aSignatureLineId,
                            const css::uno::Reference<css::security::XCertificate>& xCert,
                            const css::uno::Reference<css::graphic::XGraphic>& xValidGraphic,
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 9e5fc078c635..9e55c128bb71 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -3644,6 +3644,123 @@ void SfxMedium::CreateTempFileNoCopy()
     CloseStorage();
 }
 
+bool SfxMedium::SignDocumentContentUsingCertificate(bool bHasValidDocumentSignature,
+                                                    const Reference<XCertificate>& xCertificate)
+{
+    bool bChanges = false;
+
+    if (IsOpen() || GetError())
+    {
+        SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
+        return bChanges;
+    }
+
+    // The component should know if there was a valid document signature, since
+    // it should show a warning in this case
+    OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
+    uno::Reference< security::XDocumentDigitalSignatures > xSigner(
+        security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
+            comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
+
+    uno::Reference< embed::XStorage > xWriteableZipStor;
+
+    // we can reuse the temporary file if there is one already
+    CreateTempFile( false );
+    GetMedium_Impl();
+
+    try
+    {
+        if ( !pImpl->xStream.is() )
+            throw uno::RuntimeException();
+
+        bool bODF = GetFilter()->IsOwnFormat();
+        try
+        {
+            xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImpl->xStream );
+        }
+        catch (const io::IOException& rException)
+        {
+            if (bODF)
+                SAL_WARN("sfx.doc", "ODF stream is not a zip storage: " << rException);
+        }
+
+        if ( !xWriteableZipStor.is() && bODF )
+            throw uno::RuntimeException();
+
+        uno::Reference< embed::XStorage > xMetaInf;
+        uno::Reference<container::XNameAccess> xNameAccess(xWriteableZipStor, uno::UNO_QUERY);
+        if (xNameAccess.is() && xNameAccess->hasByName("META-INF"))
+        {
+            xMetaInf = xWriteableZipStor->openStorageElement(
+                                            "META-INF",
+                                            embed::ElementModes::READWRITE );
+            if ( !xMetaInf.is() )
+                throw uno::RuntimeException();
+        }
+
+        {
+            if (xMetaInf.is())
+            {
+                // ODF.
+                uno::Reference< io::XStream > xStream;
+                if (GetFilter() && GetFilter()->IsOwnFormat())
+                    xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
+
+                bool bSuccess = xSigner->signDocumentWithCertificate(xCertificate, GetZipStorageToSign_Impl(), xStream);
+
+                if (bSuccess)
+                {
+                    uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
+                    xTransact->commit();
+                    xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
+                    xTransact->commit();
+
+                    // the temporary file has been written, commit it to the original file
+                    Commit();
+                    bChanges = true;
+                }
+            }
+            else if (xWriteableZipStor.is())
+            {
+                // OOXML.
+                uno::Reference<io::XStream> xStream;
+
+                    // We need read-write to be able to add the signature relation.
+                bool bSuccess =xSigner->signDocumentWithCertificate(
+                        xCertificate, GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream);
+
+                if (bSuccess)
+                {
+                    uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
+                    xTransact->commit();
+
+                    // the temporary file has been written, commit it to the original file
+                    Commit();
+                    bChanges = true;
+                }
+            }
+            else
+            {
+                // Something not ZIP based: e.g. PDF.
+                std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE));
+                uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream));
+                if (xSigner->signDocumentWithCertificate(xCertificate, uno::Reference<embed::XStorage>(), xStream))
+                    bChanges = true;
+            }
+        }
+    }
+    catch ( const uno::Exception& )
+    {
+        SAL_WARN( "sfx.doc", "Couldn't use signing functionality!" );
+    }
+
+    CloseAndRelease();
+
+    ResetError();
+
+    return bChanges;
+}
+
 bool SfxMedium::SignContents_Impl(bool bSignScriptingContent, bool bHasValidDocumentSignature,
                                   const OUString& aSignatureLineId,
                                   const Reference<XCertificate>& xCert,
diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index ce6b1cf0666d..c8bdda36a707 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -1585,6 +1585,85 @@ void SfxObjectShell::SignDocumentContent(weld::Window* pDialogParent)
     AfterSigning(bSignSuccess, false);
 }
 
+bool SfxObjectShell::SignDocumentContentUsingCertificate(const Reference<XCertificate>& xCertificate)
+{
+    // 1. PrepareForSigning
+
+    // check whether the document is signed
+    ImplGetSignatureState(false); // document signature
+    if (GetMedium() && GetMedium()->GetFilter() && GetMedium()->GetFilter()->IsOwnFormat())
+        ImplGetSignatureState( true ); // script signature
+    bool bHasSign = ( pImpl->nScriptingSignatureState != SignatureState::NOSIGNATURES || pImpl->nDocumentSignatureState != SignatureState::NOSIGNATURES );
+
+    // the target ODF version on saving (only valid when signing ODF of course)
+    SvtSaveOptions aSaveOpt;
+    SvtSaveOptions::ODFDefaultVersion nVersion = aSaveOpt.GetODFDefaultVersion();
+
+    // the document is not new and is not modified
+    OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
+
+    if (IsModified() || !GetMedium() || GetMedium()->GetName().isEmpty()
+      || (GetMedium()->GetFilter()->IsOwnFormat() && aODFVersion != ODFVER_012_TEXT && !bHasSign))
+    {
+        if ( nVersion >= SvtSaveOptions::ODFVER_012 )
+        {
+            sal_uInt16 nId = SID_SAVEDOC;
+            if ( !GetMedium() || GetMedium()->GetName().isEmpty() )
+                nId = SID_SAVEASDOC;
+            SfxRequest aSaveRequest( nId, SfxCallMode::SLOT, GetPool() );
+            //ToDo: Review. We needed to call SetModified, otherwise the document would not be saved.
+            SetModified();
+            ExecFile_Impl( aSaveRequest );
+
+            // Check if it is stored a format which supports signing
+            if (GetMedium() && GetMedium()->GetFilter() && !GetMedium()->GetName().isEmpty()
+                && ((!GetMedium()->GetFilter()->IsOwnFormat()
+                     && !GetMedium()->GetFilter()->GetSupportsSigning())
+                    || (GetMedium()->GetFilter()->IsOwnFormat()
+                        && !GetMedium()->HasStorage_Impl())))
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return false;
+        }
+
+        if ( IsModified() || !GetMedium() || GetMedium()->GetName().isEmpty() )
+            return false;
+    }
+
+    // the document is not modified currently, so it can not become modified after signing
+    pImpl->m_bAllowModifiedBackAfterSigning = false;
+    if ( IsEnableSetModified() )
+    {
+        EnableSetModified( false );
+        pImpl->m_bAllowModifiedBackAfterSigning = true;
+    }
+
+    // we have to store to the original document, the original medium should be closed for this time
+    bool bResult = ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium);
+    printf("ConnectTmpStorage_Impl %d\n", bResult);
+
+    if (!bResult)
+        return false;
+
+    GetMedium()->CloseAndRelease();
+
+    // 2. Check Read-Only
+    if (GetMedium()->IsOriginallyReadOnly())
+        return false;
+
+    // 3. Sign
+    bool bSignSuccess = GetMedium()->SignDocumentContentUsingCertificate(HasValidSignatures(), xCertificate);
+
+    // 4. AfterSigning
+    AfterSigning(bSignSuccess, false);
+
+    return true;
+}
+
 void SfxObjectShell::SignSignatureLine(weld::Window* pDialogParent,
                                        const OUString& aSignatureLineId,
                                        const Reference<XCertificate>& xCert,


More information about the Libreoffice-commits mailing list