Secure Document Signing in Crayonic Gateway
Technical Specification
1. Overview
Crayonic Gateway™ (CGW) is a “FIDO2 ready” open source Identity and Access Management solution based on Red Hat Keycloak. It makes it easy to secure applications and services with little to no code.
This document describes specifications for the Secure Signing of Documents feature using the Crayonic KeyVault (CKV) in CGW.
2. Process Description
2.1 Entities used in the signing process
-
Crayonic Gateway (CGW) - the Identity and Access Management server
-
Crayonic KeyVault (CKV) - the FIDO2 biometric authentication device
-
Document Service Provider (DP) - the server/service that provides documents to be signed
2.2 Prerequisites / Expectations
-
All communication between CGW and DP is over HTTPS only, using HTTP results in an error
-
Authentication/Authorization protocol in API shall be agreed with DP
-
There are two integration options of secure document signing depending on the agreed scope
-
Full integration option:
-
This option includes user authentication and simple management of documents to be signed
-
getDocsToSign and postDocInfo endpoints are used
-
User authentication in CGW is done via OpenID Connect + WebAuthn, using CKV for biometric authentication of the user
-
Users in DP are linked to users in CGW via "realm/username" credentials that are present in DP's database. DP shall identify the correct user based on these credentials and provide CGW with a list of documents that are to be signed by the given user.
-
-
Lite integration option:
-
This option covers simple document signing
-
Only signDoc endpoint is used
-
User authentication is not required and users in DP don't need to be linked to users in CGW
-
2.3 Authentication/Authorization in API
To ensure API security, all API calls shall use one of the following methods (TBA with DP):
-
Bearer token
-
API Keys
-
a popular method used to secure API endpoints
-
DP is assigned an API key, which is then included in the header of all API calls. Only valid API keys coming from registered hostname are processed by CGW
-
-
OAuth1 - Digest Scheme
-
Popular, tested, secure, signature driven, well-defined protocol
-
Uses cryptographic signature, which is a mix of a token secret, nonce, and other request based information
-
-
OAuth2 - Bearer Token Scheme
- works with authentication scenarios called flows, these flows include: Authorization Code flow, Implicit flow, Resource Owner Password flow, Client Credentials flow
-
OpenID Connect Discovery
-
Based on the OAuth 2.0 protocol
-
Uses a sign-in flow that permits user authentication and information access by a client app
-
User information is encoded via a secure JSON Web Token (JWT)
-
2.4 Endpoints list
API Endpoints accept form-encoded request bodies, return JSON-encoded responses, and use standard HTTP response codes and authentication.
2.4.1 Full Integration option:
These endpoints are called via HTTPS POST and are located at DP site.
-
getDocsToSign - retrieves the list of documents that are waiting to be signed by the user identified through provided realm/username parameters
-
postDocInfo - accepts information about the signed document from CGW for further processing
2.4.2 Lite Integration option:
One HTTPS POST endpoint is located at the CGW side:
- signDoc - expects documentHash which is then signed by the user using CKV (biometric authentication) and returns signedDocumentHash
2.5 Signing Process - Full integration
-
[1] Navigate to Crayonic Gateway Login Screen
-
[2] Click on the Usernameless button and authenticate using CKV
-
[3] Navigate to Sign Documents section
-
[4] Click on Retrieve Documents to sign button
-
[5] CGW calls getDocsToSign - a DP endpoint, and retrieves metadata of documents that should be signed by the user, including DocumentHash which holds data to be signed
-
[6] CGW shows all documents that are waiting to be signed on the user's screen
-
[7] Click on Document Name to select Document to sign
-
[8] CGW shows Document Preview screen - displays Document Preview of the document to be signed
-
[9] Click on Sign Document button
-
[10] CGW calls internal signDocument method
-
CGW connects to CKV and provides DocumentHash for the selected document
-
[11] CKV requests user verification via WebAuthn protocol (e.g. fingerprint/PIN/written PIN/voice)
-
[12] CKV displays provided DocumentHash on LCD screen for the user to verify
-
[13] User confirms e-signing operation on CKV (WebAuthn)
-
[14] CKV signs provided DocumentHash with user's certificate stored on CKV
- optional: user can select a certificate that will be used for signing
-
[15] CKV returns signedDocumentHash
-
-
[16] CGW displays signedDocumentHash and certificate used on screen
-
[17] CGW calls postDocInfo
-
CGW calls DP endpoint and provides the status of the signing operation, including signedDocumentHash
-
DP marks the document as signed and it is no longer provided in getDocsToSign
-
2.6 Signing Process Diagram - Full integration
2.7 Signing Process - Lite integration
-
[1] DP displays Document Preview of the document to be signed along with Sign Document button
-
[2] User clicks on Sign Document button
-
[3] DP calls CGW endpoint signDoc - and posts metadata of document that should be signed, this includes at a minimum:
- documentHash - hash of a document that is requested to be signed
-
[4] CGW calls internal signDocument method
-
[5] CGW connects to CKV and provides DocumentHash for the selected document
-
[6] CKV requests user verification via WebAuthn protocol (e.g. fingerprint/PIN/written PIN/voice)
-
[7] User confirms e-signing operation on CKV (WebAuthn)
-
[8] CKV signs provided DocumentHash with user's certificate stored on CKV
-
[9] CKV returns signedDocumentHash to CGW
-
-
[10] CGW returns signedDocumentHash, certificate, and status in signDoc response to DP
2.8 Signing Process Diagram - Lite integration
3. DP Endpoints
3.1 getDocsToSign
CGW calls this API endpoint via HTTPS POST method to retrieve the list of documents that are waiting to be signed by the user identified through provided realm/username parameters.
-
request method: POST
-
request endpoint: /cgw/docs/tosign (e.g. https://DP-site/cgw/docs/tosign) - To be defined by DP
-
request/response payload format: JSON
3.1.1 Request
Each user in CGW is identified by a value pair "realm/username". DP shall return list of documents for a given user based on these credentials.
CGW provides to DP:
-
username (string)
-
username is a unique handle for each user in a given CGW realm
-
it is used during login to CGW
-
-
realm (string)
-
refers to an object managing a set of users along with their credentials, roles, and groups. A user in CGW belongs to only one realm and the user who logs in to CGW will log into that user's realm
-
this value usually refers to the company name for hosted realms. The default value for the test/demo realm at crayonic.io is "gateway"
-
3.1.2 Response status codes
All responses shall return the status code in the header and JSON payload in the body.
-
Success: 200
-
Error - Bad request: 400 - a client error, e.g. malformed request syntax, invalid request message framing, or deceptive request routing
-
Error - Authorization error: 401 - authorization has been refused for provided credentials
3.1.3 Response success
DP returns:
-
documents (array) - an array of documents waiting to be signed by provided realm/user. For each item in the array, the following information is provided:
-
docId (string) - unique document ID (format specified by DP)
-
docPreviewURL (string) - URL link to document preview HTML page (link specified by DP)
-
documentHash (string) - hash of a document to be signed (format specified by DP)
-
3.1.4 Response error
DP returns:
-
error (string)
- Error message
3.1.5 Examples
Request example (body):
{
"username": "demouser",
"realm": "gateway"
}
Response - Success example (body):
{
"documents": [
{
"docId": "d66fd640-49bf-4b72-af53-937df3e08800",
"docPreviewURL": "https://site.sk/docs/preview/d419565e-57cd-430b-a2b7-da9e9f48c1b8.html",
"documentHash": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
},
{
"docId": "8fc6ed5e-f3f0-4555-9edc-0d6c5ec573b0",
"docPreviewURL": "https://site.sk/docs/preview/ea529ea4-855c-4676-8f91-3bf645b65b56.html",
"documentHash": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
},
...
]
}
Response - Error example (body):
{
"error": "Invalid request parameters"
}
3.2 postDocInfo
CGW calls this API endpoint via the HTTPS POST method to provide information about the signed document back to DP for further processing. Based on the provided information, DP shall either flag the document as "signed" or "not signed" in internal DB. Once the document is flagged as "signed", it should no longer be provided in the response of getDocsToSign call.
-
request method: POST
-
request endpoint: /cgw/docs/signed (e.g. https://DP-site/cgw/docs/signed) - To be defined by DP
-
request/response payload format: JSON
3.2.1 Request
Each user in CGW is identified by a value pair "realm/username". DP receives information about the signed document for a given user based on these credentials.
CGW provides to DP:
-
username (string)
- username is a unique handle for each user in a given CGW realm
-
realm (string)
- refers to an object managing a set of users along with their credentials, roles, and groups. A user in CGW belongs to only one realm and the user who logs in to CGW will log into that user's realm
-
docId (string)
-
unique document ID (format specified by DP)
-
value is taken from getDocsToSign response
-
-
documentHash (string)
-
the original hash of a document that was requested to be signed
-
value is taken from getDocsToSign response
-
-
signedDocumentHash (string)
- the hash of a document that was signed by the user
-
certificate (string)
- a certificate that was used to sign documentHash
-
status (string)
-
confirmation whether document signing operation was successful
-
ok - user successfully signed the document which is provided in signedDocumentHash
-
any other value - the document was NOT successfully signed.
-
3.2.2 Response status codes
All responses shall return status code in HTTPS header and JSON payload in body.
-
Success: 200
-
Error - Bad request: 400 - a client error, e.g. malformed request syntax, invalid request message framing, or deceptive request routing
-
Error - Authorization error: 401 - authorization has been refused for provided credentials
3.2.3 Response success
No JSON payload response in the body apart from status code 200 in the header is expected.
3.2.4 Response error
In case additional information about the error is needed, DP can return this information as a JSON payload in the body:
-
error (string)
- Error message
3.2.5 Examples
Request example (body):
{
"username": "demouser",
"realm": "gateway",
"docId": "d66fd640-49bf-4b72-af53-937df3e08800",
"documentHash": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII",
"signedDocumentHash": "9ce1488bbe2a879ec8b345a6e1b275628cacf36ddfc946671ee74400000049002437366464313237632d626539632d346666332d383165322d3266353164363665623066304e00026d32",
"certificate": "-----BEGIN CERTIFICATE----- MIIGIzCCBQugAwIBAgITEQAAAS7Aw5wqRBromgAAAAABLjANBgkqhkiG9w0BAQsF ... ",
"status": "ok"
}
Response - Success example (body):
{}
Response - Error example (body):
{
"error": "Signed Document processing error"
}
4. Crayonic Gateway Endpoints
4.1 signDoc
It is possible to use this API Endpoint to perform a lightweight e-signing flow. No user authentication is performed apart from authenticating the user via CKV during the e-signing process. A certificate used to sign provided documentHash is taken from CKV. Authorization (e.g. API keys) can be agreed and enforced.
DP calls this API endpoint via HTTPS POST method, provides data listed in Request section and CGW returns signedDocumentHash along with additional data back to DP for further processing.
-
request method: POST
-
request endpoint: /cgw/docs/signDoc (e.g. https://crayonic.io/cgw/docs/signDoc)
-
request/response payload format: JSON
4.1.1 Request
DP provides to CGW:
-
userid (string) - optional
-
userid is a unique user identifier in DP - this is the person that will be signing the document
-
can be uuid or email address or username
-
-
docId (string) - optional
- unique document ID (format specified by DP)
-
docPreviewURL (string) - optional
-
URL link to document preview HTML page (link specified by DP)
-
used only in case CGW is expected to display document preview
-
-
documentHash (string)
- the hash of a document that is requested to be signed
4.1.2 Response status codes
All responses shall return status code in HTTPS header and JSON payload in the body.
-
Success: 200
-
Error - Bad request: 400 - a client error, e.g. malformed request syntax, invalid request message framing, or deceptive request routing
-
Error - Authorization error: 401 - authorization has been refused for provided credentials
4.1.3 Response success
CGW returns:
-
userId (string) - userID provided in request
-
docId (string) - unique document ID - same as in request
-
documentHash (string) - hash of document that was used in the e-sign operation and provided in the request (format specified by DP)
-
signedDocumentHash (string)
- the hash of a document that was signed by the user using CKV
-
certificate (string)
- a certificate that was used to sign documentHash
-
status (string)
-
confirmation whether document signing operation was successful
-
ok - user successfully signed the document which is provided in signedDocumentHash
-
any other value - the document was NOT successfully signed.
-
4.1.4 Response error
In case additional error information is available, CGW returns this information as a JSON payload in the body:
-
error (string)
- Error message
4.1.5 Examples
Request example (body):
{
"userid": "demouser@gmail.com",
"docId": "d66fd640-49bf-4b72-af53-937df3e08800",
"docPreviewURL": "https://site.sk/docs/preview/ea529ea4-855c-4676-8f91-3bf645b65b56.html",
"documentHash": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII"
}
Response - Success example (body):
{
"userid": "demouser@gmail.com",
"docId": "d66fd640-49bf-4b72-af53-937df3e08800",
"documentHash": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII",
"signedDocumentHash": "9ce1488bbe2a879ec8b345a6e1b275628cacf36ddfc946671ee74400000049002437366464313237632d626539632d346666332d383165322d3266353164363665623066304e00026d32",
"certificate": "-----BEGIN CERTIFICATE----- MIIGIzCCBQugAwIBAgITEQAAAS7Aw5wqRBromgAAAAABLjANBgkqhkiG9w0BAQsF ... ",
"status": "ok"
}
Response - Error example (body):
{
"error": "Error during e-signing process: Operation timeout."
}
5. CGW Internal Methods
All listed methods are part of CGW installation and hosted either on-premise or in AWS cloud at crayonic.io.
Document Signing Workflow is implemented in Account Management Console template (/themes/gateway/account/) using ES6 Javascript.
By default, the certificate used to sign documentHash is a FIDO2 certificate stored on CKV.
5.1 signDocument
-
input: docId, documentHash
-
output: signedObject = { status: result, signedDocumentHash: signedDocumentHash, certificate: certificateUsedToSign }
const signDocument = function (docId, documentHash) {
// connect to KeyVault and sign documentHash with user's certificate
// return signedObject
const signedObject = {
status: result,
signedDocumentHash: signedDocumentHash,
certificate: certificateUsedToSign
}
return signedObject;
}