Key Provider Service
The Key Provider Service allows to manage public/private keys and Certificates using either a PKCS#12 keystore file as byte array or filepath. It also has support for PKCS#11 hardware (HSM and USB cards) as well as support for a Remote REST Key Provider and a Azure Keyvault/Managed HSM Key Provider. Next to certificate/key management a Key Provider also is responsible for creating and verifying signatures themselves. Other operations, like creating a hash, merging a signature into an input document are handled by a Signature Service instead of the Key Provider. A Single Key Provider can be shared by different Signature Services, as explained above
Given the wide range of supported import/creation methods, this library does not create or import keys/certificates. The REST API does have support for it. Please use your method of choice ( see below for some pointers).
PKCS#12 Keystore Key Provider Service
The below example in Kotlin sets up a Key Provider Service using a PKCS#12 keystore file at a certain path
Use existing tooling to create a certificate and PKCS#12 keystore
How to generate and/or import X.509 certificates and PKCS#12 keystores is out of scope of this project, but we provide some hints below. There are numerous resources on the internet to create X.509 certificates and PKCS#12 keystores.
Creating a PKCS#12 keystore using OpenSSL
The private key and certificate must be in Privacy Enhanced Mail (PEM) format (for example, base64-encoded
with ----BEGIN CERTIFICATE---- and ----END CERTIFICATE----
headers and footers).
Use the following OpenSSL commands to create a PKCS#12 file from your private key and certificate. If you have one certificate, use the CA root certificate.
If you have a chain of certificates, combine the certificates into a single file and use it for the input file, as shown below. The order of certificates must be from server certificate to the CA root certificate.
See RFC 2246 section 7.4.2 for more information about this order.
When prompted, provide a password for the new keystore.
PKCS#11 Hardware Security Module and Card based Key Provider Service
The PKCS#11 Key Provider allows you to use Hardware Security Based solutions that can interact using a PKCS#11 interface. It needs access to the driver library in order to operate.
Azure Keyvault or Managed HSM Key Provider Service
An Azure Keyvault Key Provider uses Azure Keyvault and Azure Managed HSM to retrieve certificates, create the Signature and verify a signature. The below example in Kotlin sets up a Key Provider Service using Azure Keyvault or Azure Managed HSM. Both Keyvault and Managed HSM support Hardware Security Modules. The Managed HSM service is Microsoft’s solution for an HSM not shared with other customers/tenants.
Note: Although the Azure Key Provider should work with Azure Managed HSM, the library is not being tested against Azure Managed HSM, as opposed to Azure Keyvault.
REST Key Provider
The REST Key Provider uses REST to get Keys/Certificates It also exposes the createSignature and verifySignature methods as REST endpoints. Lastly other methods like creating a digest, determineSignInput and placing the signature in the original document could also be executed remotely if desired. This is however handled by the RESTClientSignatureService.
Authentication and Authorization support
The REST Key Provider has OAuth2, OpenID Connect and bearer token support integrated.
OAuth2 support
The REST Key Provider client has support for oAuth2 and by extension OpenID Connect. Access to the OAuth2 functionality can be
achieved by
invoking the oauth()
method on the REST Key Provider after providing the appropriate configuration:
Bearer Token and JWT support
The REST Key Provider client has support to include bearer tokens (JWTs) in the authentication header. Access to the JWT functionality can be achieved by invoking the bearerAuth() method on the REST Key Provider after providing the appropriate configuration:
OAuth2, OpenID Scopes
The REST Microservice can be configured to support scopes. It is supported for both OAuth2 and OpenID Connect. Scopes are optional and when enabled, protect the API endpoints from users not having access to a certain scope at an endpoint level.
The available scopes are:
- read:vdx_sign_key: Read/List keys
- admin:vdx_sign_key: Administer keys
- sign:vdx_sign_key: Sign using keys
- read:vdx_sign_config: Read configurations
- admin:vdx_sign_config: Create and update configurations
Please note that this doesn’t provide protection at an individual configuration nor key level. For these there is role support. The eIDAS REST MS documentation provides more info on this subject.
To enable scopes, you have to use your IAM solution of choice which supports oAuth2 or OpenID Connect and ensure that the appropriate scopes are requested from the IAM solution. How this works is different per IAM and outside the scope of this README.
The REST Key Provider can set the scopes before requesting the tokens using the configuration as shown above. You can also programmatically set the scopes:
Roles support
The REST Microservice has role based support. It is possible to define roles on individual configurations as well as individual keys. Meaning you can define which roles and thus users/groups can access and administer certain signing configurations, as well as which users/groups can sign using a particular key. This is more fine-grained than using the scopes above. Of course both could be used together if desired. The use of roles is explained in the Micro Service documentation. How roles should be made available to the JWT/bearer tokens is outside the scope of this README.
Key Provider caching
Especially for remote Key Providers like the REST, Azure and PKCS#11 Key Providers it might make sense to enable Key/Certificate
caching. This means that a key which has been retrieved recently and which has not hit the configured Time to Live yet, will be returned from the
local cache, improving performance. Please be aware that this library is not involved in updating or replacing keys as these are highly implementation
specific. As such providing a really high TTL could return a stale Key/Certificate if the Key had been replaced for a certain kid value. Given
keys/certificates are not replaced that often in practice this shouldn’t be too much of a problem. Please note that the actual signing using a
key/certificate is rarely done using a cached key/certificate itself, given the private key is seldomly included. The createSignature
method
typically isn’t involved in the caching mechanism.
List keys, certificates
To list all available keys of the provider one can use the getKeys() method. A list of IKeyEntry objects is being returned. The interface does not expose private keys, as developers typically should not access the private key directly and not every supported implementation gives access to private keys. If you are sure that key contains private keys, you can cas the result to IPrivateKeyEntry.
Get a key/certificate by kid
Use the geKey(kid: String) method to get a single key IKeyEntry object by kid if it exists. If it does not exist null is being returned. The IKeyEntry interface does not expose private keys, as developers typically should not access the private key directly and not every supported implementation gives access to private keys. If you are sure that the key entry contains private keys, you can cast the result to IPrivateKeyEntry. Make sure to never sent private keys across unprotected network connections!
Create the signature
Depending on the Key Provider this method could be traversing the network as it might call a signature REST API, or use a network/cloud based Hardware Security Module containing the private key to sign. As such we advise to create the digest hash using a SignatureService beforehand so original documents/data is not being sent. Only the hash digest will traverse the network.