Skip to content

Creating a CA with a Pkcs11 Module

Stefan Berger edited this page Sep 24, 2020 · 3 revisions

The following example sets up a local CA using a pkcs11 module as the (root) CA. The setup is done under a user's account.

We use softhsm2 as an example pkcs11 module since it is commonly available. certtool is part of the gnutls package.

Setting up SoftHSM2

First we setup softhsm2:

  #> sudo apt-get install -y softhsm gnutls-bin      # Debian/Ubuntu
  #> sudo dnf install -y softhsm gnutls-utils        # Fedora/RedHat

  #> mkdir -p ~/.config/softhsm2/tokens

  #> cat <<_EOF_ > ~/.config/softhsm2/softhsm2.conf
directories.tokendir = ${HOME}/.config/softhsm2/tokens
objectstore.backend = file
log.level = DEBUG
slots.removable = false
_EOF_

  #> export SOFTHSM2_CONF=${HOME}/.config/softhsm2/softhsm2.conf

  #> softhsm2-util --init-token --label mytoken --free --so-pin my-so-pin --pin my-pin
Slot 0 has a free/uninitialized token.
The token has been initialized and is reassigned to slot 353319736

We set SOFTHSM2_CONF to the location of our softhsm2 configuration file. In this particular case it would not have been necessary since the file at ${HOME}/.config/softhsm2/softhsm2.conf is being searched automatically by softhsm2, but it makes clear where the file is located at.

Creating an RSA key

Now we use certtool to create the private key for our root CA. We then create a self-signed certificate.

In every step involving pkcs11 URIs, one has to use the pkcs11 URIs shown in the local output, so do not just copy all the command lines here. All URIs used on the command line have to be surrounded by single quotes (').

  #> p11tool --list-tokens
[...]
Token 2:
	URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=b5187422150f3b38;token=mytoken
	Label: mytoken
	Type: Generic token
	Flags: RNG, Requires login
	Manufacturer: SoftHSM project
	Model: SoftHSM v2
	Serial: b5187422150f3b38
	Module: /usr/lib64/pkcs11/libsofthsm2.so
[...]

  #> p11tool --generate-privkey=rsa --login --set-pin my-pin --label cakey \
'pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=b5187422150f3b38;token=mytoken'
Generating an RSA key...
-----BEGIN PUBLIC KEY-----
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA4P9KeEDe5iy8FmKg1FGM
BzCFdyUlCkW/evMr0s8Rr2kMcheZfNdI8/AIG99Ih3hAzs1Q5wiqXpM68L+IcRce
pzO1DRYW6nlzdXSJUgGEoWehhFme3sltYegh57kPti30C3qHPIrpXLNkCLXt4fOt
arY/r+D7W7WR/XAnUKgWGBPkUKYo9uOabkQC9c7vdJ2IBengg+gGCo1V6QMHOSlt
HtIDC7vjNXcnWAZymdD+AWnPgIv4aHhGad6cIAQmiTnEiVP85QlY2lxkOaVgQK4w
lcjlwXEuQi1oamIg+o10ZC4JFozCt9amEGGnhJjKurzj6qKfYwm/Lxd3FZt4SWWR
lU9pjz/PrR2Z4KOG2xzwsgd+9GVKR91FfMkiIc6eNZz9gGB0rnnzlKDYlIsLFNY3
0pp6ksPRkeutnVK6Ct+mcysI1gLwfhfr1FJ4LFLkVO/np6JmYMuZlj5rNdBZIRaC
qEdZvaScFMTkwJI9uoyHC0Y4nJMo0xt0HAz2jIHj2n3lAgMBAAE=
-----END PUBLIC KEY-----

  #> p11tool --list-privkeys --login --set-pin my-pin \
'pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=b5187422150f3b38;token=mytoken'

	URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=b5187422150f3b38;token=mytoken;id=%DE%75%15%CF%BD%C4%70%51%89%F4%68%10%1B%01%4E%1D%0E%B9%F0%E9;object=cakey;type=private
	Type: Private key (RSA-3072)
	Label: cakey
	Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; 
	ID: de:75:15:cf:bd:c4:70:51:89:f4:68:10:1b:01:4e:1d:0e:b9:f0:e9

  #> export SIGNINGKEY='pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=b5187422150f3b38;token=mytoken;id=%DE%75%15%CF%BD%C4%70%51%89%F4%68%10%1B%01%4E%1D%0E%B9%F0%E9;object=cakey;type=private'

  #> cat <<_EOF_ > template
cn=swtpm-localca-rootca
ca
cert_signing_key
expiration_days = 3650
_EOF_

  #> GNUTLS_PIN=my-pin certtool --generate-self-signed --template template --outfile issuercert.pem --load-privkey ${SIGNINGKEY}
Generating a self signed certificate...
[...]
Signing certificate...

Setting up a local CA and creating an EK certificate

We now have our root CA's certificate in issuercert.pem. Let's set up a local CA and create an EK certificate. The signing key is the pkcs11 URI of the private key. We can pass the PIN either using SWTPM_PKCS11_PIN or signingkey_password (since swtpm 0.5.0) or append ?pin-value=my-pin to the URI. We also write the softhsm2 environment variable into this file so that the softhsm2 pkcs11 module will find its configuration file.

  #> XDG_CONFIG_HOME=${HOME}/.config /usr/share/swtpm/swtpm-create-user-config-files
Writing /home/stefanb/.config/swtpm_setup.conf.
Writing /home/stefanb/.config/swtpm-localca.conf.
Writing /home/stefanb/.config/swtpm-localca.options.

  #> cat <<_EOF_ > ${HOME}/.config/swtpm-localca.conf
statedir = ${HOME}/.config/var/lib/swtpm-localca
signingkey = ${SIGNINGKEY}
signingkey_password = my-pin
issuercert = ${HOME}/.config/var/lib/swtpm-localca/issuercert.pem
certserial = ${HOME}/.config/var/lib/swtpm-localca/certserial
env:SOFTHSM2_CONF=${HOME}/.config/softhsm2/softhsm2.conf
_EOF_

  #> mv issuercert.pem ~/.config/var/lib/swtpm-localca/issuercert.pem

  #> /usr/share/swtpm/swtpm-localca --type ek --ek da625739e699ac82d1f76ea42f368d8870a33a6a062ef6c7beb9545e1d11d23652544a47f36b3c33cb054671e4db0497624a451da4b6314aba9fb11bf1feac6d6960a600633987f90613413a3f0e3b6680445ce7d30e1d9d0edcb48349717fbe1c66cf51e1e6750d229d290ebba423e5b966c15f5e4a13b6bf51d10cb023c60fd8a086d3897efbb11b136580aeac9646abf38fb9ba67f6109d6fb644df6b343d3604031efcad11f58c1ce8de1ebe85ded71339573b319ba60805e80c298c64dd2b44160537bf9a96309e5b64ac5df76784f133c09d79755588eacf1a7d2a1067725b8e3d03467d46df3e390d1cc98372df5d4ffd7f68401d53404f54485ebf55 \
--dir ./ --tpm-spec-family 2.0 --tpm-spec-level 0 --tpm-spec-revision 162 --tpm-manufacturer id:00001014 \
--tpm-model swtpm --tpm-version id:20191023 --tpm2 --configfile ${HOME}/.config/swtpm-localca.conf \
--optsfile ${HOME}/.config/swtpm-localca.options --vmid test
CA uses a PKCS#11 key; using password from 'signingkey_password'
Successfully created EK certificate locally.

  #> ls -l ek.cert
-rw-rw-r--. 1 stefanb stefanb 1015 Sep 18 14:05 ek.cert

Verifying the certificate chain

Finally, we verify the certificate chain.

  #> certtool -i --inder --infile ek.cert --outfile ekcert.pem

  #> certtool --verify --load-ca-certificate ${HOME}/.config/var/lib/swtpm-localca/issuercert.pem \
--infile ekcert.pem --verify-profile medium
Loaded CAs (1 available)
	Subject: CN=test
	Issuer: CN=swtpm-localca-rootca
	Checked against: CN=swtpm-localca-rootca
	Signature algorithm: RSA-SHA256
	Output: Verified. The certificate is trusted. 

Chain verification output: Verified. The certificate is trusted. 

If libvirt is used in user mode, then this local CA will create the TPM certificates. To use a similar CA in libvirt's 'system mode', the configuration file /etc/swtpm-localca.conf would have to be adapted accordingly.