Technical¶
Components in the Add-on¶
Lime eSign uses the following different components in Lime CRM:
- Web components
- Static pages to host signing portal
- Custom endpoints
- Lime Newsletter for email templates
- TRAML
- Lime Gävle's BankID service
- Task Handler
- Data structure
- Security policies
- Lime Bootstrap apps
- Actionpads
- Runtime configuration in Lime Admin
- Application configuration
Security¶
Internal Integrity Checks¶
There are two main internal checks that is made to make sure the integrity of the data during the signing process, access token and document fingerprint.
Access Token¶
When a signing is created with Lime eSign, an access token is created for each signer. This means that each signer on each signing has a unique access token. The access token is stored in a separate property on the signer object in Lime CRM.
An access token is a sequence of numbers and letters and it contains credentials that identifies a user. Lime eSign is using python's secret library to generate a URL-safe text string that contains 32 random bytes to make sure that the user has correct access rights to transfer data between two parties.
A token is sent to the server everytime someone is doing one request to the server from the portal (for example when someone enters the portal). The server then validates if the token exists on a single signer in the database. If so the case, the request to the server will go through and the performed actions will be tied to that signer.
If the token doesn't exist on any signer or if it exists on several signers, an InvalidToken error will be raised and the request will return an HTTP 400 Bad Request error.
Document Fingerprint¶
A fingerprint is a sequence of numbers and letters and it is used to detect errors in the original data source. In Lime eSign, an industry standard 256 bit secure SHA256 hashing algorithm is used to generate fingerprints.
When a signing is created with Lime eSign, all documents that should be signed will be merged to a new PDF document called original document. The original document is stored as a file property on the signing object in Lime CRM. A fingerprint will be calculated based on this original document. This fingerprint will be stored in a separate property on the signing object in Lime CRM. This fingerprint is called Original Document Fingerprint and is used to check that the original document is not modified during the signing process.
A randomly generated UUID is also saved in the original_document, making it truly unique if exactly the same documents would be used for another signing.
Whenever a signer is requesting to view the original document (for example when the signer is entering the portal), a fingerprint is calculated based on the original document that is currently stored on the signing object. This newly calculated fingerprint is then compared with the Original Document Fingerprint that is stored on the signing object. If the fingerprints match, the signer will get access to the original document.
If the fingerprints do not match, then either the Original Document Fingerprint or the original document stored on the signing has been modified and a TamperedFile error will be raised and the signer won't get access to the original document.
What happens if someone with bad intentions changes the original document on the signing object and also replace the Original Document Fingerprint on the signing object, so it matches the new original document?
This is a case that is possible (only if PAdES isn't enabled) and it emphasizes the importance of installing Lime eSign according to the instructions! Lime eSign is tied with the same security level as Lime CRM.
External Integrity Checks¶
If using PAdES, the signed document is created at eServices, not at the Lime CRM server. When a signer signs the document using an electronic ID, the fingerprint of the document that was presented to the signer is saved with the signature at eServices' servers. A copy of this data is also saved in the Lime CRM server, but it is the data at eServices that is the master data. This means that:
-
It is not possible for someone with bad intentions to change the signing data, since the master is stored in a service strictly under Lime Technologies' control and not in the customer's Lime CRM database.
-
If someone with bad intentions replaces the document and the Original Document Fingerprint in Lime, as described in the previous section, it will not succeed because:
- The original document fingerprint stored in Lime CRM on the signing object is not used when creating the signed document at eServices.
- The original document saved in Lime CRM is uploaded to eServices when everybody has signed. The fingerprint of that document is then calculated and compared to the signatures stored at eServices. If the original document was changed, no signatures will match that fingerprint.
Verifying a Signed Document¶
PAdES signed PDF¶
When using eServices and PAdES, it is impossible to modify a signed document, since it is sealed with a certificate. To verify that the document has not been altered, open the document in Adobe Acrobat Reader. If everything is alright, a message stating "the document was certified by Lime Technologies" will be displayed. If the document has been altered, a warning will be displayed at the same location.
To get more in-depth information about the signature and certificate used, it is possible to click on the Lime eSign stamp on the verification page.
Warning
It is important to use Adobe Acrobat Reader. Most other PDF viewers, like the ones built into browsers or operating systems, often ignore the PAdES data in the PDF file - hence they do not warn if the PDF has been altered.
Classic Method of Verification¶
All documents signed with Lime eSign use an industry standard 256 bit secure SHA256 hashing algorithm to generate a digital fingerprint. Together with unique data collected from the signer, such as precise time, IP address and platform used, a digital signature is created.
When a document has been signed by all parties, an email is sent to the signer(s), containing the signed document together with the unique fingerprint ID of this document. The ID is made up of 32 letters and numbers, also known as a hash. Using standard tools, provided with most operating systems, the ID can be calculated for the signed document file and matched against the ID provided in the e-mail.
Example ID:
b0b4fcae7531a0509fc1f29e814ea59487c38787df671e6bc04b17ee355b24f3
If the ID calculated for the signed document file matches the ID provided in the e-mail, and the e-mail is sent from a trusted source, there is strong evidence for the document being valid.
Using Microsoft Windows¶
Open the Command Prompt (cmd.exe) and change the directory to where the document file is located. To calculate the ID for the document, run:
>certutil -hashfile document.pdf SHA256
where document.pdf
is the name of the document file.
If successful, the result should look similar to:
(the ID has been emphasised in red)
Using Linux or macOS¶
Open a terminal session and change the directory to where the document file is located. To calculate the ID for the document, run:
>shasum -a 256 document.pdf
where document.pdf
is the name of the document file.
If successful, the result should look similar to:
b0b4fcae7531a0509fc1f29e814ea59487c38787df671e6bc04b17ee355b24f3
Note
This method also works on documents signed with PAdES, although this defeats the purpose of PAdES!
user_non_visible_data in Secure Signatures¶
Lime Technologies is storing all information connected to a Lime Signatures (Criipto) or Swedish BankID signature made with Lime eSign. The URL to the digital quittance of the signing is included on the verification page in the signed PDF.
Lime eSign is connecting each signature with the original document's fingerprint. This information is accessible via the user_non_visible_data field at the centralized Lime Technologies service and can be used to match the original document's fingerprint in the verification pages.
The user_non_visible_data value in Lime Technologies Gävle AB is base64 encoded. To retrieve the original document's fingerprint do as follows:
Using Microsoft Windows¶
Put the user_non_visible_data string from Lime Technologies Gävle AB in a txt file, input.txt for example.
Open the Command Prompt (cmd.exe) and change the directory to where the input.txt file is located. To decode the file, run:
>certutil -decode input.txt output.txt
where input.txt is the name of the file where the user_non_visible_data from Lime Technologies Gävle AB is stored. output.txt is the name of the file where the result will end up. If successful, the content of output.txt should look similar to:
{"file": number, "file_name": string, "original_document_fingerprint": string}
Using Linux or macOS¶
Open a terminal session and run:
>echo <user_non_visible_data> | base64 --decode
where <user_non_visible_data> is the string retrieved from Lime Technologies Gävle AB. The result should look something like this:
{"file": number, "file_name": string, "original_document_fingerprint": string}
Lime Signatures Service¶
If Lime Signatures Service is used as signing service. All calls to the service requires an API key and a customer specific token which ensure secure and authorized access.
Signing Portal Access¶
A user can sign a document that has been sent for signing via the signing portal. The signing portal can be accessed through a unique link that has been generated for each signer.
Every request made from the portal is made using an impersonate user. The impersonate user can never be used to log into the system. It can only be used within Python code on the Lime CRM server, and only if it has been granted access to the requested endpoint.
Table and Field Definitions Lime CRM¶
These tables and fields must be created before you can use Lime eSign.
Table database name: signing
Field | Field type | Note |
---|---|---|
title | Text (1024) | |
metadata | Text (4000) | |
originaldocumentfingerprint | Text (300) | |
signeddocumentfingerprint | Text (300) | |
signingstatus | Option | Options: empty , created , sent , opened , partlysigned , signed , canceled , error |
order | Integer | Default value = 1 |
methods | Set | Options: empty , bankid_se , bankid_no , mitid_da , ftn_fi ,checkbox , signature |
originaldocument | File | |
sentdate | Date & Time | |
signeddate | Date & Time | |
coworker | Relation | |
signeddocument | Relation | |
document | Relation | |
signer | Relation | |
history | Relation | |
additional limetype |
Relation | Can be configured during the installation. |
Table database name: signer
Field | Field type | Note |
---|---|---|
name | Text (83) | |
Text (100) | ||
token | Text (64) | |
methoddata | Text (2048) | |
role | Option | Options: empty , signer , viewer , approver |
signerstatus | Option | Options: created , sent , notified , opened , signed , approved , canceled , error |
method | Option | Options: empty , bankid_se , bankid_no , mitid_da , ftn_fi , checkbox , signature |
order | Integer | Default value = 1 |
sentdate | Date & Time | |
notifieddate | Date & Time | |
lastopeneddate | Date & Time | |
approveddate | Date & Time | |
signeddate | Date & Time | |
signing | Relation | |
history | Relation | |
signer parent |
Relation | Can be configured during the installation. |
Signing Portal¶
Browser support¶
The signing portal is supporting the same browsers as lime-elements since it is built based on these components. Click here to see which browsers that are supported. It is impossible to access the signing portal with a browser that is not supported.
Signing Verification Pages¶
Lime eSign will generate verification pages when the signing is completed. These pages are attached to the original document and will together make up the signed document. Below are tables that explains the content of the verification pages.
Document information¶
Parameter | Description |
---|---|
Name | The descriptive name for current document that has been signed. |
Sent by | Person who has sent the document for signing. |
Sent date | UTC formatted timestamp when the document was sent for signing. |
Signed by all parties | UTC formatted timestamp when the document was signed by all parties. |
Signing/transaction ID | The ID of the signing object in the application. |
Original document file ID | The ID of the actual file. |
Original document fingerprint | The unique fingerprint for the document that has been sent for signing. This fingerprint is taken without the verification pages! |
Signer information¶
Parameter | Available for signing method | Description |
---|---|---|
Name | All | The name of the signer. |
All | The e-mail to the signer. | |
Signed date | All | UTC formatted timestamp when the signer signed the document. |
Signing method | All | Which signing method the signer used. |
IP address | All | For Swedish BankID: The IP address is fetched from the signing service which means that the IP address is from the device that the signer signed with. For other signing methods: The IP address is fetched from the device that was used to finalize the signing in the signing portal. Several IP addresses could occur, when the signing request goes through several proxies. |
Browser | All | The browser that was used to view the document when the signer signed. |
Platform | All | The platform that was used to view the document when the signer signed. |
Personal identification | All electronic signatures | The personal identification of the signer |
Transaction id | All electronic signatures | Lime Gävle's BankID service's unique transaction ID that is connected to the official BankID signature. |
Receipt url | All electronic signatures | URL that displays the recipe of Lime Gävle's BankID service's transaction. |
Internal Endpoints¶
The following endpoints are used by the Lime clients and use regular sessions as authentication.
Initialize Signing¶
GET¶
/signing/init/
Get all relevant information to initialize a signing from document ids. It's used by the create signing dialog in the client apps. The response could be used as the base of a new signing and sent to the POST signing endpoint to create the signing.
Payload:
{
"documents": [1003]
}
Response:
{
"signers": [
{
"limetype": "coworker",
"id": 1002,
"name": "Carlito Jakobsson",
"email": "[email protected]",
"default": false,
"limetypeLocalname": "Medarbetare"
},
{
"limetype": "person",
"id": 1039,
"name": "Mari Ahna",
"email": "[email protected]",
"default": false,
"limetypeLocalname": "Person"
},
{
"limetype": "person",
"id": 1051,
"name": "Peter Johansson",
"email": "[email protected]",
"default": false,
"limetypeLocalname": "Person"
}
],
"methods": [
{
"text": "Swedish BankID",
"value": "bankid_se",
"default": true
},
{
"text": "Checkbox",
"value": "checkbox",
"default": false
}
],
"title": "JAS 39",
"languages": ["da", "de", "en_us", "fi", "nl", "no", "sv"],
"message": "Carlito Jakobsson wants you to sign JAS 39.",
"documents": [
{
"limetype": "document",
"id": 2044,
"type": {
"value": "agreement",
"text": "Agreement"
},
"name": "JAS 39",
"file": {
"filename": "JAS.pdf",
"extension": "pdf",
"id": 48164,
"size": 1149314,
"mimetype": "application/pdf"
},
"url": "https://lime_server/app_name/api/v1/file/48164/contents/"
}
]
}
Signing¶
GET¶
/signing/<int:signing_id>/
Fetch a specific signing.
Response:
{
"coworker": {
"limetype": "coworker",
"id": 1002,
"name": "Nisse Jensen",
"email": "[email protected]",
"phone": "046-123456",
},
"originalDocument": {
"extension": "pdf",
"filename": "JAS 39 (bundle).pdf",
"id": 49275,
"mimetype": "application/pdf",
"size": 1149314,
"url": "https://lime_server/app_name/api/v1/file/49275/contents/"
},
"signingService": "criipto",
"methods": [{ "text": "Checkbox", "value": "checkbox" }],
"signedDocument": {
"file": {
"extension": "pdf",
"filename": "JAS 39 (signed).pdf",
"id": 49276,
"mimetype": "application/pdf",
"size": 1402673,
"url": "https://lime_server/app_name/api/v1/file/49276/contents/"
},
"id": 3071,
"limetype": "document",
"name": "JAS 39 (signed)",
"type": { "text": "Signed agreement", "value": "signedagreement" }
},
"signers": [
{
"email": "[email protected]",
"name": "Camilla Bangsgaard",
"order": 1,
"role": {
"value": "viewer",
"text": "Viewer"
},
"duty": null
},
{
"name": "Peter Johansson",
"email": "[email protected]",
"order": 2,
"role": {
"value": "viewer",
"text": "Viewer"
},
"duty": null
}
],
"id": 1007,
"status": { "text": "Signed", "value": "signed" },
"title": "JAS 39",
"portalUrl": "https://lime_server/app_name/limepkg-esign/portal/?app=app_name&token=adshg8j233ej" // Personal portal URL for the logged in coworker if he/she is one of the signers
}
POST¶
/signing/
Creates a signing, preferably to be based on a response from the Init endpoint. Example payload:
{
"signers": [
{
"limetype": "person",
"id": 1004,
"email": "[email protected]",
"name": "Camilla Bangsgaard",
"order": 1,
"role": "signer",
"duty": "sign"
},
{
"limetype": "person",
"id": 1051,
"name": "Peter Johansson",
"email": "[email protected]",
"order": 2,
"role": "viewer",
"duty": null
},
{
"limetype": "coworker",
"id": 1010,
"name": "Nisse Jensen",
"email": "[email protected]",
"order": 1,
"role": "approver",
"duty": "approve"
}
],
"documents": [1006],
"meta": {
"subject": "Document to sign",
"message": "Greetings friend, please sign this document or else...",
"language": "en_us"
},
"title": "Protection agreement",
"methods": ["bankid_se", "checkbox"]
}
Returns the signing in the same format as the GET method.
DELETE¶
/signing/<int:signing_id>/
Cancels a signing. Returns the signing in the same format as the GET method.
Status¶
GET¶
/status/<string:limetype>/<int:limeobject_id>/
Fetches the status and the context of the limeobject. If there's one or more signings connected to the limeobject, a list of signings will be returned. This endpoint is used to quickly see if a limeobject is/has a signing or if it's qualified to create a signing from.
Context can be one of the following:
signing
- the limetype in the URL is configured as the Signing limetypedocument
- the limetype in the URL is configured as the Document limetyperelation
- the limetype in the URL configured as a Additional limetypenot_configured
- the limetype in the URL is not configured to be used with eSign in any context
If there's possibility to create a signing, a list of potential documents will be returned with the following rules depending on context:
document
returns a list of potential documentsrelation
returns a list of potential documents only if the optional argument force_docs=1 is supplied (this is due to performance reasons)- in all other cases the potential documents list will be empty
Example on an existing signing:
/status/signing/1006/
{
"context": "signing",
"potentialDocuments": [],
"signings": [
{
"id": 1006,
"limetype": "signing",
"status": {
"text": "signing.signingstatus.option.created",
"value": "created"
},
"title": "The Sign"
}
],
"coworker": {
"limetype": "coworker",
"id": 1002,
"name": "Nisse Jensen",
"email": "[email protected]",
"phone": "046-123456",
}
}
Example on a document:
/status/document/1033/
{
"context": "document",
"potentialDocuments": [
{
"file": {
"extension": "pdf",
"filename": "mothership.pdf",
"id": 40101,
"mimetype": "application/pdf",
"size": 2372002,
"url": ""
},
"id": 1033,
"type": "other"
}
],
"signings": [],
"coworker": {
"limetype": "coworker",
"id": 1002,
"name": "Nisse Jensen",
"email": "[email protected]",
"phone": "046-123456"
}
}
Example on a relation:
/status/deal/2089/?force_docs=1
{
"context": "relation",
"potentialDocuments": [
{
"file": {
"extension": "pdf",
"filename": "mothercar.pdf",
"id": 1,
"mimetype": "application/pdf",
"size": 2371234562,
"url": ""
},
"id": 2089,
"type": "other"
}
],
"signings": [],
"coworker": {
"limetype": "coworker",
"id": 1002,
"name": "Nisse Jensen",
"email": "[email protected]",
"phone": "046-123456"
}
}
Example on a relation (without force_docs):
/status/deal/2089/
{
"context": "relation",
"potentialDocuments": [],
"signings": [],
"coworker": {
"limetype": "coworker",
"id": 1002,
"name": "Nisse Jensen",
"email": "[email protected]",
"phone": "046-123456"
}
}
Resume¶
POST¶
/signing/resume/<int:signing_id>/
Resumes a signing. Returns the checkpoint the resuming starts from, eg the next after the last succesful one.
Response:
{
"isoDatetime": "",
"path": "signing_complete.create_signed_document_file"
}
Portal Endpoints¶
The following endpoints are used by the portal and uses a token as authentication.
Signing¶
GET¶
/portal/signing/<string:token>/
Get the signing for a specific signer using the signer's token.
{
"signer": {
"duty": "view",
"email": "[email protected]",
"name": "Camilla Bangsgaard",
"order": 1,
"role": {
"value": "viewer",
"text": "Viewer"
},
"status": {
"text": "Notified",
"value": "notified"
}
},
"signing": {
"coworker": {
"email": "[email protected]",
"id": 1001,
"limetype": "coworker",
"name": "Carlito Jakobsson",
"phone": "08-7020090"
},
"id": 3065,
"signingService": "criipto",
"methods": [
{
"text": "Checkbox",
"value": "checkbox"
}
],
"originalDocument": {
"extension": "pdf",
"filename": "JAS (bundle).pdf",
"id": 729301,
"mimetype": "application/pdf",
"size": 1147798,
"url": "https://lime_server/limepkg-esign/app_name/portal/original_document/RpBvgNLpxED3DVEklgI89BQCl-w7cw5_WxvAeCHTy_g/"
},
"signers": [
{
"duty": "view",
"email": "[email protected]",
"name": "Camilla Bangsgaard",
"order": 1,
"role": {
"value": "viewer",
"text": "Viewer"
},
"status": {
"text": "Notified",
"value": "notified"
}
}
],
"status": {
"text": "Sent",
"value": "sent"
},
"title": "JAS 39"
}
}
Original Document¶
GET¶
/portal/original_document/<string:token>/
Gets the original document file.
Signed Document¶
GET¶
/portal/signed_document/<string:token>/
Gets the signed document file.
BankID Signing Method¶
POST¶
/portal/sign/bankid/<string:personal_number>/<string:token>/
Initiate a BankID signing using Lime BankID SV Service.
Response:
{
"success": "bool",
"transaction_id": "string",
"auto_start_token": "string"
}
The BankID transaction_id is then used with the GET endpoint below.
GET¶
/portal/sign/bankid/<string:personal_number>/<string:transaction_id>/<string:token>/
Gets the status of an ongoing BankID signing with Lime BankID SV Service.
Response:
{
"bankidStatus": "PENDING"
}
Keep polling the endpoint if "PENDING".
{
"bankidStatus": "COMPLETE",
"signer": {...},
"signing": {...}
}
Successful BankID signing when "COMPLETE".
Criipto Signing Method¶
POST - Initialize¶
/portal/sign/criipto/initialize/<string:auth_type>/<string:token>/
Initialize a BankID signing using Lime Signatures Service. See the swagger documentation of Lime Signatures Service for all available auth_types.
Response:
{
"redirect_url": "string"
}
The application should redirect the user to the redirect_url.
POST - Finalize¶
/portal/sign/criipto/finalize/<string:state>/<string:token>/
Finalize a BankID signing using Lime Signatures Service. State parameter can be fetched from the query parameters in the return url that the user is redirected to after the signing is performed.
Response:
{
"signer": {...},
"signing": {...}
}
The transaction is now completed.
GET - AuthTypes¶
/portal/sign/criipto/auth_types/<string:signing_method>/<string:token>/
Get available authentication types from Lime Signatures Service for one signing method.
Response:
[
{
"text": "string",
"value": "string"
}
]
Checkbox Signing Method¶
POST¶
/portal/sign/checkbox/<string:token>/
Sign the signing with checkbox.
Payload:
{
"signed": true
}
Response:
{
"signer": {..},
"signing": {..}
}
Translation¶
Gets all translations for eSign from the .po-files. Used by the portal.
GET¶
/portal/translation/
Events¶
The events below are published by eSign.
esign.signing.created¶
A new signing was created.
{
"signing_id": 90
}
esign.signing.sent¶
The signing was sent to everyone at the current or lower order.
{
"signing_id": 90
}
esign.signer.reminded¶
A signer is reminded about the signing process.
{
"signer_id": 70200,
"signing_id": 90
}
esign.signing.completed¶
A signing has been completed.
{
"signing_id": 90
}
esign.signing.canceled¶
A signing has been canceled.
{
"signing_id": 80
}
esign.signer.opened¶
A signer opened the portal.
{
"signer_id": 70200,
"signing_id": 90
}
esign.signer.signed¶
A signer has signed.
{
"signer_id": 70200,
"signing_id": 90
}
esign.signing.error¶
A signing has changed status to error.
{
"signing_id": 80
}
Signing Versioning¶
PADES (2)¶
The signing is compatible for use with PAdES.
RESUME (1)¶
With the introduction of checkpoints, the following properties were added to metadata
:
version
- used for versioning the signingprevious_status
- keeps track of the previous status of the signingcheckpoint
- object storing thename
of the last completed checkpoint and thedatetime
ANCIENT (0 a.k.a. None)¶
The original signing structure.