Introduction
The eIDAS Advanced Electronic Signature (AdES) client, allows to sign documents and digests (hashes), using CAdES (CMS, binary data), JAdES (JSON), PAdES (PDF), XAdES (XML) signatures, as defined by the European Telecommunications Standards Institute (ETSI). These signatures are part of the eIDAS legal framework in the European Union. Next to PAdES it can also create and verify PKCS#7 PDF signatures. These are non-ETSI, but are the more common PDF signatures, provided by companies on Adobe’s Approved Trust List.
The purpose of this client is to easily create and verify eIDAS and PKCS#7 compliant signatures for documents and input data, using certificates which are stored in keystore files (PKCS#12) or using hardware (PKCS#11). Documents can be signed by providing the full document or by generating a hash/digest of the document first. Especially with remote signing REST APIs part of the Sphereon VDX platform, we suggest to create the digest first and then use the signature to merge with the original document. This means you are not sending the full document across the wire, which obviously is better from a privacy and security perspective.
Multiplatform library and REST API
This is a multiplatform Kotlin library. Right now it supports Java and Kotlin only. In the future Javascript/Typescript will be added. Please note that a REST API is also available that has integrated this client, allowing to generate and validate signatures using other languages. Next to Java/Kotlin, Javascript/Typescript a .NET SDK is available that integrates with the REST API. SDK code can be generated for other languages based upon the OpenAPI 3 spec provided with the REST API.
Signature flow
Creating a signed AdES document comprises several steps. It starts with the Original Data/Document, for which we first need to determine the Sign
Input. The SignInput
typically either is the full document, or a part of the document (PDF for instance). The determineSignInput
method which
requires the input document together with the signature type and configuration as parameters, automatically determines the Sign Input. The
determineSignInput can be run locally without the need to use a REST API for instance.
Next there are two options. Directly signing the SignInput
object using the createSignature
method, resulting in a signature, or creating a
Digest (Hash) of the SignInput
. Since the createSignature method could be using a remote REST service or remote Hardware Security Module for
instance, it is advisable to use the Digest method in most cases. The Digest method can be run locally, so even if the createSignature method needs to
access remote resources, no information from the original data/document would be sent across the wire. The digest method accepts a SignInput
object
as
parameter and results in another SignInput
object, with its sign method set to DIGEST
instead of the original method of DOCUMENT
.
The createSignature
method accepts the SignInput
object, which the signMode either being DOCUMENT
or DIGEST
, depending on which method was
chosen. It is using the supplied ‘KeyEntry’ or Key kid string to sign the input object. This can either be done locally or remotely depending on the
CertProvider implementation. The end result is a Signature
object.
Lastly the Signature
object needs to be merged with the original Document. It really depends on the type of signature being used how this is
achieved. The document could for instance become part of the signature (ENVELOPING), the signature could become part of the document (ENVELOPED), or
the signature could be detached (DETACHED)
The picture below gives a schematic overview of the process
It is possible to use multiple so called SignatureServices with the same KeyProvider. This allows for instance to extract bytes and create a digest/hash from the input file locally, while creating the signature using a REST API or Azure Keyvault for instance. Then the signature is recombined with the original document locally. The createSignature method and its counterpart verifySignature methods are typically ran using a REST API, Keyvault or locally with PKCS#11 hardware Key Providers. It is up to the caller to determine whether creating the digest/hash, and placing the signature in the input document also should run remotely or not.
For non Kotlin/Java environments we advise to setup the eIDAS Signature REST Microservice on premise, which connects to PKCS#11 hardware, a QTSP or Azure Keyvault remotely. Then use the REST endpoints, or use an SDK if available for your language. Please note that these SDKs typically have little local processing functionality unlike the Kotlin/Java library. The setup ensures that Personally Identifiable Information (PII) or other sensitive information doesn’t leave your premise, and that only the signature is being created remotely from the Digest/Hash value. It also allows you to use authentication and roles/authorization locally on a per key and configuration level.
License
The signature client (this library) and most integrations are licensed as LGPLv3, meaning they can be integrated into commercial products without a problem. Whenever changes are being made to the client or other libraries covered under this license and used by 3rd parties, the source-code containing the changes has to be made available.
The REST API is licensed as GNU AGPLv3 as opposed to the libraries and SDKSs. GNU AGPLv3 means that the changed source-code must be made available for parties interacting with the REST API.
Commercial clients paying a support fee or paying for on-premise products created by Sphereon get a perpetual commercial license for the particular version(s) in use instead of the LGPLv3/GNU AGPLv3 licenses, which doesn’t have the aforementioned source-code publication restrictions.