CollaboraOnline / online

Collabora Online is a collaborative online office suite based on LibreOffice technology. This is also the source for the Collabora Office apps for iOS and Android.
https://collaboraonline.com
Other
1.88k stars 710 forks source link

Digitally sign documents #9992

Closed vmiklos closed 1 day ago

vmiklos commented 2 months ago

Is your feature request related to a problem?

Once a document is signed digitally, the COOL toolbar has an icon to view these signatures. You can't add or remove a document signature, though.

Describe the solution you'd like

As a first step, be able to remove document signatures. Later, also be able to add them (sure, that's more complicated).

Describe alternatives you've considered

An option is to only use COOL for signature verification, and do the signature creation outside COOL with apps like https://apps.nextcloud.com/apps/signlive or https://apps.nextcloud.com/apps/electronicsignatures.

Additional context

There are lots of unknowns here, but as a first step, let's focus on how the signatures dialog is ready-only: we need a read-write async dialog to start on this.

vmiklos commented 2 months ago

For the async dialog conversion, the backtrace of run(), till the async command dispatch:

#0  DigitalSignaturesDialog::run() (this=0x74f5200) at /home/vmiklos/git/libreoffice/core/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx:423
#1  0x00007fffbc31b5c7 in (anonymous namespace)::DocumentDigitalSignatures::ImplViewSignatures(com::sun::star::uno::Reference<com::sun::star::embed::XStorage> const&, com::sun::star::uno::Reference<com::sun::star::io::XStream> const&, DocumentSignatureMode, bool)
    (this=0x76479f0, rxStorage=uno::Reference to (OStorage *) 0x758d788, xSignStream=uno::Reference to (OWriteStream *) 0x7565f78, eMode=DocumentSignatureMode::Content, bReadOnly=false)
    at /home/vmiklos/git/libreoffice/core/xmlsecurity/source/component/documentdigitalsignatures.cxx:449
#2  0x00007fffbc31a80b in (anonymous namespace)::DocumentDigitalSignatures::signDocumentContent(com::sun::star::uno::Reference<com::sun::star::embed::XStorage> const&, com::sun::star::uno::Reference<com::sun::star::io::XStream> const&) (this=0x76479f0, rxStorage=uno::Reference to (OStorage *) 0x758d788, xSignStream=uno::Reference to (OWriteStream *) 0x7565f78)
    at /home/vmiklos/git/libreoffice/core/xmlsecurity/source/component/documentdigitalsignatures.cxx:280
#3  0x00007ffff33da661 in SfxMedium::SignContents_Impl(weld::Window*, bool, bool, rtl::OUString const&, com::sun::star::uno::Reference<com::sun::star::security::XCertificate> const&, com::sun::star::uno::Reference<com::sun::star::graphic::XGraphic> const&, com::sun::star::uno::Reference<com::sun::star::graphic::XGraphic> const&, rtl::OUString const&)
    (this=0x46171b0, pDialogParent=0x5ba0638, bSignScriptingContent=false, bHasValidDocumentSignature=true, aSignatureLineId="", xCert=empty uno::Reference, xValidGraphic=empty uno::Reference, xInvalidGraphic=empty uno::Reference, aComment="") at /home/vmiklos/git/libreoffice/core/sfx2/source/doc/docfile.cxx:4440
#4  0x00007ffff3472218 in SfxObjectShell::SignDocumentContent(weld::Window*) (this=0x46078e0, pDialogParent=0x5ba0638)
    at /home/vmiklos/git/libreoffice/core/sfx2/source/doc/objserv.cxx:2132
#5  0x00007ffff3467499 in SfxObjectShell::ExecFile_Impl(SfxRequest&) (this=0x46078e0, rReq=...) at /home/vmiklos/git/libreoffice/core/sfx2/source/doc/objserv.cxx:591 <- start here, 1/5

You can see what we try to create a non-async dialog with this patch:

diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index 7b87a3da30e1..6b92bad9eafc 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -2063,7 +2063,7 @@ void SfxObjectShell::AfterSigning(bool bSignSuccess, bool bSignScriptingContent)
 bool SfxObjectShell::CheckIsReadonly(bool bSignScriptingContent, weld::Window* pDialogParent)
 {
     // in LOK case we support only viewer / readonly mode so far
-    if (GetMedium()->IsOriginallyReadOnly() || comphelper::LibreOfficeKit::isActive())
+    if (GetMedium()->IsOriginallyReadOnly())
     {
         // If the file is physically read-only, we just show the existing signatures
         try
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index c49b7427f67d..478e65b9dc12 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -444,10 +444,12 @@ bool DocumentDigitalSignatures::ImplViewSignatures(
         {
             xSignaturesDialog->beforeRun();
             weld::DialogController::runAsync(xSignaturesDialog, [] (sal_Int32) {});
+            SAL_DEBUG("DocumentDigitalSignatures::ImplViewSignatures: good, async run()");
             return false;
         }
         else if (xSignaturesDialog->run() == RET_OK)
         {
+            SAL_DEBUG("DocumentDigitalSignatures::ImplViewSignatures: bad, sync run()");
             if (xSignaturesDialog->SignaturesChanged())
             {
                 bChanges = true;
vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/172914 step 1/5 to make the rw sign dialog async, on master so far.

https://gerrit.libreoffice.org/c/core/+/172934 is step 2/5 on master.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173060 is step 3/5 on master.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173117 is step 4/5 on master.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173155 is step 5/5 on master, to have an async signing dialog.

vmiklos commented 2 months ago

One more sub-task before getting to signature removal: the doc sign dialog is available in COOL, but not the macro sign dialog. The idea is to automatically sign macros (when makes sense) as part of the doc signing.

https://gerrit.libreoffice.org/c/core/+/173263 to do that on master.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173118/2#message-9b569cb370711a1c783597ca9c31ef80de571032 suggests there is some cleanup is recommended after the async conversion, https://gerrit.libreoffice.org/c/core/+/173313 does that.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173428 implements the core side of signature removal.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173514 avoids a buggy "sign status: invalid" state as an update right after load.

vmiklos commented 2 months ago

https://github.com/CollaboraOnline/online/pull/10069 is meant to fix the COOL side of the "signature removal" problems.

vmiklos commented 2 months ago

I'm still tweaking the above to pass all tests. In the meantime, https://gerrit.libreoffice.org/c/core/+/173651 starts on the signing side, first just creating suitable test certificates to do that with the existing script.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173691 extracts some duplicated cert parsing code, so I can build on that later.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173806 starts handling the new signing key view options that an integration can pass to us.

sig.patch.txt is the mock patch I use on the online side till the core side is working, to be able to do this in the core -> online -> integration order.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173837 stores signing cert in the view, it's not yet read.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173892 makes the signing work at an NSS level. The UI needs fixes here & there, still.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/173964 fixes the sign dialog part of the UI, now we show the Add button when the view has a sign cert.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/174002 fixes the cert chooser to show the right certificate.

https://github.com/CollaboraOnline/online/pull/10135 fixes the COOL side to allow signature descriptions.

vmiklos commented 2 months ago

https://gerrit.libreoffice.org/c/core/+/174215 converts the cert chooser dialog to a jsdialog.

https://gerrit.libreoffice.org/c/core/+/174307 fixes the status of the signature after mutating the trusted CA list.

vmiklos commented 1 month ago

https://gerrit.libreoffice.org/c/core/+/174369 cool#9992 avoids storing the sign cert in the model after sign

vmiklos commented 1 month ago

https://github.com/CollaboraOnline/online/pull/10166 adds UI to create a signature on unsigned documents.

vmiklos commented 1 month ago

https://github.com/CollaboraOnline/online/pull/10172 adds the local file WOPI provider for signing.

vmiklos commented 1 month ago

https://github.com/CollaboraOnline/online/pull/10184 connects the WOPI provider with the view settings of the kit process, so 'make run' now works if you load a file like test.odt and files test.odt.ca.pem, test.odt.cert.pem & test.odt.key.pem exist in the same directory. Those 3 files can be generated by executing:

./create-certs.sh RSA NOPASS

in core.git xmlsecurity/qa/create-certs/.

vmiklos commented 1 month ago

https://github.com/CollaboraOnline/online/pull/10189 adds a setting to disable this, seeing that e.g. nextcloud richdocuments integration expects such a setting for zotero.

vmiklos commented 1 month ago

Getting back to this as now the nextcloud slide is "only" pending review.

https://github.com/CollaboraOnline/online/pull/10247 hides the sign button when it could not add a signature anyway.

vmiklos commented 1 month ago

https://github.com/CollaboraOnline/online/pull/10259 adds a cypress test for the sign create case, which is the first sign test.

vmiklos commented 1 month ago

https://sdk.collaboraonline.com/docs/advanced_integration.html#document-signing now adds some documentation on how to create sign keys for testing purposes without git clone.

vmiklos commented 1 month ago

https://gerrit.libreoffice.org/c/core/+/175373 is the core side of delayed online -> core passing of signing cert/key.

vmiklos commented 1 month ago

https://github.com/CollaboraOnline/online/pull/10311 is the online side of delayed online -> core passing of signing cert/key.

vmiklos commented 1 month ago

https://gerrit.libreoffice.org/c/core/+/175630 exposes the 3 new signing props also for the COOL convert-to endpoint. Example curl invocation:

curl -k -F "data=@test.odt" -F "format=pdf" -F 'options={"SignPDF":,"SignCertificateCaPem":{"type":"string","value":"..."},"SignCertificateCertPem":{"type":"string","value":"..."},"SignCertificateKeyPem":{"type":"string","value":"..."}}' https://localhost:9980/cool/convert-to > out.pdf
vmiklos commented 3 weeks ago

The above PDF signature is created, but the content is still problematic, https://github.com/CollaboraOnline/online/pull/10409 is the first fix to address that.

vmiklos commented 3 weeks ago

https://gerrit.libreoffice.org/c/core/+/176040 adds a way to test sign-during-PDF-export for both the desktop and the COOL case, and now with that consistent setup it works for me.

vmiklos commented 3 weeks ago

https://github.com/CollaboraOnline/online/pull/10416 adds UI in the compact mode, towards interactive PDF signing.

vmiklos commented 3 weeks ago

https://github.com/CollaboraOnline/online/pull/10431 adds UI to interactively sign PDF files.

vmiklos commented 3 weeks ago

https://gerrit.libreoffice.org/c/core/+/176255 start on the hash extract part, which will be needed for https://docs.eideasy.com/electronic-signatures/api-flow-with-file-hashes-pdf.html

Local online.git patch in case you want to try this out:

diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index 3a2542424f..78200d9d5c 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -676,6 +676,10 @@ bool ChildSession::_handleInput(const char *buffer, int length)
             }
             else if (tokens[1].find(".uno:Signature") != std::string::npos)
             {
+                char* values = getLOKitDocument()->getCommandValues(".uno:Signature");
+                std::cerr << "debug, ChildSession::_handleInput: getCommandValues('.uno:Signature') returned '"<<values<<"'" << std::endl;
+                std::free(values);
+
                 if (unoSignatureCommand())
                 {
                     // .uno:Signature has been sent with parameters from user private info, done.

Then open a PDF, click File -> digital signatures, and you currently get a 0 signatureTime, the above change is towards fixing that.

vmiklos commented 2 weeks ago

https://gerrit.libreoffice.org/c/core/+/176370 continues the hash extract part, time extraction works now, so digest can be the next one.

vmiklos commented 2 weeks ago

https://gerrit.libreoffice.org/c/core/+/176459 exposes the digest of the document, part of the hash extract task.

vmiklos commented 2 weeks ago

https://gerrit.libreoffice.org/c/core/+/176574 adds a time parameter for hash extraction, this way we can get stable doc hashes.

vmiklos commented 2 weeks ago

https://gerrit.libreoffice.org/c/core/+/176618 adds initial support for serializing an externally provided signature.

vmiklos commented 1 week ago

https://github.com/CollaboraOnline/online/pull/10530 is work towards allowing electronic signing params for .uno:Signature from JS.

vmiklos commented 1 week ago

https://github.com/CollaboraOnline/online/pull/10540 allows specifying esign settings during a local 'make run' (no integration). Sample test.pdf.user-private-info.json:

{
    "ESignatureBaseUrl": "https://test.eideasy.com",
    "ESignatureSecret": "56RkLgZREDi1H0HZAvzOSAVlxu1Flx41",
    "ESignatureClientId": "2IaeiZXbcKzlP1KvjZH9ghty2IJKM8Lg"
}

These are not real values, but test data from https://docs.eideasy.com/guide/test-environment.html#sandbox-test-environments-credentials

vmiklos commented 1 week ago

https://gerrit.libreoffice.org/c/core/+/176896 fixes 'commandvalues command=.uno:Signature' to emit a json that is a good fit for COOL.

vmiklos commented 1 week ago

https://github.com/CollaboraOnline/online/pull/10572 for electronic signing, this is step 1/5 on the online side (hash extract).

vmiklos commented 5 days ago

https://github.com/CollaboraOnline/online/pull/10593 is step 2/5 for electronic signing: send the hash for signing.

vmiklos commented 4 days ago

https://github.com/CollaboraOnline/online/pull/10603 is step 3/5 for electronic signing: sign the hash. For this to work, the sign method has to be part of the user config. E.g. to sign a test.pdf, you want a test.pdf.user-private-info.json, containing (these are public test settings, not real ones):

{
    "ESignatureBaseUrl": "https://test.eideasy.com",
    "ESignatureSecret": "56RkLgZREDi1H0HZAvzOSAVlxu1Flx41",
    "ESignatureClientId": "2IaeiZXbcKzlP1KvjZH9ghty2IJKM8Lg",
    "ESignatureMethod": "smart-id-signature"
}

And when asked for an Estonian personal ID number, use the test 30303039914 value.

I plan to revisit specifying the sign method, but let's have a first working esign scenario.

vmiklos commented 3 days ago

https://github.com/CollaboraOnline/online/pull/10609 fetches the signature from the remote server, so now only the signature serialization is missing.

vmiklos commented 2 days ago

https://github.com/CollaboraOnline/online/pull/10617 finally completes 1 specific scenario: signing with the smart-id-signature provider. To have a green sign for the result, one has to also trust TEST_of_EID-SK_2016.pem.crt, so a sample test.pdf.user-private-info.json looks like:

{
    "ESignatureBaseUrl": "https://test.eideasy.com",
    "ESignatureSecret": "56RkLgZREDi1H0HZAvzOSAVlxu1Flx41",
    "ESignatureClientId": "2IaeiZXbcKzlP1KvjZH9ghty2IJKM8Lg",
    "ESignatureMethod": "smart-id-signature",
    "SignatureCa": "-----BEGIN CERTIFICATE-----\nMIIG+DCCBeCgAwIBAgIQUkCP5k8r59RXxWzfbx+GsjANBgkqhkiG9w0BAQwFADB9\nMQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1\nczEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290\nIENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwIBcNMTYwODMwMTEyNDE1WhgP\nMjAzMDEyMTcyMzU5NTlaMGgxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0\naWZpdHNlZXJpbWlza2Vza3VzMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEcMBoG\nA1UEAwwTVEVTVCBvZiBFSUQtU0sgMjAxNjCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAOrKOByrJqS1QsKD4tXhqkZafPMd5sfxem6iVbMAAHKpvOs4Ia2o\nXdSvJ2FjrMl5szeT4lpHyzfECzO3nx7pvRLKHufi6lMwMGjtSI6DK8BiH9z7Lm+k\nNLunNFdIir0hPijjbIkjg9iwfaeST9Fi5502LsK7duhKuCnH7O0uMrS/MynJ4StA\nNGY13X2FvPW4qkrtbwsmhdN0Btro72O6/3O+0vbnq/yCWtcQrBGv3+8XEBdCqH5S\n/Rt0EugKX4UlVy5l0QUc8IrjGtdMsr9KDtvmVwlefXYKoLqkC7guMGOUNf6Y4AYG\nsPqfY4dG3N5YNp5FHDL7IO93h7TpRV3gyR38LiJsPHk5nES5mdPkNuEkCyg0zEKI\n7uJ4LUuBbjzZPp2gP7PN8Iqi9GP7V2NCz8vUVN3WpHvctsf0DMvZdV5pxqLY5ojy\nfhMsU4aMcGSQA9EK8ES3O1zBK1DW+btjbQjUFW1SIwCkB2yofFxge+vvzZGbvt2U\nGOE8oAL8/JzNxi9FbjTAbycrGWgEMQ0sM1fKc+OsvoaSy9m3ZQGph0+dbsouQpl3\nkpJvjDMzxxkrMqxdhlVMreLKGCMMxJMAGQEwVS5P93Nnmz8UbkmeomUJr3NrBo4+\nV9L5S4Kx1vTvD0p72xRYFyfifLOjs8qs7lR3yhkcBPQI78ERqxv31FWDAgMBAAGj\nggKFMIICgTAfBgNVHSMEGDAWgBS1NAqdpS8QxechDr7EsWVHGwN2/jAdBgNVHQ4E\nFgQUrrDq4Tb4JqulzAtmVf46HQK/ErQwDgYDVR0PAQH/BAQDAgEGMIHEBgNVHSAE\ngbwwgbkwPAYHBACL7EABAjAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3dy5zay5l\nZS9yZXBvc2l0b29yaXVtL0NQUzA8BgcEAIvsQAEAMDEwLwYIKwYBBQUHAgEWI2h0\ndHBzOi8vd3d3LnNrLmVlL3JlcG9zaXRvb3JpdW0vQ1BTMDsGBgQAj3oBAjAxMC8G\nCCsGAQUFBwIBFiNodHRwczovL3d3dy5zay5lZS9yZXBvc2l0b29yaXVtL0NQUzAS\nBgNVHRMBAf8ECDAGAQH/AgEAMCcGA1UdJQQgMB4GCCsGAQUFBwMJBggrBgEFBQcD\nAgYIKwYBBQUHAwQwfAYIKwYBBQUHAQEEcDBuMCAGCCsGAQUFBzABhhRodHRwOi8v\nb2NzcC5zay5lZS9DQTBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5zay5lZS9jZXJ0\ncy9FRV9DZXJ0aWZpY2F0aW9uX0NlbnRyZV9Sb290X0NBLmRlci5jcnQwQQYDVR0e\nBDowOKE2MASCAiIiMAqHCAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAMCUGCCsGAQUFBwEDBBkwFzAVBggrBgEFBQcLAjAJBgcEAIvs\nSQEBMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHBzOi8vd3d3LnNrLmVlL3JlcG9zaXRv\ncnkvY3Jscy90ZXN0X2VlY2NyY2EuY3JsMA0GCSqGSIb3DQEBDAUAA4IBAQAiw1VN\nxp1Ho7FwcPlFqlLl6zb225IvpNelFX2QMbq1SPe41LuBW7WRZIV4b6bRQug55k8l\nAm8eX3zEXL9I+4Bzai/IBlMSTYNpqAQGNVImQVwMa64uN8DWo8LNWSYNYYxQzO7s\nTnqsqxLPWeKZRMkREI0RaVNoIPsciJvid9iBKTcGnMVkbrgyLzlXblLMU4I0pL2R\nWlfs2tr+XtCtWAvJPFskM2QZ2NnLjW8WroZr8TooocRA1vl/ruIAPC3FxW7zebKc\nA2B66j4tW7uyF2kPx4WWA3xgR5QZnn4ePEAYjJdu1eWd9KbeAbxPCfFOST43t0fm\n20HfV2Wp2PMEq4b2\n-----END CERTIFICATE-----\n"
}

and then using 30303039914 as a test ID during signing gives a valid signature.

vmiklos commented 1 day ago

https://github.com/CollaboraOnline/online/pull/10626 adds some ground work to have a UI for selecting the esign provider (backend of eIDEasy). Further progress will be documented in https://github.com/CollaboraOnline/online/issues/10630