Securing cryptographic keys as a case study of the YubiHSM 2 FIPS Hardware Security Module

Securing cryptographic keys as a case study of the YubiHSM 2 FIPS Hardware Security Module

The YubiHSM 2 FIPS is a Cryptographic Hardware Security Module used primarily for generating, protecting and storing cryptographic keys. Since we at EuroLinux utilize HSMs (Hardware Security Modules), we decided to create an article being a practical example of using YubiHSM 2 FIPS in Linux systems.

The YubiHSM 2 FIPS is a Cryptographic Hardware Security Module intended for server usage. It is used primarily for generating, protecting and storing cryptographic keys, which secure critical applications, identities and confidential data. EuroLinux utilizes an HSM (Hardware Security Module) for signing documents, rpm packages of all our products and EuroLinux 8’s bootchain for Secure Boot purposes, among others.

The YubiHSM 2 FIPS empowers secure file signing – that is without exposing a private key. It supports both symmetric and asymmetric cryptography (Public-key cryptography). The physical separation of the Hardware Security Module is what prevents potential attackers from accessing memory and other identifiable resources, which could be abused to compromise company secrets. YubiHSM 2’s capabilities include keys generating, dumping, signing, decoding, hashing and wrapping. The device’s ultra-flat „nano” case fits seamlessly into a server’s internal USB port.

YubiHSM 2 FIPS

The YubiHSM 2 FIPS is operated through integrating with an open software development toolkit for a wide range of both open and closed source applications. The communication with the Module can be carried out through Yubico Key Storage Provider (KSP), the PKCS#11 standard or Microsoft CNG as well as via native system libraries of Windows, Linux and macOS.

YubiHSM 2 FIPS

The integrity and privacy of commands and data transmitted between the HSM and applications is protected with a mutually-authenticated, secured tunnel. Applications can establish multiple sessions simultaneously with YubiHSM 2 for performing cryptographic operations.

Creating backups and deploying cryptographic keys on multiple HSMs is a critical element of a security architecture of an enterprise and should not be performed under supervision of only one, single administrator. YubiHSM supports setting M of N rules on a Wrap Key, which is used for exporting keys for creating backups or transferring the Module’s data. Thanks to this feature, multiple administrators, who own parts of the Wrap Key, are needed to import and fully decrypt the key so it can be used on additional HSMs. For instance, an Active Directory root CA private key in an enterprise can be wrapped with a Wrap Key intended for 6 administrators (N=6) and at least 4 of them (M=4) must import their pieces of the Wrap Key to transfer data onto a new HSM.

Communication with HSM

We’ll generate an asymmetric RSA key directly in the Module and we’ll import a private RSA key, that exists on our disk, to the Module. Both keys will be used to sign files. So let’s start with creating such a pair of keys on our system – before the communication with the Module has begun:

[eurolinux@el ~]$ openssl genrsa -out private.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..................................+++++
.....................+++++
e is 65537 (0x010001)
[eurolinux@el ~]$ openssl rsa -in private.pem -outform PEM -pubout -out public.pem
writing RSA key
[eurolinux@el ~]$ ls
private.pem
public.pem

After installing yubihsm2-sdk, we invoke the command:

sudo yubihsm-connector &>/dev/null &

We visit the following address in a web browser:

http://localhost:12345/connector/status

and check the status of the connection with the Module. The information we get should be similar to the following:

status=OK
serial=*
version=3.0.2
pid=45428
address=localhost
port=12345

Thereby, a secure tunnel for communicating with the Module has been created.

Before we conduct the full configuration, it’s a good idea to create an Authentication Key with all possible privileges but protected with our own password. Consequently, it becomes possible to perform the operations blocked with the default Authentication Key and to easily perform a software factory reset. We’ll be able to delete that key the recommended way after our configuration is completed and tested. As a result, it won’t be necessary to perform a hardware factory reset, what is not pleasant in any way neither to an HSM, nor to a USB port, since this is performed by pressing the device to a USB port forcibly.

First, we invoke the command:

yubihsm-shell

and second, the next commands within the device’s interface:

yubihsm> connect
Session keepalive set up to run every 15 seconds
yubihsm> session open 1
Enter password:
Created session 0

session open 1 means opening a session with Authentication Key ID 1 (hex 0x0001), which is supplied in the Module by default and its default password is: password. Even though the structure of commands for both opening and closing a session appears to be quite similar, when closing a session we type the ID of the session we close, rather than an ID of a key.

Lets list the objects in the Module to ensure that the factory settings are correct – it is necessary to suffix a session ID, which comes from running the earlier commands, to the list objects command. In this case that ID of the session just created is 0:

yubihsm> list objects 0
Found 1 object(s)
id: 0x0001, type: authentication-key, sequence: 0

In the Module we have only one Authentication Key that authorizes logging in to the device. No other objects are present. This way we can add our MasterKey:

yubihsm> put authkey 0 0x0009 MasterKey all all all
Enter password:
Stored Authentication key 0x0009

Following the above command’s convention: we create in our active session 0 an Authentication Key ID 9 (hex 0x0009) named nicely as MasterKey with the maximum amount of domains and capabilities. This is necessary since the default Authentication Key, which is created with the yubihsm-setup command, does not provide a reset capability, that is factory-resetting the device.

Let’s check all the capabilities of the key created this way:

yubihsm> get objectinfo 0 0x0009 authentication-key

We’ll get the following list:

id: 0x0009, type: authentication-key, algorithm: aes128-yubico-authentication, label: "MasterKey", length: 40, domains: 1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16, sequence: 0, origin: imported, capabilities: change-authentication-key:create-otp-aead:decrypt-oaep:decrypt-otp:decrypt-pkcs:delete-asymmetric-key:delete-authentication-key:delete-hmac-key:delete-opaque:delete-otp-aead-key:delete-template:delete-wrap-key:derive-ecdh:export-wrapped:exportable-under-wrap:generate-asymmetric-key:generate-hmac-key:generate-otp-aead-key:generate-wrap-key:get-log-entries:get-opaque:get-option:get-pseudo-random:get-template:import-wrapped:put-asymmetric-key:put-authentication-key:put-mac-key:put-opaque:put-otp-aead-key:put-template:put-wrap-key:randomize-otp-aead:reset-device:rewrap-from-otp-aead-key:rewrap-to-otp-aead-key:set-option:sign-attestation-certificate:sign-ecdsa:sign-eddsa:sign-hmac:sign-pkcs:sign-pss:sign-ssh-certificate:unwrap-data:verify-hmac:wrap-data, delegated_capabilities: change-authentication-key:create-otp-aead:decrypt-oaep:decrypt-otp:decrypt-pkcs:delete-asymmetric-key:delete-authentication-key:delete-hmac-key:delete-opaque:delete-otp-aead-key:delete-template:delete-wrap-key:derive-ecdh:export-wrapped:exportable-under-wrap:generate-asymmetric-key:generate-hmac-key:generate-otp-aead-key:generate-wrap-key:get-log-entries:get-opaque:get-option:get-pseudo-random:get-template:import-wrapped:put-asymmetric-key:put-authentication-key:put-mac-key:put-opaque:put-otp-aead-key:put-template:put-wrap-key:randomize-otp-aead:reset-device:rewrap-from-otp-aead-key:rewrap-to-otp-aead-key:set-option:sign-attestation-certificate:sign-ecdsa:sign-eddsa:sign-hmac:sign-pkcs:sign-pss:sign-ssh-certificate:unwrap-data:verify-hmac:wrap-data

The key looks correct. Thus we can add the next RSA keys for signing packages. We’ll import a key ID 5 from the private.pem file created earlier and we’ll create a key ID 6 directly in our Module. The following examples are based on one, single domain, so we’ll be identifying it as just “1”:

yubihsm> put asymmetric 0 5 rsakey 1 sign-pkcs,exportable-under-wrap private.pem
Stored Asymmetric key 0x0005
yubihsm> generate asymmetric 0 6 genrsa 1 sign-pkcs,exportable-under-wrap rsa2048
Generated Asymmetric key 0x0006

The time it takes to generate this last key is about 7 seconds. If we do not add the exportable-under-wrap capability, the key will never be able to be extracted from the Module. This is why in the above case we leave the capability of an Object to be exportable under wrap.

Let’s close session 0 created with the default Authentication Key ID 1 and let’s test logging in with our MasterKey – that is Authentication Key ID 9. In the same session we’ll next get the public key of the RSA key ID 6 we generated earlier in the Module, copy it to a clipboard and disconnect from the Module.

yubihsm> session close 0
yubihsm> session open 9
yubihsm> get pubkey 0 6
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+xtOVKo9rZfy2jtziw1
I5pIEkDS3ftZFFdxOv9e98ui4mBXBQKzqlRP6jMqMi1MtIyBAhv2rmqCDc7VOctj
T6jtam5IK6388Y617BZ3T6PHUvaq1X2Pkzp/yDw4mw6oCB2cjxT4xuTk3Ki5JeRn
/KDLKaXfEZnseBmypfBBtv9E+ZET3ZpOBRLIS3PEl+65gug3oimVuRcLjzvUErcg
NkI+bwzBjA/kCPKCzL5BX5H5LanqeoDe8vObZKn8g3YHuSjl6nhHREBH9YNjmgl+
jO0Q8rQ8xRnZF5IHK3Px5s7jwhG9oJrBxs01O25NnVSO7qoCBL2Ek6GfCqjOXI6L
5QIDAQAB
-----END PUBLIC KEY-----
yubihsm> session close 0
yubihsm> disconnect
yubihsm> quit

Let’s save the key we have in our clipboard as a file we’ll name genpublic.pem.

YubiHSM 2 FIPS Configuration

We’ll perform a complete Module setup for KSP (Key Storage Provider). While the setup can be performed through the yubihsm-shell command, the yubihsm-setup command is way more comfortable to use:

yubihsm-setup ksp

Without specifying additional parameters, the above command utilizes our default Authentication Key ID 1, which is supplied in the Module by default after a factory reset and its default password is: password:

Enter authentication password: password
Using authentication key 0x0001
Would you like to add RSA decryption capabilities? (y/n)

We get an information that our Authentication Key ID 1 (hex: 0x0001) is used and a prompt if we want to add RSA decryption capabilities – we choose the answer “y”.

In this practical example a single domain will be enough for us. When prompted to enter domains, we provide only the number “1”:

Enter domains: 1
Using domains:
	 One

Here we enter the number “2” as a Wrap Key ID, since ID 1’s space is temporarily preoccupied with the default Authentication Key ID 1 provided by default:

Enter wrap key ID (0 to choose automatically): 2
Stored wrap key with ID 0x0002 on the device

We’ll get an information that the Wrap Key ID 2 has been stored on the device.

Next, three parts of the Wrap Key will be shown. Each one of them must be recorded and stored by three administrators (a part is shown after a screen is cleared). Only two Wrap Key pieces will be required to restore backed up data on a fresh HSM:

Enter the number of shares: 3
Enter the privacy threshold: 2                    

*************************************************************
* WARNING! The following shares will NOT be stored anywhere *
* Record them and store them safely if you wish to re-use   *
* the wrap key for this device in the future                *
*************************************************************
Press Enter to start recording key shares 

2-1-fY/UAf6cK1/vklhSoM++u9QziaSqXGM2XDv9B1jAjEOBGh8NLmrpFGu/verU4gw5XsyNpg
Have you recorded the key share? (y/n)

2-2-+gW1AeElVr7DOeCkXYNha7ZlTVhzyIQN7zJaeoAnjbEmZmvY9zMHmfaJa5AlPnArTH5clg
Have you recorded the key share? (y/n)

2-3-h4hhAR+5feEsq4j2/Uzf0GNX+gzPT9nvdTXMUch6eRSwuUdgSwRd4nab0k2Bga8lQhAThg
Have you recorded the key share? (y/n)

We’ll now create a new Authentication Key ID 3 with way restricted capabilities compared to the default factory-supplied Authentication Key ID 1:

Enter application authentication key ID (0 to choose automatically): 3
Enter application authentication key password: rhL#Yrz)eh9X_S
Stored application authentication key with ID 0x0003 on the device
Saved wrapped application authentication key to ./0x0003-authentication-key.yhw

As we can see in the snippet above, our new Authentication Key has also been stored in a working directory on our workstation.

In the next step we’ll create an Audit Key ID 4. YubiHSM internally stores a log with all the events of maintenance and cryptographic actions that occur in the Module. Such a log can be displayed for monitoring the Module and reporting its operation. Each entry (line) in the Store is connected through a hashing chain and signed. This allows to determine, whether any of the events have been tampered with or deleted.

Creating an Audit Key that only has rights to access the Module’s log entries is the next automatic step of the `yubihsm-setup` command:

Would you like to create an audit key? (y/n) y
Enter audit key ID (0 to choose automatically): 4
Enter audit authentication key password: Ar$@w_d+5G49x3
Stored audit authentication key with ID 0x0004 on the device
Saved wrapped audit authentication key to ./0x0004-authentication-key.yhw
Previous authentication key 0x0001 deleted
All done

The configuration is finished. The default factory-supplied Authentication Key ID 1 has been automatically deleted from the Module and the new keys: Authentication Key ID 3 and Audit Key ID 4 also been stored in a working directory on our workstation:

[eurolinux@el85 ~]$ ls *.yhw
0x0003-authentication-key.yhw  0x0004-authentication-key.yhw

Signing files with HSM

Before we start signing files with HSM, we need to create appropriate entries that will let us communicate with YubiHSM 2 FIPS through PKCS#11 interface. From here, I direct you to the Module’s documentation – though I’ll mention that the entries in our ~/.bashrc file shall look similar to the ones in the following listing (they may differ a bit depending on the distribution used):

export YUBIHSM_PKCS11_CONF=/etc/pki/tls/yubihsm_pkcs11.conf
export YUBIHSM_PKCS11_MODULE=/usr/lib64/pkcs11/yubihsm_pkcs11.so
alias yhsm2-tool='pkcs11-tool --module ${YUBIHSM_PKCS11_MODULE} --login'

Let’s sign some sample files with our RSA keys. Caution: when prompted to enter User PIN, we need to provide the Authentication Key’s ID in hex without the „0x” prefix with the key’s password appended – e.g. 0003rhL#Yrz)eh9X_S. Additionally, we specify ID 5 of the RSA key we imported earlier, which we’ll use to create a signature:

[eurolinux@el ~]$ echo $RANDOM | tee test-file-1.txt
[eurolinux@el ~]$ yhsm2-tool --sign --id 0005 -m SHA256-RSA-PKCS -i test-file-1.txt -o test-file-1.sig
Using slot 0 with a present token (0x0)
Logging in to "YubiHSM".
Please enter User PIN: 
Using signature algorithm SHA256-RSA-PKCS

and let’s software verify the signature with the public.pem public key:

[eurolinux@el ~]$ openssl dgst -sha256 -verify public.pem -signature test-file-1.sig test-file.txt
Verified OK

As we can see, the signature has been verified correctly.

We can test a signature verification the same way for the key ID 6 we generated directly in the Module. However, it’s vital that the genpublic.pem key be used for that verification.

Backup the HSM’s data

We can consider the configuration and signature tests as complete. Therefore, we should create a backup of all the keys that are in the Module. Since the default factory-supplied Authentication Key ID 1 has been deleted from the Module earlier, we need to provide an ID of a new Authentication Key with the -k parameter – in this case ID 3 (hex: 0x0003).

[eurolinux@el ~]$ yubihsm-setup -k 3 dump
Enter authentication password: rhL#Yrz)eh9X_S
Using authentication key 0x0003
Enter the wrapping key ID to use for exporting objects: 2
Found 6 object(s)
Unable to export object authentication-key with ID 0x0009: Wrong permissions for operation. Skipping over ...
Successfully exported object asymmetric-key with ID 0x0005 to ./0x0005-asymmetric-key.yhw
Successfully exported object asymmetric-key with ID 0x0006 to ./0x0006-asymmetric-key.yhw
Unable to export object wrap-key with ID 0x0002: Wrong permissions for operation. Skipping over ...
Successfully exported object authentication-key with ID 0x0003 to ./0x0003-authentication-key.yhw
Successfully exported object authentication-key with ID 0x0004 to ./0x0004-authentication-key.yhw
All done

[eurolinux@el ~]$ ls
0x0003-authentication-key.yhw  genpublic.pem
0x0004-authentication-key.yhw  private.pem
0x0005-asymmetric-key.yhw      public.pem
0x0006-asymmetric-key.yhw

When asked to enter the wrapping key ID to use for exporting objects, we specified ID 2. The information above carry the message that it was not possible to export our MasterKey and Wrap Key 0x0002, and that the rest of the keys has been wrapped and saved to a working directory on our workstation. Though we do have the pieces of the Wrap Key 0x0002 divided by our three administrators, what makes it possible to import the rest of the keys to another, backup HSM.

Let’s again log in to the Module with the Authentication Key ID 3 and list all the objects in the device, the data on the occupied storage space and general Module information:

[eurolinux@el ~]$ yubihsm-shell
Using default connector URL: http://127.0.0.1:12345
yubihsm> connect
Session keepalive set up to run every 15 seconds
yubihsm> session open 3
Enter password: 
Created session 0
yubihsm> list objects 0
Found 6 object(s)
id: 0x0002, type: wrap-key, sequence: 0
id: 0x0003, type: authentication-key, sequence: 0
id: 0x0004, type: authentication-key, sequence: 0
id: 0x0005, type: asymmetric-key, sequence: 0
id: 0x0006, type: asymmetric-key, sequence: 0
id: 0x0009, type: authentication-key, sequence: 0
yubihsm> get storage 0
free records: 250/256, free pages: 1004/1024 page size: 126 bytes
yubihsm> get deviceinfo
Version number:		2.2.0
Serial number:		16499959
Log used:		55/62
Supported algorithms:	rsa-pkcs1-sha1, rsa-pkcs1-sha256, rsa-pkcs1-sha384, 
			rsa-pkcs1-sha512, rsa-pss-sha1, rsa-pss-sha256, 
			rsa-pss-sha384, rsa-pss-sha512, rsa2048, 
			rsa3072, rsa4096, ecp256, 
			ecp384, ecp521, eck256, 
			ecbp256, ecbp384, ecbp512, 
			hmac-sha1, hmac-sha256, hmac-sha384, 
			hmac-sha512, ecdsa-sha1, ecdh, 
			rsa-oaep-sha1, rsa-oaep-sha256, rsa-oaep-sha384, 
			rsa-oaep-sha512, aes128-ccm-wrap, opaque-data, 
			opaque-x509-certificate, mgf1-sha1, mgf1-sha256, 
			mgf1-sha384, mgf1-sha512, template-ssh, 
			aes128-yubico-otp, aes128-yubico-authentication, aes192-yubico-otp, 
			aes256-yubico-otp, aes192-ccm-wrap, aes256-ccm-wrap, 
			ecdsa-sha256, ecdsa-sha384, ecdsa-sha512, 
			ed25519, ecp224, rsa-pkcs1-decrypt, 
			
yubihsm> session close 0

Let’s open a new session with out Audit Key ID 4 and fetch our Module’s audit log:

yubihsm> session open 4
Enter password: 
Created session 0
yubihsm> audit get 0
0 unlogged boots found
0 unlogged authentications found
Found 58 items
item:     1 -- cmd: 0xff -- length: 65535 -- session key: 0xffff -- target key: 0xffff -- second key: 0xffff -- result: 0xff -- tick: 4294967295 -- hash: 37223398636214763cb25f56370d261a
item:     2 -- cmd: 0x00 -- length:    0 -- session key: 0xffff -- target key: 0x0000 -- second key: 0x0000 -- result: 0x00 -- tick: 0 -- hash: 20093cb7a5ccba04e7ccaabc66617f37
item:     3 -- cmd: 0x03 -- length:   10 -- session key: 0xffff -- target key: 0x0001 -- second key: 0xffff -- result: 0x83 -- tick: 44011 -- hash: ee9a3e41ebaaf69cbf24cabe1335ffd8
item:     4 -- cmd: 0x04 -- length:   17 -- session key: 0xffff -- target key: 0x0001 -- second key: 0xffff -- result: 0x84 -- tick: 44011 -- hash: 029ba4e75b02529003515fe2a32b90ca
(...)
item:    58 -- cmd: 0x04 -- length:   17 -- session key: 0xffff -- target key: 0x0004 -- second key: 0xffff -- result: 0x84 -- tick: 199145 -- hash: 9d654498b49407dd84ebd15c66dc48fd
yubihsm> session close 0

After closing the session, let’s open another (the last one) with our MasterKey ID 9 and software-reset our Module to factory settings:

yubihsm> session open 9
Enter password: 
Created session 0
yubihsm> reset 0
Device successfully reset
yubihsm> quit

Restore the HSM’s data from backup

In order to restore the keys we dumped earlier, we’ll need to ask for assistance at least two administrators, each having a piece of the Wrap Key ID 2, which was used to wrap (encrypt) the keys that got saved to our working directory earlier. This time we’ll invoke the yubihsm-setup command with the -d option, what will prevent the deletion of the default factory-supplied Authentication Key ID 1. Since the Module is now reset, we use the default password: password. In the number of shares prompt we specify only the required amount of pieces of the Wrap Key, 2 in our case.

[eurolinux@el ~]$ yubihsm-setup -d restore
Enter authentication password: password
Using authentication key 0x0001
Enter the number of shares: 2
Enter share number 1: 2-1-fY/UAf6cK1/vklhSoM++u9QziaSqXGM2XDv9B1jAjEOBGh8NLmrpFGu/verU4gw5XsyNpg
Received share 2-1-fY/UAf6cK1/vklhSoM++u9QziaSqXGM2XDv9B1jAjEOBGh8NLmrpFGu/verU4gw5XsyNpg
Enter share number 2: 2-3-h4hhAR+5feEsq4j2/Uzf0GNX+gzPT9nvdTXMUch6eRSwuUdgSwRd4nab0k2Bga8lQhAThg
Received share 2-3-h4hhAR+5feEsq4j2/Uzf0GNX+gzPT9nvdTXMUch6eRSwuUdgSwRd4nab0k2Bga8lQhAThg
Stored wrap key with ID 0x0002 on the device

reading ./0x0003-authentication-key.yhw
Successfully imported object authentication-key, with ID 0x0003
reading ./0x0004-authentication-key.yhw
Successfully imported object authentication-key, with ID 0x0004
reading ./0x0005-asymmetric-key.yhw
Successfully imported object asymmetric-key, with ID 0x0005
reading ./0x0006-asymmetric-key.yhw
Successfully imported object asymmetric-key, with ID 0x0006
Previous authentication key 0x0001 *not* deleted. Make sure you know what you are doing
All done

Our two RSA keys (the first one imported from a file and the second one created directly in the Module) have been reinstated in an HSM and it’s once again possible to use them to sign files and verify signatures with the public.pem and genpublic.pem public keys in our workstation. Both the Authentication Key ID 3 and the Audit Key ID 4 have also been properly imported. Our Module will be ready for production use after the factory-supplied Authentication Key ID 1 is deleted and after several additional operations:

yubihsm> delete 0 1 authentication-key

Summary

A Hardware Security Module provides the highest level of security in our company, which consists of delegating cryptographic operations outsite the realm of applications, the integrity and confidentiality of documents, the protection of certificates and keys from physical and network threats. The implementation of HSMs in EuroLinux Sp. z o.o. guarantees the security of keys and the applications that use these keys according to the cryptographic procedures included in the American standard FIPS 140-2 level 3.

Authors

The blog articles are written by people from the EuroLinux team. We owe 80% of the content to our developers, the rest is prepared by the sales or marketing department. We make every effort to ensure that the content is the best in terms of content and language, but we are not infallible. If you see anything that needs to be corrected or clarified, we'd love to hear from you.