When documenting my experiences using a SmartCard-HSM for DNSSEC I linked to a post by Remy van Elst in which he discusses using a CardContact SmartCard-HSM with SSH, and I thought I’d try that, focussing on using EC keys.

SmartCard-HSM in keyboard

The six year-old HSM I have has support for 2048 bit only RSA keys which is enough reason to attempt using EC keys, but as Remy pointed out when he wrote the article in 2016, OpenSSH had no PKCS#11 support for them then.

It turns out my client of choice has OpenSSH_8.1p1 which isn’t recent enough either, so I install portable OpenSSH version 8.6p1.

$ ./configure --prefix=/tmp/ssh \
              --with-ssl-dir=/usr/local/Cellar/openssl\@1.1/1.1.1i/
...
OpenSSH has been configured with the following options:
...
                   PKCS#11 support: yes
                  U2F/FIDO support: yes
...

I then create an EC key pair on the HSM:

$ pkcs11-tool --pin 123456 --keypairgen --key-type EC:prime256v1 --label SSH-key-s00
Using slot 0 with a present token (0x0)
Key pair generated:
Private Key Object; EC
  label:      SSH-key-s00
  ID:         6423210e6bde55c0c4b8ce6d6eafb98b6bdd2a4c
  Usage:      sign, derive
  Access:     none
Public Key Object; EC  EC_POINT 256 bits
  EC_POINT:   044104accb84a58d36204a25f14bf76c5c967de7c48b93831a86dd370d6fd9eb16d88d5f02fdec36ea6006c4ca21cc704997a5886133f8bf1e8acdbd34223456f4f482
  EC_PARAMS:  06082a8648ce3d030107
  label:      SSH-key-s00
  ID:         6423210e6bde55c0c4b8ce6d6eafb98b6bdd2a4c
  Usage:      verify, derive
  Access:     none

and extract the SSH public key for this object; nice that the key label is added to the output:

$ pkcs15-tool --read-ssh-key 6423210e6bde55c0c4b8ce6d6eafb98b6bdd2a4c
Using reader with a card: Identive SCT3522CC token
ecdsa-sha2-nistp256 AAAAE2VjZHNhLX[..]hM/i/HorNvTQiNFb09II= SSH-key-s00

The public SSH key I place into an authorized_keys file on the target system. (I do this manually now but will typically use ssh-copy-id to do so.)

$ cat .ssh/authorized_keys
ecdsa-sha2-nistp256 AAAAE2VjZHNhLX[..]hM/i/HorNvTQiNFb09II= SSH-key-s00

Back on my client, I attempt to connect using the newly-built SSH client:

$ /tmp/ssh/bin/ssh -v -o "PKCS11Provider /usr/local/Cellar/opensc/0.21.0/lib/opensc-pkcs11.so"  192.168.33.15
OpenSSH_8.6p1, OpenSSL 1.1.1i  8 Dec 2020
debug1: Connecting to 192.168.33.15 [192.168.33.15] port 22.
debug1: Connection established.
debug1: provider /usr/local/Cellar/opensc/0.21.0/lib/opensc-pkcs11.so: manufacturerID <OpenSC Project> cryptokiVersion 2.20 libraryDescription <OpenSC smartcard framework> libraryVersion 0.21
debug1: provider /usr/local/Cellar/opensc/0.21.0/lib/opensc-pkcs11.so slot 0: label <SmartCard-HSM (User... (UserPIN> manufacturerID <www.CardContact.de> model <PKCS#15 emulate> serial <DECC0500007> flags 0x40d
..
debug1: Local version string SSH-2.0-OpenSSH_8.6
debug1: Remote protocol version 2.0, remote software version OpenSSH_7.9p1 Debian-10+deb10u2
..
debug1: Will attempt key: rs001 RSA SHA256:B0KDkBLyWjkyfGS3X0AhBdHgFboXSWTpzbG5AP2qcjI token
..
debug1: Will attempt key: SSH-key-s00 ECDSA SHA256:/uGTFUy11/xvMbsp0n2GSw7xqrK0+HV+sCALVNjBRkw token
..
debug1: Authentications that can continue: publickey,password
debug1: Offering public key: SSH-key-s00 ECDSA SHA256:/uGTFUy11/xvMbsp0n2GSw7xqrK0+HV+sCALVNjBRkw token
debug1: Server accepts key: SSH-key-s00 ECDSA SHA256:/uGTFUy11/xvMbsp0n2GSw7xqrK0+HV+sCALVNjBRkw token
Enter PIN for 'SmartCard-HSM (User... (UserPIN':
debug1: pkcs11_check_obj_bool_attrib: provider 0x7fc8a48047c0 slot 0 object 140499730079136: attrib 514 = 0
..
debug1: Authentication succeeded (publickey).
Authenticated to 192.168.33.15 ([192.168.33.15]:22).
..
You have new mail.

That looks good to me, so I launch an SSH agent so as to not have to enter the HSM PIN whenever I connect a machine.

$ eval $(/tmp/ssh/bin/ssh-agent -P "/usr/local/Cellar/opensc/0.21.0/lib/*")
Agent pid 72428

$ /tmp/ssh/bin/ssh-add -s /usr/local/lib/opensc-pkcs11.so
Enter passphrase for PKCS#11:
Card added: /usr/local/lib/opensc-pkcs11.so

Note how I use -P to whitelist the paths for PKCS#11 shared libraries that may be added using the -s option to ssh-add. This option expects the real directory and not a symlink to it.

$ /tmp/ssh/bin/ssh-add -l
2048 SHA256:B0KDkBLyWjkyfGS3X0AhBdHgFboXSWTpzbG5AP2qcjI rs001 (RSA)
256 SHA256:/uGTFUy11/xvMbsp0n2GSw7xqrK0+HV+sCALVNjBRkw SSH-key-s00 (ECDSA)

And the rest, as they say, should be obvious: I can SSH into systems without having to specify the SmartCard-HSM PIN as the key is now managed by the agent.

$ /tmp/ssh/bin/ssh -v 192.168.33.15
..
debug1: Server accepts key: SSH-key-s00 ECDSA SHA256:/uGTFUy11/xvMbsp0n2GSw7xqrK0+HV+sCALVNjBRkw agent
..

If I unplug the HSM from USB the SSH agent loses connection and will not be able to provide the key to SSH clients. Plugging the token back in doesn’t do anything here; I have to kill and restart the agent and add the keys back into it.

I’m grateful to Remy for having inspired me to do this.

ssh, security, and hsm :: 16 Jun 2021 :: e-mail