Java library for PKI credentials support, including PKCS#11 and HSM:s.
-
1.1. Maven
-
2.1. BasicCredential
2.2. KeyStoreCredential
2.3. Pkcs11Credential
2.4. OpenSamlCredential
-
3.1. Credentials as beans
3.2. Converters
3.3. Factories
3.3.1. For Shibboleth users
3.3.2. Generic PkiCredentialFactoryBean for SpringBoot users
-
Credential containers for managing keys
5.1. Creating a credential container
5.1.1. HSM-based credential container
5.1.2. In-memory KeyStore-based credential container
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 project is published to Maven central.
Include the following snippet in your Maven POM to add credentials-support as a dependency for your project.
<dependency>
<groupId>se.swedenconnect.security</groupId>
<artifactId>credentials-support</artifactId>
<version>${credentials-support.version}</version>
</dependency>
The 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. This class can for example be used when you have the key and certificate stored on file.
The KeyStoreCredential class is backed by a KeyStore and can be initialized in a number of ways:
-
By loading a KeyStore from a Spring Resource and then getting the certificate and private key by providing the keystore alias and password.
-
By providing an already loaded KeyStore instance (see Factories 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). There are three ways of creating a KeyStoreCredential for use with PKCS#11:
-
Supplying an already existing PKCS#11 KeyStore - In some cases you may already have loaded a KeyStore using a security provider configured for PKCS#11. In these cases the initialization of the KeyStoreCredential is identical with option number 2 above. You simply create your KeyStoreCredential instance by giving the KeyStore instance, the entry alias and key password.
-
Supplying the provider name of a Security provider configured for your PKCS#11 device - Another possibility is to supply the provider name of a security provider configured for PKCS#11. This could typically look something like:
// Create a SunPKCS11 provider instance using our PKCS#11 configuration ...
Provider provider = Security.getProvider("SunPKCS11");
provider = provider.configure(pkcs11CfgFile);
Security.addProvider(provider);
// Create a credential ...
KeyStoreCredential credential = new KeyStoreCredential(
null, "PKCS11", provider.getName(), tokenPw, alias, null);
credential.init();
- Supplying the PKCS#11 configuration file - In the above example we created the SunPKCS11 provider instance manually. It is also to create a KeyStoreCredential instance by supplying the PKCS#11 configuration file.
KeyStoreCredential credential = new KeyStoreCredential(
null, "PKCS11", "SunPKCS11", tokenPw, alias, null);
credential.setPkcs11Configuration(pkcs11CfgFile);
credential.init();
Note: As an alternative of using KeyStoreCredential for PKCS#11 credentials see the Pkcs11Credential class 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 interface.
The Pkcs11Configuration interface declares the methods:
-
getProvider()
- Returns the Java Security Provider that should be used for the PKCS#11 credential. -
getPrivateKeyProvider()
- Returns a provider function that returns the private key of the credential. -
getCredentialProvider()
- Returns a provider function that returns the private key and certificate of the credential.
The default implementation of this interface is DefaultPkcs11Configuration. This implementation uses the SunPKCS11 security provider. This class can be used in two ways:
-
By providing a PKCS#11 configuration file - In these cases a call to
getProvider()
will use the SunPKCS11 provider and create a new provider named SunPKCS11-, where name is the name given in the PKCS#11 configuration file. -
By using a statically configured SunPKCS11 provider - The SunPKCS11 provider can also be configured in the
java.security
file (see below). In these cases the DefaultPkcs11Configuration should not be configured with any arguments.
Example of a statically configured SunPKCS11 provider:
...
security.provider.13=SunPKCS11 /opt/bar/cfg/pkcs11.cfg
...
For more information, see the Oracle PKCS#11 Reference Guide.
Note: If you are using another PKCS#11 security provider than SunPKCS11 you will have to provide your own implementation of DefaultPkcs11Configuration. In these cases the abstract base class AbstractPkcs11Configuration may be useful.
OK, so what about the Pkcs11Credential class? Well, once the configuration is in place it's really simple. You create an instance of the class be providing the alias (PKCS#11 label) and PIN (the password) along with the configuration discussed above.
OpenSAML offers an interface, X509Credential
, similar to the PkiCredential interface. In order to use any of the types described above together with OpenSAML the credentials-support library offers the OpenSamlCredential class. This class simply wraps a class implementing the PkiCredential interface so that it also implements the OpenSAML X509Credential
interface. In this way you can make use of the benefits of the credentials-support library such as PKCS#11 support and monitoring of credentials in an OpenSAML environment.
Note: OpenSAML 4 is an optional dependency to the credentials-support meaning that if you want to use the OpenSamlCredential you need to explicitly include the dependency org.opensaml:opensaml-security-api
.
The library uses Spring Framework, and especially the InitializingBean
and DisposableBean
interfaces.
If you are not using the library in a Spring environment you will make sure that you invoke the afterPropertiesSet()
method directly after a bean has been created and all its properties assigned.
The SpringBootTest along with its configuration class CredentialsConfiguration gives some examples of how credentials can be instantiated as Spring beans. It also illustrates how monitoring can be set up (see Monitoring and reloading credentials below.
If you are using old-fashioned Spring with XML-configuration files, take a look at SpringTest and its configuration file test-config.xml.
The credentials-support library defines two classes; PropertyToPrivateKeyConverter and PropertyToX509CertificateConverter. These are handy when you want a simple way from a property in an application properties file to a ready to go object (PrivateKey
or X509Certificate
).
Check out the tests in PropertyToPrivateKeyConverterTest and PropertyToX509CertificateConverterTest for how to register the converters and make use of them.
When using Spring making use of factory beans are often useful. The credentials-support library defines the KeyStoreFactoryBean for an easy way to create a KeyStore
object and the X509CertificateFactoryBean for creating X509Certificate
objects given a Spring Resource
.
The Shibboleth library net.shibboleth.ext:spring-extensions
defines a number of useful Spring factory bean classes in the net.shibboleth.ext.spring.factory
package. These can of course be
used instead of the classes defined in the credentials-support library, but let's go through
them and give some information that is useful to know about:
KeyStoreFactoryBean
Basically the same as se.swedenconnect.security.credential.factory.KeyStoreFactoryBean. The only difference is that the Shibboleth implementations doesn't let you create a PKCS#11 KeyStore instance.
This is probably an oversight from the Shib-team. The
resource
property is checked so that it is non-null, but in the case when loading a PKCS#11 KeyStore you don't need an input stream but supplynull
.
PKCS11PrivateKeyFactoryBean
A factory bean that creates a PrivateKey
instance that resides on a token that is accesses via PKCS#11.
This class can only be used if you are fine with using Sun's PKCS#11 security provider. If your device requires another security provider this class isn'f for you.
Also, by using the credentials support in credentials-support you also have the possibility to monitor, and possibly reload, PKCS#11 credentials. This is not possible if you are using the Shibboleth PKCS11PrivateKeyFactoryBean
.
X509CertificateFactoryBean
Basically identical to se.swedenconnect.security.credential.factory.X509CertificateFactoryBean.
So, the X509CertificateFactoryBean
of the credentials-support library is really indented for those that don't use Shibboleth.
SpringBoot configuration is usually done by configuration properties. Therefore, we have supply the PkiCredentialFactoryBean that can be used as a generic factory bean for creating a PkiCredential object.
The following properties are supported:
Property | Description |
---|---|
name |
The name of the credential. |
certificate |
A resource holding the certificate part of the credential. Used in the cases when a BasicCredential is to be used, or when setting up an PKCS#11 credential that does not store the certificate on the device. |
private-key |
A resource holding the private key part of the credential. Used in the cases when a BasicCredential is to be used. Note: If an encrypted key is used, the keyPassword must also be set. |
resource |
A resource to the keystore containing the credential. |
password |
The keystore password. |
type |
The type of keystore (defaults to JKS). |
provider |
The name of the Java Security Provider to be used when creating the keystore. See KeyStoreCredential. |
pkcs11-configuration |
If PKCS#11 is to be used, this property points at the PKCS#11 configuration file (a complete path). |
alias |
The keystore alias to the entry holding the key pair. |
keyPassword |
The password to unlock the private key from the keystore. If a keystore is used and this property is not set, the value for password is used instead. This field is also used when using an encrypted private key is used. |
pin |
The same as keyPassword (used mainly for PKCS#11 credentials). |
Based on which of the above properties that are assigned the factory will attempt to create the following classes (in order):
-
BasicCredential - If
certificate
andprivate-key
are set. -
Pkcs11Credential - If
pkcs11-configuration
,alias
,pin
(orkeyPassword
) are set. -
KeyStoreCredential - If
resource
,password
andalias
are set.
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.
See SpringBootTest and CredentialsConfiguration for an example of how to set up a scheduled monitor in Spring Boot.
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:
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:
Pkcs11Configuration pkcs11Configuration = new DefaultPkcs11Configuration(...);
...
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.
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 5.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:
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:
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:
- Create keys with as short validity time as possible.*
- On all restarts and on suitable occasions, call the
cleanup()
method to ensure that old keys are properly deleted.** - Always call the
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).
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 PkiCredentials from 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 library also provides some supporting key generation scripts:
- A PKCS11 key generation script (p11-keygen.sh) used to generate keys and install certificates in a HSM slot
- A corresponding soft key generation script that will create key stores (JKS and PKCS12) to support test environment setup.
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.