How to Use YubiHSM 2 With PKCS#11 in Java for RSA Decryption

Recently, I had to implement a solution to keep an RSA private key safe with YubiHSM 2 and Java, also using PKCS#11. It required a bit more steps than I would’ve liked and there wasn’t much information on the web. Hence, I decided to share what’s needed to make it work.

Hendrig Sellik
Feb 1 · 8 min read
Photo by Philipp Katzenberger on Unsplash

Table of Contents

What Is an HSM?

What Is YubiHSM 2?

Setting Up YubiHSM 2

sudo yubihsm-connector -d --config "/location/to/yubihsm-connector-config.yaml"
# Listening address. Defaults to "localhost:12345".
listen: localhost:12345
# Device serial in case of multiple devices
serial: ""
# Log to syslog/eventlog. Defaults to "false".
syslog: false
# Use to enable host header filtering. Default to "false".
# Use this if there is an absolute need to use a web browser on the host where the YubiHSM 2 is installed to connect to untrusted web sites on the Internet.
enable-host-whitelist: false
# Default list for the host header filter
host-whitelist: localhost,localhost.,127.0.0.1,[::1]
$curl http://127.0.0.1:12345/connector/status
status=OK
serial=*
version=2.2.0
pid=303337
address=localhost
port=12345

PKCS#11

Generating 2048 Bit RSA Key for PKCS#11

yubihsm> generate asymmetric SESSION_ID KEY_ID LABEL DOMAINS CAPABILITIES KEY_ALGORITHMyubihsm> put opaque SESSION_ID KEY_ID LABEL DOMAINS none opaque-x509-certificate /ABSOLUTE/PATH/TO/TEMPLATE_X509_CERT.deryubihsm> attest asymmetric SESSION_ID KEY_ID KEY_ID /ABSOLUTE/PATH/TO/SELF_SIGNED_CERT.deryubihsm> delete SESSION_ID KEY_ID opaqueyubihsm> put opaque SESSION_ID KEY_ID LABEL DOMAINS CAPABILITIES opaque-x509-certificate /ABSOLUTE/PATH/TO/SELF_SIGNED_CERT.der
openssl req -x509 -outform der -keyout /tmp/privkey.pem -out /tmp/TEMPLATE_X509_CERT.der
$yubihsm-shell --connector http://127.0.0.1:12345
yubihsm> connect
yubihsm> session open 45bd 9ga2k5jhk1234hkl
yubihsm> generate asymmetric 0 0x1e16 my_key_alias 1 exportable-under-wrap:sign-pkcs:sign-pss:decrypt-pkcs,sign-attestation-certificate rsa2048yubihsm> put opaque 0 0x1e16 my_key_alias 1 none opaque-x509-certificate /tmp/TEMPLATE_X509_CERT.derThen we use the attest function to sign the self-signed certificate and the delete the template certificate and import the new self-signed certificateyubihsm> attest asymmetric 0 0x1e16 0x1e16 /tmp/SELF_SIGNED_CERT.dercopy the console output to /tmp/SELF_SIGNED_CERT.deryubihsm> delete 0 0x1e16 opaqueyubihsm> put opaque 0 0x1e16 my_key_alias 1 none opaque-x509-certificate /tmp/SELF_SIGNED_CERT.der

Generating Authentication Key

yubihsm> put authkey 0 0x3c86 my_auth_key 1,2,3 sign-pkcs,sign-ecdsa,sign-eddsa,decrypt-pkcs,decrypt-oaep,get-pseudo-random,sign-hmac,verify-hmac,get-log-entries,sign-ssh-certificate,decrypt-otp get-pseudo-random k9fo5lsotks7

Configuration for Java

export YUBIHSM_PKCS11_CONF=/location/to/yubihsm_pkcs11.conf
# The address of the Connector
connector=http://127.0.0.1:12345

PKCS#11 implementation in Java code

Debugging YubiHSM 2

-Djava.security.debug=sunpkcs11,pkcs11keystore
# Enables debug output in the module
debug
# Redirects the debug output to a specific file. The file is created if it does not exist. The content is appended
debug-file = /location/to/yubihsm_pkcs11_debug.txt
# Enables function tracing (ingress/egress) debug output in the module
dinout
# Enables libyubihsm debug output in the module
libdebug

Errors you may face when trying to use PKCS#11

1) error: PKCS11 function C_Login failed: rv = CKR_ARGUMENTS_BAD (0x7)
2) sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ATTRIBUTE_TYPE_INVALID
3) javax.crypto.BadPaddingException: dofinal() failed. Caused by sun.security.pkcs11.wrapper.PKCS11Exception: CKR_FUNCTION_FAILED
4) java.security.KeyStoreException: PKCS11 not found. Caused by: java.security.NoSuchAlgorithmException: no such algorithm: PKCS11 for provider SunPKCS11-YubiHSM

Conclusion

Additional Reading

RingIT Blog

A blog about software development, technology and life at…