Estimated read time: 13 minutes
LibreOffice Technology had the concept of digital signing, but this was not available in Collabora Online, so it was not possible to combine this with collaborative editing. Also, once Collabora Online started to expose digital signing with software certificates for ODF files, that also allowed taking a further step and start supporting electronic signing for PDF files. Partnering with eID Easy, you can create strongest of the electronic signatures – the mighty QES. This means signing with Collabora Online allows you to:
- create proper electronic signatures
- not share your document with a 3rd-party, only the hash of your PDF will be sent to the external service
- integrate with e.g. Nextcloud, use the feature without installing anything other than the Nextcloud AIO image
- potentially combine signing with other security features like Secure View and
- work with visual signing in a WYSIWYG way, which allows placing a visible signature widget at the specified page, then dragging it to the preferred position.
The sample integration presented here is for Nextcloud, but the feature can be made available in other integrations as well.
See Collabora's blog post if you prefer less technical information about this feature.
Motivation¶
Digital and electronic signing of documents is meant to be based on cryptographic security, and traditionally this has been exposed to users in a very complex way. You need to know that first you have to sign your macros and only then your document, you need to somehow get PEM files to have a signing certificate, you need to somehow get your certificate trusted by some certificate authority that is commonly trusted by other people who will verify your signature, and so on.
This lead to the need to first support digital signatures in COOL using a single signatures dialog for ODF files and then later to provide electronic visual signing for PDF files, while continuing to respect your privacy by not sharing your document with a 3rd-party service.
Results so far¶
A read-write signatures dialog¶
First the signature viewer dialog was turned into a read-write digital signatures dialog in COOL that is still async (compatible with collaborative editing), first for ODF files & using PEM files.
Related to this, we automatically sign macros (if the document has macros) when signing the document, so you can’t forget about this or get the order wrong (sign macros first, then the document).
At this stage implementing signature removal was possible, which again needs an async conversion so the user can confirm they really want to remove a signature. This also means the signature status of the document can change, the COOL UI now supports this.
You can now associate a signing certificate / key / CA chain with a COOL editor, so you can sign the document, but not an other editor working on the same document.
Finally adding a digital signature is now possible, where the certificate chooser just shows your signing certificates and hides it from other editors.
Here is a screenshot of the early digital signatures dialog at this stage:
Automatically signed documents¶
The second half of digital signing support in COOL started with WOPI extensions, so an integrator of COOL can specify the signature settings on their user settings page and pass that to COOL when a document is edited. We then send this to the document editor process only when needed, i.e. not on file open, but when the actual signing process would start.
UI is also added on the notebookbar in the form of a new button that allows adding signatures to a previously unsigned document – before you could only trigger the signatures dialog if the status bar said something about existing signatures, and only then you could add a signature. This button is hidden if you don’t have signature settings configured. It looks like this:
When was still missing here is automated Cypress tests to make sure signing e.g. an ODT file keeps working and the SDK documentation now also describes what does it take to support digital signatures in your COOL integration. For example you can create a Nextcloud integration like this:
Finally, COOL’s convert-to endpoint is hooked up with signature support, so you can export to a signed PDF. Example curl invocation:
curl -k -F "data=@in.odt" -F "format=pdf" -F 'options={"SignPDF":{"type":"boolean","value":"true"},"SignCertificateCaPem":{"type":"string","value":"..."},"SignCertificateCertPem":{"type":"string","value":"..."},"SignCertificateKeyPem":{"type":"string","value":"..."}}' https://localhost:9980/cool/convert-to > out.pdf
Plumbing for electronic signing¶
Once digital signing of ODF files is handled, let’s switch to PDF signing, which is much more interesting: you typically want to sign something final, and we see PDF as a final output of your documents. So first support for digital signing of PDFs was added.
The next part is to integrate with eID Easy, which can do privacy-friendly electronic signing for us. This is a 5 step process:
- Extract the hash of the to-be-signed document. This is similar to signing, you start the process but once you have the hash that you would sign locally, you just take that hash and abort the actual signing.
- Send this hash to the electronic signing service.
- Open a popup and let the user authenticate with their credentials (passport, personal ID, etc) using one of the providers (different providers support different countries) and sign the hash.
- Download the signed hash from the service.
- Serialize this signed hash into the local document. This requires producing the local PDF signature once more, but this time using the previous timestamp (instead of the system clock, so the hash is table) and using the downloaded PKCS#7 signature instead of locally signing something.
At the end we got something that looks like a signature produced externally, but there was no UI for this. An initial popup for step 3 looked like this in the test environment (that doesn’t work with real passport numbers or anything sensitive):
UI for electronic signing¶
The next step was to create a user interface for electronic signing. The Insert menu had a new menu item to insert electronic signatures and to specify your country, finally choose one of the providers available in your country.
Also support for two types of providers is added: the first is the “in context” one, the other is a “redirect based” one. We now support both: all the redirect (should be familiar to you if you ever did e.g. online payments) happens in the popup, so the original COOL editor is never closed.
eID also has the concept of multiple tokens for signing: initiating the signing costs money, so is done using a “secret”, which is never sent to the COOL JS code. Then the “client ID” identifies the client, but can’t be used to start signing. Finally any single signing transaction has a specific “document ID”. We took care to follow the guidelines here, so the sensitive “secret” for signing is always kept on the server.
Similar to the initial document signing, electronic signing settings are also possible to specify from an integration, we documented this in the SDK and also created a sample Nextcloud integration for this.
The Nextcloud integration looks like this:
Note that later the API URL was changed to be a hidden setting, as real signing never needs a custom value there, this is just for testing.
Visual signing¶
The last part of this electronic signing effort was to expose visual singing in COOL, something that was added to LibreOffice Draw back in 2020, see this earlier blog post.
First this was exposed in COOL with digital signing, in a way that the current page gets a signature widget inserted at the page center and then the user can move that signature widget to the desired location.
Combining this with electronic signing is a bit more tricky, since we don’t want to select a certificate when the signature widget is inserted, we’ll deal with that in the external service, as usual.
Also, there was no real reason to not use visual signing unconditionally, so now the way to initiate a signing process is to open your PDF in COOL, use the Insert → Signature line menu item to insert a signature widget, move it to the wanted position, click “finish” on the snackbar and that completes the process with the usual electronic signing popup.
The final problem was that our multi-page PDF viewer was not really prepared to deal with changed PDF content (assuming your PDF rendering will not change is reasonable), so some last minute work had to be done to make sure the signature widget’s graphical selection indicator, its dragging and its rendering works fine even on non-first pages of a PDF document.
At the end, a test signature using the d-trust signature provider’s test environment looks like this:
Or if you prefer watching a demo, a typical electronic signing process session looks like this:
There were a few more talks with similar content:
At the end you get an electronic signature that is trusted by the EU trust list and thus e.g. Acrobat Reader:
How is this implemented?¶
If you would like to know a bit more about how this works, continue reading... :-) As usual, the high-level problem was addressed by a series of small changes.
LibreOffice core commits:
- cool#9992 lok doc sign: add SfxObjectShell::AfterSignContent()
- cool#9992 lok doc sign: make
SfxMedium::SignContents_Impl()
async - cool#9992 lok doc sign: async DocumentDigitalSignatures::signDocumentContent()
- cool#9992 lok doc sign: async DocumentDigitalSignatures::ImplViewSignatures()
- cool#9992 lok doc sign: async read-write DigitalSignaturesDialog
- cool#9992 lok doc sign: allow sign of macros & the document itself in one step
- cool#9992 lok doc sign: implement signature removal
- cool#9992 lok doc sign: fix signature status after load
- cool#9992 lok doc sign: add password-less mode to create-certs.sh
- cool#9992 lok doc sign: extract duplicated code to SfxLokHelper
- cool#9992 lok doc sign: handle .uno:SignatureCert/Key/Ca view options
- cool#9992 lok doc sign: store signing cert in the view
- cool#9992 lok doc sign: fix import of the private key
- cool#9992 lok doc sign: conditionally show the add button in the sign dialog
- cool#9992 lok doc sign: only take sign cert from the view in the cert chooser
- cool#9992 lok doc sign: convert the certificate chooser dialog to async
- cool#9992 lok doc sign: update sign status after modify the list of trusted CAs
- cool#9992 lok doc sign: avoid storing the sign cert in the model after sign
- cool#9992 lok doc sign: allow late-init of the sign cert
- cool#9992 lok doc sign: never remember previous .uno:Signature params
- cool#9992 lok doc sign: allow injecting sign cert/key during pdf export
- cool#9992 lok doc sign, create-certs.sh password-less mode: still create a .p12
- cool#9992 lok doc sign, hash extract: initial getCommandValues('Signature')
- cool#9992 lok doc sign, hash extract: time for getCommandValues('Signature')
- cool#9992 lok doc sign, hash extract: digest for getCommandValues('Signature')
- cool#9992 lok doc sign, hash extract: add signatureTime parameter
- cool#9992 lok doc sign: add initial serialization of external signatures
- cool#9992 doc electronic sign: make return type for .uno:Signature consistent
- cool#10630 lok doc sign: fix Impress sign line when creating directly
- cool#10630 lok doc sign: fix Impress sign line when picking a certificate
- cool#10630 doc sign: fix Impress sign line, to be able to finish signing again
- cool#10630 lok doc sign: allow setting the pos of the Impress sign line
- cool#10630 lok doc sign: allow setting the size of the Impress sign line
- cool#10630 doc electronic sign: fix insertion of the signature line
- cool#10630 doc electronic sign: fix no graphic selection for the signature line
- cool#10630 doc electronic sign: move signature line tracking to the view
- cool#10630 doc electronic sign: unselect & reject reselect
- cool#10630 lok doc sign: reduce the default size of the signature line
Collabora Online commits:
- cool#9992 doc sign: fix update of the signature widget in the status bar
- cool#9992 doc sign: fix missing enable on the cert chooser description entry
- cool#9992 doc sign: better fix for the cert chooser dialog's disabled description widget
- cool#9992 doc sign: add sign button to the home tab of the notebookbar
- cool#9992 doc sign: local file wopi provider: allow setting the sign cert/key/ca
- cool#9992 doc sign: set the view's sign cert from the WOPI UserPrivateInfo
- cool#9992 doc sign: add a setting to be able to disable this
- cool#10220 doc sign: don't assume that user private data is a dict json
- cool#9992 doc sign: hide sign button when user pref doesn't provide cert or key
- cool#9992 doc sign: add signature creation cypress test
- cool#9992 doc sign: move sign key/cert init from doc init to sign dispatch
- cool#9992 doc sign: fix handling of saveas options containing spaces
- cool#9992 doc sign: add menu item for the compact UI
- cool#9992 doc sign: add UI to sign PDF files
- cool#9992 doc electronic sign: allow passing sign params from JS
- cool#9992 doc electronic sign: allow more user private info settings with make run
- cool#9992 doc electronic sign: add menu item to trigger hash extract
- cool#9992 doc electronic sign: send the hash to be signed
- cool#9992 doc electronic sign: actually sign the hash in a popup
- cool#9992 doc electronic sign: fetch the created signature
- cool#9992 doc electronic sign: serialize the fetched signature
- cool#9992 doc electronic sign: add cypress test
- cool#9992 doc electronic sign: add a provider selector dialog
- cool#9992 doc electronic sign: select the provider interactively
- cool#10630 doc electronic sign: improve error handling on bad client ID
- cool#10630 doc electronic sign: more human-readable names for providers
- cool#10630 doc electronic sign: add /cool/signature endpoint
- cool#10630 doc electronic sign: implement support for redirect-based providers
- cool#10630 doc electronic sign: expose the name of the document
- cool#10630 doc electronic sign: send the hash on the server
- cool#10630 doc electronic sign: get the signature on the server
- cool#10630 doc electronic sign: stop sending the secret to the client
- cool#10630 doc electronic sign: remove CSP rules
- cool#10630 doc electronic sign: configure the language of the popup
- cool#10630 doc electronic sign: add a country selector to the dialog
- cool#10630 doc electronic sign: add ISO country names
- cool#10630 doc electronic sign: send selected country to the server
- cool#10630 doc electronic sign: moved esign settings out of UserPrivateInfo
- cool#10630 doc electronic sign: support per-server private info during 'make run'
- cool#10630 doc electronic sign: default to a redirect-based provider
- cool#10630 doc electronic sign: set defaults without an index
- cool#10630 doc electronic sign: return dialog result without an index
- cool#10630 doc electronic sign: limit the offered providers based on the selected country
- cool#10630 doc electronic sign: sort the country & provider lists
- cool#10630 doc sign: expose visual signing
- cool#10630 doc sign: add visual signing testcase
- cool#10630 doc sign: allow setting the position / size of a visual signature
- cool#10630 doc electronic sign: handle visual signatures
- cool#10630 doc electronic sign: add a snackbar
- cool#10630 doc electronic sign: show the sign view dialog after esign
- cool#10630 doc electronic sign: remember the provider in localstorage
- cool#10630 doc electronic sign: show busy overlay while the popup is open
- cool#10630 doc electronic sign: close the popup on tab close
- cool#10630 doc electronic sign: avoid unwanted postmessage during sign
- cool#10630 doc electronic sign: fix no graphic selection on 2nd page
- cool#11002 kit: fix memory corruption in Document::handleSaveMessage()
- cool#10630 doc electronic sign: fix no SVG in graphic selection on 2nd page
- cool#10630 doc electronic sign: fix outgoing mouse messages on 2nd page
- cool#10630 doc electronic sign: fix outgoing transform pos on 2nd page
- cool#10630 doc electronic sign: fix outdated tile for shape move on 2nd page
Nextcloud richdocuments commits:
- feat: add personal setting to specify the CA chain for document signing
- feat: expose the documentSigningCa personal setting in the WOPI CheckFileInfo
- feat: document signing, add setting for the signing certificate & key, too (fixes #4123)
- feat: electronic signing, add settings for eIDEasy (fixes #4311)
Want to start using this?¶
You can get a development edition of Collabora Online 24.04 and try it out yourself right now: try the development edition.