This article focuses on enabling the usage of the keys stored in the TPM2 by various tools using the PKCS#11 interface. The module should be configured to allow the access to these keys only after some measurement of the state of the system is done, to guarantee that it was not tampered. This part is outside of the scope of these notes. Here the protections offered to the user are the physical possession and the requirement to enter a PIN.
PKCS#11 exposes N separate slots, each containing a token. We will used a separate slot/token for each application. For the basic support under Arch Linux, the following packages need to be installed:
tpm2-tss. The latest package also sets up udev rules to allow the abrmd broker daemon to access the device
/dev/tpm0. You can test if the TPM2 module is working by printing some random characters by using its random number generator:
$ tpm2_getrandom --hex 16
tpm-pkcs11 needs to save some information on disk, I've set the
TPM2_PKCS11_STORE environment variable to a suitable directory in my
SSH in slot 0
Using the TPM2 is pretty straightforward. From here on [PIN] denotes the user PIN. Avoid saving the command lines containing it in the bash history, for example by prepending the line with a space.
$ tpm2_ptool init action: Created id: 1 $ tpm2_ptool addtoken --pid=1 --sopin=[PIN] --userpin=[PIN] --label=ssh_token $ tpm2_ptool addkey --algorithm=rsa2048 --label=ssh_token --key-label=ssh_token --userpin=[PIN] action: add private: CKA_ID: '33333334333132626661393734663161' public: CKA_ID: '33333334333132626661393734663161'
To output the public key (to be added to the
authorized_keys file on the remote system):
$ ssh-keygen -D /usr/lib/pkcs11/libtpm2_pkcs11.so ssh-rsa AAAAB3NzaC1yc2EAAAADAQA...
And you can connect to a system by offering the key from the TPM2:
$ ssh -I /usr/lib/pkcs11/libtpm2_pkcs11.so [destination host]
GnuPG in slot 1
Supporting GnuPG is more complicated. You will need
openssl for creating a certificate from the public key and the package
gnupg-pkcs11-scd to interface GnuPG with the TPM2 via the PKCS#11 API. Unfortunately, there is a bug at the moment in the upstream program which doesn't correctly inform the GnuPG agent daemon about the key padding. I prepared a Pull Request for the upstream, until it is merged, you need to use the version from my github repository.
The initial part is similar to the previous case, but then you need to create a certificate from the public key to allow GnuPG to use it:
$ tpm2_ptool init action: Created id: 2 $ tpm2_ptool addtoken --pid=2 --label=gpg_token --sopin=[PIN] --userpin=[PIN] $ tpm2_ptool addkey --algorithm=rsa2048 --label=gpg_token --key-label=gpg_token --userpin=[PIN] $ openssl <<EOF req -engine pkcs11 -new -key pkcs11:model=rls;manufacturer=Nuvoton;serial=0000000000000000;token=gpg_token;type=private;pin-value=[PIN] -keyform engine -out req.pem -text -x509 -subj /CN=[Your Common Name] x509 -engine pkcs11 -signkey pkcs11:model=rls;manufacturer=Nuvoton;serial=0000000000000000;token=gpg_token;type=private;pin-value=[PIN] -keyform engine -in req.pem -out cert.pem EOF $ tpm2_ptool addcert --label gpg_token --key-label gpg_token cert.pem
Afterwards, we need to configure the SCD (smart card driver) for the GnuPG Agent which uses the PKCS#11 to work with the private key. Unfortunately, GnuPG Agent supports only a single SCD, so you cannot use both the TPM2 and a normal smart card at the same time. Also, note that the patched version of gnupg-pkcs11-scd needs to be used until upstream is fixed. Two configuration files need changes:
has_padding providers tpm provider-tpm-library /usr/lib/pkcs11/libtpm2_pkcs11.so
- for the latter, the following debug directives might be useful if you encounter any problems:
verbose debug-all log-file /tmp/scd.log
GnuPG Agent has to be restarted and you need to trigger a reload of the smart card:
$ systemctl --user restart gpg-agent.service $ gpg --card-status
The next step consist in identifying the keygrip for the RSA keypair stored in the TPM2 module. The procedure for creating a keypair should support automatically identifying the smartcard. Unfortunately, this doesn't seem working, so you need to manually list the available keygrips:
$ gpg-agent --server gpg-connect-agent << EOF SCD LEARN EOF ... gnupg-pkcs11-scd: S KEY-FRIEDNLY 01B4D88E8F24441E1773472EFAD1CFE020072CF2 /CN=[The CN you used] on gpg_tokenchan_0 ... ...
Look for a 40 characters long string of letters and numbers after the words
KEY-FRIENDLY. With this information you can proceed with the normal generation of a keypair using option 13 Existing key and entering the keygrip when prompted:
$ gpg --expert --full-generate-key ... Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) (7) DSA (set your own capabilities) (8) RSA (set your own capabilities) (9) ECC and ECC (10) ECC (sign only) (11) ECC (set your own capabilities) (13) Existing key (14) Existing key from card Your selection? 13 Enter the keygrip: 01B4D88E8F24441E1773472EFAD1CFE020072CF2 ...
And that's it, you should have a keypair based on the RSA keys in the TPM2. Please test it by encrypting/decrypting/signing some text.