Java libraries for PKI credentials support, including PKCS#11 and HSM:s.
1.1. API Documentation
1.2. Maven
2.1. BasicCredential
2.2. KeyStoreCredential
2.3. Pkcs11Credential
3.1. Credential Name
3.2. Transformation to other Formats
3.4. Credential Metadata
4.1. KeyStore Builder and Factories
4.2. Credential Factories
Credential Bundles and Configuration Support
5.1. The Bundles Concept
5.2.1. StoreConfigurationProperties
5.2.2. BaseCredentialConfigurationProperties
5.2.3. PemCredentialConfigurationProperties
5.2.4. StoreCredentialConfigurationProperties
Credential Containers for Managing Keys
7.1. Creating a Credential Container
7.1.1. HSM-based Credential Containers
7.1.2. In-memory KeyStore-based Credential Container
8.1. Spring Factories
8.2. Spring Converters
11.1. Using SoftHSM to Test PKCS#11 Credentials
11.2. Key Generation Scripts
The credentials-support library defines an uniform way of representing PKI credentials (private keys and X.509 certificates) by introducing the PkiCredential interface.
The library supports both basic credentials stored on file, or in a key store (JKS, PKCS#12), as well as PKCS#11 credentials residing on a Hardware Security Module.
The credentials-support-nimbus library offers support for working with Nimbus datatypes such as the JWK class in conjunction with PkiCredential objects.
The credentials-support-opensaml library offers an add-on for OpenSAML, where a PkiCredential object can be used to create an OpenSAML credential.
The credentials-support-spring library offers Spring add-ons consisting of converters, factories and configuration support.
The credentials-support-spring-boot-starter library is a Spring Boot starter that can be used for an easy and straight forward way of configuring credentials that are to be used in a Spring Boot application.
:exclamation: If you are still using the 1.X.X version of the credentials-support library, see the old README.
All libraries for the credentials-support project is published to Maven central.
Include the following snippets in your Maven POM to add dependencies for your project.
The credentials-support base library:
<dependency>
<groupId>se.swedenconnect.security</groupId>
<artifactId>credentials-support</artifactId>
<version>${credentials-support.version}</version>
</dependency>
The credentials-support-opensaml library:
<dependency>
<groupId>se.swedenconnect.security</groupId>
<artifactId>credentials-support-opensaml</artifactId>
<version>${credentials-support.version}</version>
</dependency>
Will include the opensaml-library.
The credentials-support-nimbus library:
<dependency>
<groupId>se.swedenconnect.security</groupId>
<artifactId>credentials-support-nimbus</artifactId>
<version>${credentials-support.version}</version>
</dependency>
Will include the opensaml-library.
The credentials-support-spring library:
<dependency>
<groupId>se.swedenconnect.security</groupId>
<artifactId>credentials-support-spring</artifactId>
<version>${credentials-support.version}</version>
</dependency>
Will include the opensaml-library.
The credentials-support-spring-boot-starter library:
<dependency>
<groupId>se.swedenconnect.security</groupId>
<artifactId>credentials-support-spring-boot-starter</artifactId>
<version>${credentials-support.version}</version>
</dependency>
Will include opensaml-library and credentials-support-spring.
The credentials-support library defines three classes implementing the PkiCredential interface and a wrapper that takes a PkiCredential into an OpenSAML credential type.
The BasicCredential class is a simple implementation of the PkiCredential interface that is created by providing the private key and certificate (or just a public key). This class can for example be used when you have the key and certificate stored on file or in memory.
The KeyStoreCredential class is backed by a Java KeyStore and is initialized by providing a loaded KeyStore instance (see KeyStore Builder and Factory below) and giving the entry alias and key password.
This class also supports handling of PKCS#11 credentials. This requires using a security provider that supports creating a KeyStore based on an underlying PKCS#11 implementation (for example the SunPKCS11 provider).
:exclamation: For a PKCS#11 key store, the alias
parameter is equal to the PKCS#11 CKA_LABEL
attribute for the object holding the private key (and certificate), and the password
parameter is the PIN needed to unlock the object.
Note: If you are using a security provider for PKCS#11 support that does not support exposing the HSM device as a Java KeyStore, you need to use the Pkcs11Credential (see below).
As was described above, the KeyStoreCredential can be used for PKCS#11 credentials, but it is limited to those Java security providers that also offers a KeyStore abstraction of the PKCS#11 device entry. The Pkcs11Credential is a class that does not make any assumptions on how the security provider in use handles its PKCS#11 entries. Instead it uses the Pkcs11Configuration, Pkcs11PrivateKeyAccessor and Pkcs11CertificatesAccessor interfaces.
The Pkcs11Configuration interface declares the method getProvider()
that returns the Java Security Provider that should be used for the PKCS#11 credential, and the accessors provide access to the private key and certificates respectively.
So, for those that wishes to use the credentials-support library with a custom security provider there is an implementation task ahead…
The credentials-support library also offers implementation of the above interfaces for providers that uses key stores for PKCS#11 (SunPKCS11 provider). However, if you are using the SunPKCS11 provider stick with the KeyStoreCredential.
The main use of a PkiCredential is to provide an abstraction and unified way of holding a private key and a certificate (or just a public key) for use in signing and decryption.
This section highlights some interesting features apart from getter-methods for keys and certificates.
In an application where multiple credentials are used, we may want to have a way to name each credential (for logging and other purposes). Therefore, the getName()
method exists, and the AbstractPkiCredential offers a way of assigning a custom name to a credential.
If no name is explicitly assigned, a name will be generated according to the following:
For a BasicCredential the serial numver of the entity certificate will be used. If no certificate exists, the name will be chosen as <public-key-type>-<uuid>, for example, RSA-0c6fbdce-b485-44a4-9000-93943626c675
.
If the key store is a PKCS#11 key store, the name is <provider name>-<alias>-<certificate serial number>
, for example SunPKCS11-foo-rsa1-89716151
. Note that the provider name most usually is “base provider name”-“slot name”.
For other key store types, the name is <key type>-<alias>-<certificate serial number>
, for example RSA-mykey-89716151
.
<provider-name>-<alias>
.:raised_hand: It is recommended that a custom name is assigned to each credential to get a good understanding of which credential is which when looking at the logs. Make sure to use unique names.
The credentials-support libraries offer a uniform way of representing credentials via the PkiCredential interface and also a smooth and efficient way of configuring those (see section 5 below), but other frameworks and libraries have their way of representing credentials. So, we need a way to handle this. The solution is the tranform
method:
/**
* Transforms the credential to another format, for example an JWK or a Java KeyPair.
*
* @param transformFunction the transform function
* @param <T> the type of the new format
* @return the new format
*/
default <T> T transform(@Nonnull final Function<PkiCredential, T> transformFunction) {
return transformFunction.apply(this);
}
Thus, by implementing a Function
that accepts a PkiCredential and returns the custom credential representation we can use the credentials-support library together with other frameworks.
See section 10, Nimbus Support, for how to transform a PkiCredential into a JWK and section 11, OpenSAML Support, for how to transform a PkiCredential into an OpenSAML X509Credential.
When using a HSM there is a possibility that the connection with the device is lost. The result is that the instantiated credential stops working. Therefore the credentials-support library offers ways to test and reload credentials. The credential types that support testing and reloading implements the ReloadablePkiCredential interface.
An application that makes use of credentials that may fail, and may need to be reloaded, needs to set up a monitor that periodically tests that all monitored credentials are functional, and if not, tries to reload them. See section 6, Monitoring, below.
For credentials implementing the ReloadablePkiCredential, the DefaultCredentialTestFunction will be installed by default.
Additional metadata may be associated with a credential. This is mainly useful when transforming to other formats, see section 3.2 above. The PkiCredential.Metadata interface is basically a map where metadata is stored.
The AbstractPkiCredential class will pre-populate the issued-at
and expires-at
based on the validity of a credential’s entity certificate.
The libraries offer a number of builder and factory classes for building KeyStore and PkiCredential objects.
Setting up a Java KeyStore involves loading a file from disc and unlocking it.
The KeyStoreBuilder class offers doing this using a standard builder pattern.
To load a Java KeyStore from file and to unlock it may then be done like:
final KeyStore keyStore = KeyStoreBuilder.builder()
.location("classpath:store.jks")
.password("secret")
.build();
Note: The default resource loader will support strings with prefixes defined by Spring and SmallRye (Qurkus style).
Example of how a PKCS#12 file is loaded.
final KeyStore keyStore = KeyStoreBuilder.builder()
.location("/opt/keys/mykeys.p12")
.password("secret")
.type("PKCS12")
.build();
It is also possible to use the builder to load a PKCS#11 KeyStore:
final KeyStore keyStore = KeyStoreBuilder.builder(customResourceLoader)
.type("PKCS11")
.provider("SunPKCS11")
.pin("secret")
.pkcs11ConfigurationFile("/opt/config/p11.conf")
.build();
The example above illustrates how another resource loader is used. For Spring users, the SpringConfigurationResourceLoader should be used.
Apart from the nice builder the class KeyStoreFactory offers methods for loading a KeyStore. This class is mainly used internally when a StoreConfiguration object should be turned into a KeyStore. See section 5.2 below.
See also section 8.1, Spring Factories.
Creating a PkiCredential instance is easiest done using the different constructors for BasicCredential or KeyStoreCredential, but the credentials-support also offers the PkiCredentialFactory. This class is mainly intended to be used internally when loading configuration (see section 5.2) below.
See also section 8.1, Spring Factories.
Spring Boot has introduced a feature called SSL Bundles where SSL/TLS credentials are configured in a separate place, and later referenced in different location where they are needed.
spring:
ssl:
bundle:
jks:
mybundle:
key:
alias: "application"
keystore:
location: "classpath:application.p12"
password: "secret"
type: "PKCS12"
myapp:
example:
bundle: mybundle
The credentials-support library borrows/steals this concept and introduces “Credential Bundles”, where KeyStore and PkiCredential instances are configured under a bundle, and then referenced wherever they are needed.
Example:
credential:
bundles:
keystore:
ks1:
location: classpath:ks-1.jks
password: secret
type: JKS
jks:
cred1:
store-reference: ks1
name: "Credential One"
key:
alias: rsa1
key-password: secret
cred2:
store-reference: ks1
name: "Credential Two"
key:
alias: rsa2
key-password: secret
pem:
cred3:
certificates: file:/opt/creds/cred3.pem.crt
private-key: file:/opt/creds/cred3.pkcs8.key
name: "Credential Three"
myapp:
example:
credential: cred2
The package se.swedenconnect.security.credential.bundle contains support for implementing “Credential Bundles”. It contains the following interfaces and classes:
CredentialBundles - An interface for accessing registered credentials and keystores.
CredentialBundleRegistry - An interface for registering KeyStore and PkiCredential instances in the credential bundle.
CredentialBundleRegistrar - A functional interface for registering stores and credentials at a CredentialBundleRegistry.
DefaultCredentialBundleRegistry - Default implementation of the CredentialBundles and CredentialBundleRegistry interfaces.
ConfigurationCredentialBundleRegistrar - An implementation of the CredentialBundleRegistrar interface that sets up a CredentialBundles based on the a supplied CredentialBundlesConfiguration (see section 5.2 below).
The below example shows how a CredentialBundles is constructed.
final CredentialBundlesConfiguration config = ...;
final DefaultCredentialBundleRegistry bundle = new DefaultCredentialBundleRegistry();
final ConfigurationCredentialBundleRegistrar registrar =
new ConfigurationCredentialBundleRegistrar(config);
registrar.register(bundle);
// bundle is now populated with all stores and credentials available from the configuration object.
:raised_hand: When using the Spring Boot Starter, a fully populated CredentialBundles bean will be injected automatically based on the credentials configuration. See section 8.3, The Spring Boot Starter for Credentials Support.
Once a CredentialBundles object has been set up, it can be queried for registered keystores and credentials.
final CredentialBundles bundles = ...;
final PkiCredential credential1 = bundles.getCredential("cred1");
The package se.swedenconnect.security.credential.config contains interfaces for configuring KeyStore and PkiCredential instances.
Each interface also has a corresponding implementation class under the se.swedenconnect.security.credential.config.properties package.
The reason that interfaces are used is that we want to make it possible to use the SmallRye Configuration Library to configure keystores and credentials. For Spring use, the corresponding concrete classes are used.
The following configuration interfaces and classes are available:
Interface | Class | Description |
---|---|---|
StoreConfiguration | StoreConfigurationProperties | Configuration for creating a KeyStore. This includes configuration support for configuring a PKCS#11 KeyStore. See 5.2.1. |
PemCredentialConfiguration | PemCredentialConfigurationProperties | Configuration for creating a PkiCredential using PEM-encoded certificate(s)/public keys and private keys. Both references to resources and inline PEM-encodings are supported. See 5.2.3. |
StoreCredentialConfiguration | StoreCredentialConfigurationProperties | Configuration for creating a PkiCredential backed by a KeyStore. See 5.2.4. |
PkiCredentialConfiguration | PkiCredentialConfigurationProperties | Configuration support for configuring a PkiCredential outside of the bundles concept. One, and exactly one, of bundle , jks or pem must be supplied.See 5.2.5. |
CredentialBundlesConfiguration | CredentialBundlesConfigurationProperties | Configuration for bundles of credentials and keystores. If both PEM and JKS (keystore) credentials are configured, the ID:s assigned must be unique for all credentials, i.e., the same ID can not be used for PEM and JKS. See 5.2.6. |
Configuration for creating a KeyStore.
Property | Description | Type |
---|---|---|
location |
Location of the keystore. Spring and SmallRye prefixes such as “classpath:” and “file:” are supported. For PKCS#11 keystores, this property should not be assigned. | String |
password |
The password for unlocking the keystore. | String |
type |
The type of keystore, e.g. “JKS”, “PKCS12 or “PKCS11”. | String |
provider |
The name of the Security provider to use when setting up the keystore. If not assigned, a system default will be used. | String |
pkcs11.* |
If the type is “PKCS11” and a provider that is not statically configured for PKCS#11, additional PKCS#11 configuration needs to be supplied. Note that the security provider used must support PKCS#11 via the KeyStoreSpi interface. The “SunPKCS11” is such a provider. |
See Pkcs11ConfigurationProperties below |
Additional configuration of PKCS11 key stores.
Property | Description | Type |
---|---|---|
configuration-file |
The complete path of the PKCS#11 configuration file with which the PKCS#11 device is configured. | String |
settings.* |
As an alternative to providing the PKCS#11 configuration file, each PKCS#11 setting can be provided separately. This property holds these detailed settings. | See Pkcs11SettingsProperties below |
Pkcs11SettingsProperties:
Property | Description | Type |
---|---|---|
library |
The PKCS#11 library path. | String |
name |
The name of the PKCS#11 slot. | String |
slot |
The slot number/id to use. | String |
slot-list-index |
The slot index to use. | Integer |
the AbstractBaseCredentialConfigurationProperties class is a base class that is used by both PemCredentialConfigurationProperties and StoreCredentialConfigurationProperties. It defines properties that are common for all type of credentials.
Property | Description | Type |
---|---|---|
name |
The name of the credential. | String |
key-id |
Key identifier metadata property. | String |
issued-at |
Issued-at metadata property. | Instant |
expires-at |
Expires-at metadata property. | Instant |
metadata |
Additional metadata in the form of key-value:s | Map where both keys and values are Strings |
Configuration for creating a PkiCredential using PEM-encoded certificate(s)/public keys and private keys. Both references to resources and inline PEM-encodings are supported.
In addition to the BaseCredentialConfigurationProperties the following properties are used to configure a PEM-based credential:
Property | Description | Type |
---|---|---|
public-key |
Location or content of the public key in PEM format. This setting is mutually exclusive with the certificates setting. |
String |
certificates |
Location or content of the certificate or certificate chain in PEM format. If more than one certificate is supplied, the entity certificate, i.e., the certificate holding the public key of the key pair, must be placed first. This setting is mutually exclusive with the public-key setting. |
String |
private-key |
Location or content of the private key in PEM format. | String |
key-password |
Password used to decrypt the private key (if this is given in encrypted format). | String |
Examples illustrating how a PEM-based credential can be configured.
credential:
bundles:
...
pem:
cred1:
certificates: file:/opt/keys/test1.pem.crt
private-key: file:/opt/keys/test1.pkcs8.key
name: "Example credential #1"
credential:
bundles:
...
pem:
cred2:
certificates: |
-----BEGIN CERTIFICATE-----
MIIDFDCCAfygAwIBAgIEZyt6yTANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJT
RTEXMBUGA1UECgwOU3dlZGVuIENvbm5lY3QxFDASBgNVBAsMC0RldmVsb3BtZW50
...
wVz5c0ouR+c54aoJn1oVg6PCga41gvEtc03Fl0W0vmxs0QZHg15g7Mugd4jQzi/9
6mrCVbGyFIYkGi4vgVA+aMVYyyaSXKyN
-----END CERTIFICATE-----
private-key: |
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCX9V5RUFhAId1X
JVBPYN0lWkV4sWrZuPzxRTYDdA5LNsLPXmu/lthjLk1RLYqxJidsywJWTzkNS3FU
...
5MGCkA4SKlmCZFqyKq6W7Dxk+dz55VNoZNAKpYaPIex885cl1A6/7OxMt4V3Fp/Z
gwfASW4la2qIv1z4fIuR4Tnz3uE7UXdfHJSBVr0D0fFf7JrOQV0lMx5wr3X4jcKQ
6gE2jgKrhq3F/BbqbDEk7mTfHw==
-----END PRIVATE KEY-----
name: "Example credential #2"
Configuration for creating a PkiCredential backed by a KeyStore.
In addition to the BaseCredentialConfigurationProperties the following properties are used to configure a JKS-based credential:
Property | Description | Type |
---|---|---|
store |
Configuration for the KeyStore holding the key pair entry. Mutually exclusive with the store-reference property. |
StoreConfigurationProperties |
store-reference |
A store reference. As an alternative to giving the key store configuration, a reference to a key store configuration may be given. This feature may be used when one key store holds several keys. Makes use of the Bundles Concept. | String |
monitor |
Setting telling whether the credential should be configured for monitoring. The default is true if the store used is a PKCS#11 store, and false otherwise. |
Boolean |
key.alias |
The alias that identifies the key pair in the key store. If the store is a PKCS#11 store, this setting corresponds to the PKCS#11 CKA_LABEL attribute for the object holding the private key on the device. |
String |
key.key-password |
The password to unlock the key entry identified by the given alias. If not given, the store password will be used (in these cases, using a store reference will not function). | String |
key.certificates |
For some credentials where an underlying KeyStore is being used, an external certificate should be used. The most typical example would be a PKCS#11 key store where the certificate of the key pair resides outside the HSM device. This setting holds the location or content of the certificate or certificate chain in PEM format. | String |
Example:
credential:
bundles:
keystore:
ks1:
...
jks:
cred1:
name: "Example credential #1"
store-reference: ks1
key:
alias: test1
key-password: secret
monitor: true
key-id: 123456
issued-at: "2024-11-15T14:08:26Z"
metadata:
algorithm: RSA
keyuse: sign
cred2:
name: "Example credential #2"
store:
location: file:/opt/keys/example.p12
password: secret
type: PKCS12
key:
alias: mykey
The above example illustrates how two JKS-credentials are configured. The first one refers to an already configured keystore and the other configures the store inline. Also note how metadata is configured for the first credential.
The PkiCredentialConfigurationProperties is not used when setting up a credential using the Bundles Concept. It is aimed to be used as the primary configuration object when a PkiCredential is to be configured directly in an application.
Property | Description | Type |
---|---|---|
bundle |
Reference to a PkiCredential accessible via the CredentialBundles bean. | String |
jks |
Configuration for a JKS (Java KeyStore) based credential. | StoreCredentialConfigurationProperties |
pem |
Configuration for a PEM-based credential. | PemCredentialConfigurationProperties |
:exclamation: One, and exactly one, of bundle
, jks
or pem
must be supplied.
Study the TestConfigurationProperties and TestConfiguration in the application example for how a PkiCredentialConfigurationProperties class can be used in an application’s configuration to inject a credential (from a bundle or directly configured).
The CredentialBundlesConfigurationProperties class is the main configuration class for setting up a CredentialBundles bean (see 5.1 above).
Property | Description | Type |
---|---|---|
keystore |
Map of key store ID:s and key store configurations. | Map where keys are Strings (ID:s) and the values are StoreConfigurationProperties. |
pem |
Map of credential ID:s and PEM based credential configurations. | Map where keys are Strings (ID:s) and the values are PemCredentialConfigurationProperties. |
jks |
Map of credential ID:s and key store based credential configurations. | Map where keys are Strings (ID:s) and the values are StoreCredentialConfigurationProperties. |
monitoring.enabled |
Spring Boot only. Whether credential monitoring is enabled. If enabled, a CredentialMonitorBean is set up to monitor all credentials (that are configured for monitoring). |
Boolean |
monitoring.test-interval |
Spring Boot only. The interval between tests of credentials. The default is 10 minutes. |
Duration |
monitoring.health-endpoint-enabled |
Spring Boot only. Whether a HealthEndpoint for monitoring should be set up. See section 8.3.1, Credential Monitoring Health Endpoint. |
Boolean |
:exclamation: If both PEM and JKS (keystore) credentials are configured, the ID:s assigned must be unique for all credentials, i.e., the same ID can not be used for PEM and JKS.
Example:
credential:
bundles:
keystore:
ks1:
location: file:/opt/keys/test-1.jks
password: secret
type: JKS
p11:
password: secret
type: PKCS11
provider: SunPKCS11
pkcs11:
configuration-file: /opt/config/p11.conf
jks:
test1:
store-reference: ks1
name: "Test1"
key:
alias: test1
key-password: secret
monitor: true
key-id: 123456
issued-at: "2024-11-15T14:08:26Z"
metadata:
algorithm: RSA
keyuse: sign
test2:
store:
location: classpath:test-2.p12
password: secret
type: PKCS12
name: "Test2"
key:
alias: test2
testP11:
store-reference: p11
name: "TestPkcs11"
key:
key-password: secret
alias: test1
monitor: true
pem:
test3:
certificates: classpath:test3.pem.crt
private-key: classpath:test3.pkcs8.key
name: "Test3"
test3b:
public-key: classpath:test3.pubkey.pem
private-key: classpath:test3.pkcs8.key
name: "Test3b"
test4:
certificates: classpath:test4.pem.crt
private-key: classpath:test4.pkcs8.enc.key
key-password: secret
name: "Test4"
test5:
certificates: |
-----BEGIN CERTIFICATE-----
MIIDFDCCAfygAwIBAgIEZyt6yTANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJT
RTEXMBUGA1UECgwOU3dlZGVuIENvbm5lY3QxFDASBgNVBAsMC0RldmVsb3BtZW50
...
wVz5c0ouR+c54aoJn1oVg6PCga41gvEtc03Fl0W0vmxs0QZHg15g7Mugd4jQzi/9
6mrCVbGyFIYkGi4vgVA+aMVYyyaSXKyN
-----END CERTIFICATE-----
private-key: |
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCX9V5RUFhAId1X
JVBPYN0lWkV4sWrZuPzxRTYDdA5LNsLPXmu/lthjLk1RLYqxJidsywJWTzkNS3FU
...
6gE2jgKrhq3F/BbqbDEk7mTfHw==
-----END PRIVATE KEY-----
name: "Test5"
monitoring:
enabled: true
test-interval: 10m
health-endpoint-enabled: true
When using a HSM there is a possibility that the connection with the device is lost. The result is that the instantiated credential stops working. Therefore the credentials-support library offers ways to test and reload credentials. The credential types that support testing and reloading implements the ReloadablePkiCredential interface.
An application that makes use of credentials that may fail, and may need to be reloaded, needs to set up a monitor that periodically tests that all monitored credentials are functional, and if not, tries to reload them.
By implementing the CredentialMonitorBean interface and schedule it to run periodically, one or more credentials can be monitored.
The DefaultCredentialMonitorBean is the default implementation of this interface. It can be configured with a number of callbacks that can be used for raising alarms or produce audit logs.
The The Spring Boot Starter for Credentials Support creates a monitor bean automatically based on the credential configuration.
This library provides support for setting up a credential container for generating, storing and managing public and private key pairs.
The primary use case for the credential container is when key pairs for user accounts are generated and maintained by an application and these keys are generated and stored in a HSM slot. A typical such usage is when a signing service needs to generate a signing key for a document signer (user), and where this key is used to sign a document and then permanently deleted/destroyed without ever leaving the HSM.
Such procedure is necessary for the highest level of confidence that the signing key is kept under so called “sole-control” in accordance with the eIDAS regulation, which ensures that the key can never be copied or used by any other process or person to sign any other document under another identity.
Even though the HSM option is the primary use case, the credential container also supports software based or in-memory key storage.
A credential container is created according to the following examples:
A credential container backed up by a HSM via the PKCS#11 interface is implemented by the HsmPkiCredentialContainer class.
final PkiCredentialContainer credentialContainer = new HsmPkiCredentialContainer(provider, hsmSlotPin);
The provider
parameter is the security provider that implements the HSM slot‚ and the hsmSlotPin
is the PIN code for accessing the HSM slot.
Instead of supplying a provider for the HSM slot as input, you may instead provide a Pkcs11Configuration
object:
final Pkcs11Configuration pkcs11Configuration = ...
final PkiCredentialContainer credentialContainer =
new HsmPkiCredentialContainer(pkcs11Configuration, hsmSlotPin);
In most cases, the connection to the HSM-device is configured using a PKCS#11 configuration file, and
a HsmPkiCredentialContainer
may be initialized by giving the full path to such a file.
final String p11ConfigFile = "/opt/config/p11/hsm.cfg";
final PkiCredentialContainer credentialContainer =
new HsmPkiCredentialContainer(p11ConfigFile, hsmSlotPin);
The above example uses a Java KeyStore to maintain the keys/credentials in the HSM, but it is also possible to use a container that uses a KeyStore that resides in memory. The SoftPkiCredentialContainer class is mainly intended to mimic the behaviour of HsmPkiCredentialContainer
and may be used in tests and simulations. See 7.1.3 below for an in-memory credential container that does not go the detour via KeyStore-usage.
An in-memory KeyStore-based credential container is created as follows:
final PkiCredentialContainer credentialContainer = new SoftPkiCredentialContainer(provider);
The provider
parameter is either a Java Security Provider, or the name of the security provider. This provider is used to create the key store used to store keys as well as the provider used to generate keys.
In order to use an in-memory based credential container create an instance of InMemoryPkiCredentialContainer as follows:
final InMemoryPkiCredentialContainer credentialsContainer = new InMemoryPkiCredentialContainer(provider);
The provider
parameter is either a Java Security Provider, or the name of the security provider. This provider is used to create the key store used to store keys as well as the provider used to generate
keys.
Keys are generated in the credential container by calling the method generateCredential(keyType)
,
where keyType
is a string representing an algorithm and key type, see KeyGenType.
Example: Generating a Nist P-256 EC key pair:
final String alias = credentialContainer.generateCredential(KeyGenType.EC_P256);
The returned alias is the handle used to obtain a PkiCredential object for the newly generated key pair.
final PkiCredential credential = credentialContainer.getCredential(alias);
Destroying credentials after use
The PkiCredential objects returned from the credential container have extended capabilities to ensure that the private key is destroyed when calling the destroy()
method of the PkiCredential
object.
In order to ensure that private keys are properly removed after usage, implementations should:
cleanup()
method to ensure that old keys are properly deleted.**destroy()
method immediately after its last intended use.[*]: The validity time of a key pair (credential) is 15 minutes by default. It can be changed using the
setKeyValidity
method on the container.
[**]: It is also wise to schedule a task that periodically invokes the
cleanup()
method of the container in use. By doing so we ensure that generated keys are not left too long in the container (expired credentials will be purged).
By including the credentials-support-spring artifact, the Credential Support is extended with Spring features.
The credentials-support-spring, offers the se.swedenconnect.security.credential.spring.factory.PkiCredentialFactoryBean. This is a Spring-style factory that accepts different credential configuration objects (see 5.2).
The se.swedenconnect.security.credential.factory.PkiCredentialFactoryBean previously used in earlier versions of the credentials-support library has been deprecated and will be removed in future versions.
The library also offers the following factory beans:
KeyStoreFactoryBean - for creating KeyStore instances using the Spring factory bean concept. However, it is recommended to use the [Bundles Concept(#the-bundles-concept) when creating key stores.
X509CertificateFactoryBean - for creating X509Certificate instances given a Resource.
A Spring Converter is an interface for type conversion. This feature is typically useful when using an application properties or YAML-file and we want to convert from Strings in the property file to certain types.
The following converters are available:
PropertyToPrivateKeyConverter - A Converter that gets a property value (e.g., classpath:signing.key
) and instantiates a PrivateKey
object.
Note: The converter only handles non-encrypted private keys in DER, PEM, and PKCS#8 formats.
PropertyToPublicKeyConverter - A Converter that gets a property value (e.g., classpath:trust.key
) and instantiates a PublicKey
object.
PropertyToX509CertificateConverter - A Converter that gets a property value (e.g., classpath:cert.crt
) and instantiates an X509Certificate
object. The converter also handles “inlined” PEM certificates.
PkiCredentialReferenceConverter - A Converter that accepts a string that is a reference to a registered PkiCredential and uses the system CredentialBundles bean to create a resolvable PkiCredentialReference.
KeyStoreReferenceConverter - A Converter that accepts a string that is a reference to a registered KeyStore and uses the system CredentialBundles bean to create a resolvable KeyStoreReference.
If the Spring Boot starter is used, these converters will be automatically installed. Otherwise, they have to be “manually” configured, see https://docs.spring.io/spring-framework/reference/core/validation/convert.html.
The credentials-support-spring-boot-starter gives a number of useful features:
Injection of a fully populated CredentialBundles bean. This bean is populated based on the configuration described in section 5, Credential Bundles and Configuration Support.
Automatic registration of the converters documented in section 8.2, Spring Converters.
The creation and injection of a scheduled CredentialMonitorBean bean.
As part of the monitoring of credentials a number of application events are published. These events may be used for alarms or audit logging. The events are:
SuccessfulCredentialTestEvent - An event that is signalled when a credential has been tested and the test was successful.
FailedCredentialTestEvent - An event that is signalled when a credential has been tested and the test failed.
SuccessfulCredentialReloadEvent - An event that is signalled when a credential has been reloaded successfully.
FailedCredentialReloadEvent - An event that is signalled when a credential has been reloaded with an error. This means that the credential no longer is functional.
If configured (credential.bundle.monitoring.health-endpoint-enabled
is set), an actuator health endpoint for credential monitoring is configured and made active. See below.
If the property credential.bundle.monitoring.health-endpoint-enabled
is set, the actuator health endpoint CredentialMonitorHealthIndicator is created and registered under the name credential-monitor
.
If everything is looking good (no failed tests of reloads), an output like the following will be returned:
{
"status" : "UP",
"details" : {
"credentials" : [
{
"credential-name" : "Signing",
"test-result" : "success"
},
{
"credential-name" : "Encryption",
"test-result" : "success"
}
]
}
}
The credential-name
holds the configured name for the credential (see section 3.1).
An error may look like:
{
"status" : "DOWN",
"details" : {
"credentials" : [
{
"credential-name" : "Signing",
"test-result" : "success"
},
{
"credential-name" : "Encryption",
"test-result" : "failure",
"test-error" : "Failed to access the private key",
"test-exception" : "java.lang.SecurityException",
"reload-result" : "failure",
"reload-error" : "No contact with PKCS#11 device",
"reload-exception" : "java.security.KeyStoreException"
}
]
}
}
In the above example it seems like both testing and reloading of the credential named “Encryption” has failed.
The health endpoint delivers a details-map, where the credentials
key holds a list of objects (one for each monitored credential). These objects have the following fields:
Field | Description |
---|---|
credential-name |
The name of the credential that was tested (and possible reloaded). |
test-result |
The result of a test. May be success or failure . |
test-error |
If the test-result is failure , this field holds a string describing the test error. |
test-exception |
If the test-result is failure , this field holds the class name for the exception that occurred during testing. |
reload-result |
If a test failed, the credential is reloaded. This field holds the result of the reloading. May be success or failure . |
reload-error |
If the reload-result is failure , this field holds a string describing the reload error. |
reload-exception |
If the reload-result is failure , this field holds the class name for the exception that occurred during reloading. |
The library credentials-support-opensaml contains the OpenSamlCredential class which is a class that wraps a PkiCredential as an OpenSAML X509Credential. This enables us to use the configuration support of the credentials-support library and use our credentials in an OpenSAML context.
The credentials-support-opensaml library also defines the OpenSamlCredentialTransformerFunction, which can be supplied to the transform
method of an existing PkiCredential and create an OpenSamlCredential instance.
The credentials-support-nimbus library offers support for working with Nimbus datatypes such as the JWK class in conjunction with PkiCredential objects.
It introduces the JwkTransformerFunction for transforming a PkiCredential into a JWK instance.
Also check the JwkMetadataProperties for definitions of metadata keys useful for an JWK.
Note: This library will be extended with more useful features in future versions.
SoftHSM is a great way to test your PKCS#11 credentials without an actual HSM. The credentials-support library contains a simple Spring Boot app that illustrates how to set up SoftHSM and how to configure your PKCS#11 devices, see the softhsm directory for details.
Once you have an application that is setup to use credentials from an HSM, this library also includes a set of scripts that extends a docker image with SoftHSM support. These scripts and their usage is described in hsm-support-scripts/soft-hsm-deployment/README.md.
In order to support generation and installing of keys and key certificates in any HSM device as part of setting up a production environment, this repository also provides some supporting key generation scripts:
For further information consult the information at hsm-support-scripts/key-generation/README.md
Copyright © 2020-2024, Sweden Connect. Licensed under version 2.0 of the Apache License.