2 releases
0.0.2 | Jun 22, 2023 |
---|---|
0.0.1 | Jun 15, 2023 |
#2130 in Cryptography
105KB
1K
SLoC
openpgp-pkcs11-tools
This crate implements opgpkcs11
, an exploratory CLI tool that exposes the functionality in
openpgp-pkcs11-sequoia
to use PKCS #11 devices in an OpenPGP context.
The tool can be used to upload OpenPGP component keys to PKCS #11 devices, and use these keys to perform OpenPGP signing and decryption operations.
This tool can also be used to migrate gnupg-pkcs11-scd-based setups to Sequoia PGP. In this use case, the OpenPGP public key (or OpenPGP certificate) is required alongside the PKCS #11 device (the OpenPGP certificate is necessary to access OpenPGP metadata that is not available on the HSM).
Signing via PKCS #11
Once a signing subkey has been loaded onto an HSM, it can be used to sign as an OpenPGP key (the tool produces a detached signature).
$ echo "hello world" | cargo run --bin opgpkcs11 -- sign --serial 16019180 --id 2
-----BEGIN PGP MESSAGE-----
wsAdBAATCgBvBYJj9RTACRDgxC4SrzU3rkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u
cy5zZXF1b2lhLXBncC5vcmcbgC3H5TAyHrskkS/Df1YhQm0hOxV2PR//4p0LHA7k
cRYhBNbjGCcsr64WE/F/t+DELhKvNTeuAABosAF/Yd26f75FMeP8uSVFR2+4J593
F+O5+U5kx1Fo1IXX6gNhrLuniEq7fDrbflFStbuCAX47Cd/+D/IlC6YSf//W9etl
sd4uMBq3AWNU3IwYJpm3/Zcx0L/2CTVa3hYa/jWmCm8=
=/R5+
-----END PGP MESSAGE-----
NOTE: On the YubiKey 4/5, --id 2
corresponds to the PIV "Digital Signature" slot (PIV 9c).
Read more about ykcs11 Key Mapping
here.
(If the default path for the PKCS #11 module /usr/lib64/libykcs11.so
isn't correct on your
system, you need to provide a path with the parameter --module
.)
After storing this detached signature in /tmp/sig
, we can verify it with sq:
$ echo "hello world" | sq verify --signer-file /tmp/janus.pgp --detached /tmp/sig
Good signature from E0C42E12AF3537AE
1 good signature.
Decryption via PKCS #11
Analogous to signing (above), a PKCS #11 device can be used to perform OpenPGP decryption operations:
Let's make an encrypted message:
$ echo "secret message!" | sq encrypt --recipient-file /tmp/janus.pgp > /tmp/secret.pgp
(If the default path for the PKCS #11 module /usr/lib64/libykcs11.so
isn't correct on your
system, you need to provide a path with the parameter --module
.)
Now we can decrypt the message on the card:
$ cat /tmp/secret.pgp | cargo run --bin opgpkcs11 -- decrypt --serial 16019180 --id 3
secret message!
NOTE: On the YubiKey 4/5, --id 3
corresponds to the PIV "KeyManagement" slot (PIV 9d).
Read more about ykcs11 Key Mapping
here
(IDs 5-24 can be used to address "Retired Key Management" slots).
Uploading to PKCS #11
cargo run --bin opgpkcs11 -- upload --serial 1234 --id 2 --key /tmp/janus.rsa2 --fingerprint E35AE0F1494FBE1098014BD61E71CF45C4A31FEC
NOTE: uploading to YubiKey 4/5 via the ykcs11 driver currently doesn't work (due to limitations of the ykcs11 driver). As an alternative, OpenPGP keys can be uploaded to these devices via the PIV interface, and then used for signing and decryption via PKCS #11.
Hardware devices with PKCS #11 support
Notes on some specific devices that can be accessed via PKCS #11.
YubiKey 4/5
https://developers.yubico.com/PIV/
- YKCS11 module (shows PIV to ykcs11 id mapping)
Example setup using YubiKey PIV CLI tools
Reset PIV application on the card:
$ ykman piv reset
Generate a new key in slot '9d' ("Key Management") and export the public key into the file public-9d.pem
:
$ yubico-piv-tool -s 9d -a generate -A ECCP256 -o public-9d.pem
(To inspect a public key ECC file: openssl ec -pubin -in pubkey.pem -text
)
Generate a new key in slot '9a' ("PIV Authentication"), using RSA by default, and export the public key into the file public-9a.pem
:
$ yubico-piv-tool -s 9a -a generate -o public-9a.pem
Dynamic library for PKCS #11 access:
$ export MODULE=/usr/lib64/libykcs11.so
Inspect "objects" on the card:
$ pkcs11-tool --module $MODULE -O
Supported functionality and limitations
The YubiKey PIV applet (which is optionally accessible via a PKCS #11 interface) supports RSA 2048, NIST P-256 and NIST P-384. Signing and decryption operations are supported with keys that use those algorithms.
Upload to the card via the PKCS #11 interface is not currently
supported, due to limitations of the ykcs11
driver. However, keys can be
uploaded to the card using the PIV interface, and then used for cryptographic
operations via PKCS#11.
Notes
YubiHSM 2
https://developers.yubico.com/YubiHSM2/Usage_Guides/YubiHSM_quick_start_tutorial.html
USB access (udev)
Access to the USB device needs to be granted, e.g. with a udev rule like:
/etc/udev/rules.d/10-yubihsm.rules
:
SUBSYSTEM=="usb", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0030", OWNER="username"
If necessary, reload the rules:
# udevadm control --reload-rules
NOTE: On my system, the YubiHSM2 didn't work when connected to USB3 ports. If you have trouble, try different USB ports, and/or USB hubs.
yubihsm-connector
"The Connector, yubihsm-connector, performs the communication between the YubiHSM 2 and applications that use it":
https://developers.yubico.com/YubiHSM2/Component_Reference/yubihsm-connector/
$ yubihsm-connector -d
Once the connector is running, access to the YubiHSM can be tested via:
$ yubihsm-shell
Using default connector URL: http://localhost:12345
yubihsm> connect
Session keepalive set up to run every 15 seconds
NOTE: During normal operation, on my system I see regular errors in yubihsm-connector
output:
handle_events: error: libusb: interrupted [code -10]
Logging in
- https://docs.yubico.com/software/yubihsm-2/component-reference/hsm2-ref-pkcs11.html#logging-in
- https://docs.yubico.com/hardware/yubikey/yk-5/tech-manual/yubihsm-auth.html
By default, logging in with yubihsm-shell
works like:
yubihsm> session open 1 password
In yubihsm-shell
, a KDF-scheme is used:
List objects
yubihsm> connect
Session keepalive set up to run every 15 seconds
yubihsm> session open 1 password
Created session 0
yubihsm> list objects 0 0 asymmetric-key
Found 12 object(s)
id: 0x02f1, type: asymmetric-key, algo: rsa2048, sequence: 0 label:
[..]
id: 0xf6bc, type: asymmetric-key, algo: rsa2048, sequence: 0 label:
Resetting a YubiHSM
yubihsm> connect
Session keepalive set up to run every 15 seconds
yubihsm> session open 1 password
Created session 0
yubihsm> reset 0
Device successfully reset
Using YubiHSM2 via PKCS #11
https://developers.yubico.com/yubihsm-shell/yubihsm-pkcs11.html
https://github.com/Yubico/yubihsm-shell/blob/master/lib/yubihsm.c#L579
Sources for the YubiHSM PKCS #11 module:
https://github.com/Yubico/yubihsm-shell/tree/master/pkcs11
Testing
yubihsm_pkcs11.so
can use a configuration file.
Here we use a minimal file /tmp/ykhsm.conf
:
connector=http://localhost:12345
Setup:
$ export MODULE="/usr/lib64/pkcs11/yubihsm_pkcs11.so"
$ export YUBIHSM_PKCS11_CONF=/tmp/ykhsm.conf
$ export SERIAL=`cargo run --bin opgpkcs11 -- --module $MODULE list`
Upload decryption subkey:
cargo run --bin opgpkcs11 -- --module $MODULE upload --serial $SERIAL --slot dec --pin 0001password --key /tmp/janus.rsa
Decrypt:
echo "hello world" | sq encrypt --recipient-file /tmp/janus.rsa >/tmp/enc
cat /tmp/enc | cargo run --bin opgpkcs11 -- --module $MODULE decrypt --serial $SERIAL --pin 0001password
Sign:
echo "hello world" | cargo run --bin opgpkcs11 -- --module $MODULE sign --serial $SERIAL --pin 0001password
Inspect card state:
cargo run --bin opgpkcs11 -- --module $MODULE dump --serial $SERIAL --pin 0001password
Supported functionality
All operations (key upload, signing, decryption) are supported for RSA 2048, RSA 3072, RSA 4096, NIST P-256, NIST P-384 and NIST P-521.
Software Implementations of PKCS #11
SoftHSM2
https://github.com/opendnssec/SoftHSMv2
Example setup/usage
(Paths for current Fedora, on different distributions exact paths will vary)
Make temporary storage path and configure SoftHSM to use it:
$ export SOFTHSM2_CONF=$(mktemp) && DIR=$(mktemp --directory) && echo "directories.tokendir = $DIR" > $SOFTHSM2_CONF
$ export MODULE=/usr/lib64/softhsm/libsofthsm.so
Initialize 'slot 0' on SoftHSM, set User PIN to 123456
, generate RSA key in slot 0:
$ pkcs11-tool --init-token --module $MODULE --slot-index 0 --label TestToken --so-pin 12345678
$ pkcs11-tool --init-pin --login --so-pin 12345678 --pin 123456 --slot-index 0 --module $MODULE
$ pkcs11-tool --module $MODULE --slot-index 0 --login --pin 123456 --keypairgen --key-type rsa:2048 --id 3
Inspect card (needs User PIN):
$ pkcs11-tool --module $MODULE --test --pin 123456
Testing opgpkcs11
with SoftHSM
"SoftHSM is an implementation of a cryptographic store accessible through a PKCS #11 interface."
Init (module path for Fedora, may differ on other systems):
export SOFTHSM2_CONF=$(mktemp) && DIR=$(mktemp --directory) && echo "directories.tokendir = $DIR" > $SOFTHSM2_CONF
export MODULE=/usr/lib64/softhsm/libsofthsm.so
pkcs11-tool --init-token --module $MODULE --slot-index 0 --label TestToken --so-pin 123456
pkcs11-tool --init-pin --login --so-pin 123456 --pin 123456 --slot-index 0 --module $MODULE
Generate OpenPGP key for testing
cargo run --bin janus_gen rsa2048 >/tmp/janus.rsa
Upload decryption subkey to SoftHSM
You can store the serial of the SoftHSM device in the environment variable SERIAL
with:
export SERIAL=`cargo run --bin opgpkcs11 -- --module $MODULE list`
cargo run --bin opgpkcs11 -- --module $MODULE upload --serial $SERIAL --slot dec --key /tmp/janus.rsa
Encrypt to key, decrypt on card
echo "hello world" | sq encrypt --recipient-file /tmp/janus.rsa >/tmp/enc.janus
cat /tmp/enc.janus | cargo run --bin opgpkcs11 -- --module $MODULE decrypt --serial $SERIAL
Supported functionality
On this device, all operations (key upload, signing, decryption) are supported for the following algorithms: RSA 2048, RSA 3072, RSA 4096, NIST P-256, NIST P-384 and NIST P-521.
A CI test under cli/ci/softhsm
tests the full set of operations for all
supported algorithms.
Dependencies
~31–42MB
~751K SLoC