Skip to content

Instantly share code, notes, and snippets.

@joostd
Created March 7, 2023 18:04
Show Gist options
  • Select an option

  • Save joostd/ac44db2d4e8e9bdbdde7cdab5c05c0fb to your computer and use it in GitHub Desktop.

Select an option

Save joostd/ac44db2d4e8e9bdbdde7cdab5c05c0fb to your computer and use it in GitHub Desktop.
Signing EFI images with keys generated on a YubiHSM 2 device

Signing EFI images with keys generated on a YubiHSM 2 device.

Using an Ubuntu VM with the YubiHSM connector running on the SSH client, tunneled over SSH:

$ ssh -i key.pem ubuntu@jammy -R 12345:localhost:12345
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-1031-aws x86_64)
...

Signing a Grub EFI image for CentOS. Downloading and extracting the images:

$ wget --quiet http://mirror.centos.org/centos/7/updates/x86_64/Packages/grub2-efi-x64-2.02-0.87.el7.centos.7.x86_64.rpm
$ sudo apt install -y rpm2cpio
$ rpm2cpio grub2-efi-x64-2.02-0.87.el7.centos.7.x86_64.rpm | cpio -idmv
./boot/efi/EFI/centos
./boot/efi/EFI/centos/fonts
./boot/efi/EFI/centos/fonts/unicode.pf2
./boot/efi/EFI/centos/grubx64.efi
./boot/grub2/grubenv
./etc/grub2-efi.cfg
7194 blocks

Install pesign for generating signing keys, verifying and generating signatures:

$ sudo apt install pesign

The grubx64.efi image has two signatures:

$ pesign -i ./boot/efi/EFI/centos/grubx64.efi -S
---------------------------------------------
certificate address is 0x7f259c0bfc08
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is CentOS Secure Boot (key 1)
The signer's email address is security@centos.org
Signing time: Thu Oct 14, 2021
There were certs or crls included.
---------------------------------------------
certificate address is 0x7f259c0c05a8
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is CentOS Secure Boot Signing 202
The signer's email address is security@centos.org
Signing time: Thu Oct 14, 2021
There were certs or crls included.
---------------------------------------------

Remove the signatures and end up with an unsigned image file:

$ pesign -i ./boot/efi/EFI/centos/grubx64.efi --remove-signature --signature-number=1 --out ./grubx64.efi
$ pesign -i ./grubx64.efi --remove-signature --signature-number=0 --out grubx64.efi.empty
$ pesign -i ./grubx64.efi.empty -S
No signatures found.

Install the YubiHSM 2 SDK.

See https://developers.yubico.com/YubiHSM2/Releases/ for the latest SDK binary release for specific platforms.

Download and install the packages for your platform:

$ wget --quiet https://developers.yubico.com/YubiHSM2/Releases/yubihsm2-sdk-2023-01-ubuntu2204-amd64.tar.gz
$ tar xf yubihsm2-sdk-2023-01-ubuntu2204-amd64.tar.gz 
$ cd yubihsm2-sdk/
$ sudo dpkg -i *.deb
$ cd ..

Test communication with the YubiHSM: Note that in this example there is a tunnel to the SSH client running a connector.

$ yubihsm-shell -p password -a get-device-info
Using default connector URL: http://localhost:12345
Session keepalive set up to run every 15 seconds
Version number:		2.2.0
Serial number:		12345678
Log used:		62/62
Supported algorithms:	rsa-pkcs1-sha1, rsa-pkcs1-sha256, rsa-pkcs1-sha384, 
			rsa-pkcs1-sha512, rsa-pss-sha1, rsa-pss-sha256, 
			rsa-pss-sha384, rsa-pss-sha512, rsa2048, 
			rsa3072, rsa4096, ecp256, 
			ecp384, ecp521, eck256, 
			ecbp256, ecbp384, ecbp512, 
			hmac-sha1, hmac-sha256, hmac-sha384, 
			hmac-sha512, ecdsa-sha1, ecdh, 
			rsa-oaep-sha1, rsa-oaep-sha256, rsa-oaep-sha384, 
			rsa-oaep-sha512, aes128-ccm-wrap, opaque-data, 
			opaque-x509-certificate, mgf1-sha1, mgf1-sha256, 
			mgf1-sha384, mgf1-sha512, template-ssh, 
			aes128-yubico-otp, aes128-yubico-authentication, aes192-yubico-otp, 
			aes256-yubico-otp, aes192-ccm-wrap, aes256-ccm-wrap, 
			ecdsa-sha256, ecdsa-sha384, ecdsa-sha512, 
			ed25519, ecp224, rsa-pkcs1-decrypt, 

Configure the YubiHSM PKCS#11 module.

$ echo "connector = http://localhost:12345" > yubihsm_pkcs11.conf
$ export YUBIHSM_PKCS11_CONF=/home/ubuntu/yubihsm_pkcs11.conf 
$ export YUBIHSM_PKCS11_MODULE=/usr/lib/x86_64-linux-gnu/pkcs11/yubihsm_pkcs11.so 

Test if the PKCS#11 module is working:

$ pkcs11-tool --module $YUBIHSM_PKCS11_MODULE --login -t
...
No errors

Create an NSS database and link the YubiHSM 2 module to it:

$ mkdir pesign
$ certutil -N -d pesign --empty-password
$ modutil -dbdir ./pesign -add yubihsm -libfile $YUBIHSM_PKCS11_MODULE -force
Module "yubihsm" added to database.

Verify you can access the YubiHSM token through NSS:

$ modutil -dbdir ./pesign -list yubihsm

-----------------------------------------------------------
Name: yubihsm
Library file: /usr/lib/x86_64-linux-gnu/pkcs11/yubihsm_pkcs11.so
Manufacturer: Yubico (www.yubico.com)         
Description: YubiHSM PKCS#11 Library         
PKCS #11 Version 2.40
Library Version: 2.40
Cipher Enable Flags: None
Default Mechanism Flags: None

  Slot: YubiHSM Connector localhost
  Slot Mechanism Flags: None
  Manufacturer: Yubico                          
  Type: Hardware
  Version Number: 3.3
  Firmware Version: 3.3
  Status: Enabled
  Token Name: YubiHSM                         
  Token Manufacturer: Yubico (www.yubico.com)         
  Token Model: YubiHSM         
  Token Serial Number: 12345678        
  Token Version: 2.20
  Token Firmware Version: 2.20
  Access: NOT Write Protected
  Login Type: Login required
  User Pin: Initialized

-----------------------------------------------------------

Generate a signing key on the YubiHSM:

$ efikeygen -t YubiHSM -S -n signer -c 'CN=EFI Signer' --dbdir pesign
Enter Password or Pin for "YubiHSM":

Verify that the key is generated on the YubiHSM token:

$ certutil -L -d pesign -h YubiHSM

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI

Enter Password or Pin for "YubiHSM": ********
YubiHSM:signer                                               u,u,u

The signing certificate can be retrieved also using yubihsm-shell:

$ yubihsm-shell -a get-opaque --label signer --outformat PEM 
Using default connector URL: http://localhost:12345
Session keepalive set up to run every 15 seconds
Enter password: 
Created session 2
-----BEGIN CERTIFICATE-----
MIIDMjCCAhqgAwIBAgIQRAjNfud5RsyCEtJmw3LacTANBgkqhkiG9w0BAQsFADAV
MRMwEQYDVQQDEwpFRkkgU2lnbmVyMB4XDTIzMDMwNzE1MzcyMFoXDTMzMDMwNDE1
MzcyMFowFTETMBEGA1UEAxMKRUZJIFNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAMxjxFQaRNNRM597P6Vrbe7haL2tixLWedAWawDAlS02ZSDC
RPYdJlhNS+O1RLzreK+8xAx5BZhKEQ460mFYXZhWm2Vwbr9YfAFK5tU1pNdIb5Gd
T0sJ1xEa/euGOrwRUw2ZkLO7iMk7F8nX5eK4xBYAlQI6EJ9UO0lngoorj/grKo3y
t7x+vOmw9TM6k58rUCLxYC7nflEy3WLLooVwPA/Cw44OAJmWVfzzNwU03jHyqKwH
G31WEj9LQ7DIHn+fCbHmrgFF1CtMxffyaI+mjUNPfClhMD3zCvA5eNlV5wjCtjre
ezUeEWti7aXHTTUvHvT6KPGYv3nX45jynkq5rm8CAwEAAaN+MHwwHwYDVR0jBBgw
FoAUO0/Bvs5Zx6EZLgw4IYB3gL0KTd4wFQYJYIZIAYb4QgEBAQH/BAUDAwDwATAT
BgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8EBAMCBLAwHQYDVR0OBBYEFDtP
wb7OWcehGS4MOCGAd4C9Ck3eMA0GCSqGSIb3DQEBCwUAA4IBAQCGrSDB0YuDBERD
TanM64c7gLIKG5mBLbVdr6AcfjIlBiePUp749O2ydajLzgw/sjVIgm5jJFQu8SUj
JRQz9OIPEAT2Fhe5e1H4+mOWUqFJJ1HRoGQosDC0GnapHpu8IlTloRM4qE99u1D9
UfuI+3Qpdr0XfAGPRAzRUcRlhaqP/qKpnS6VxlmDNv2uXFr0Ts8OJtH+1Lpv3ReO
mpRI0L/X3o9ORwFIhldRN6jtmccl5Ws88hTMdt/iXVr4mu+uA8vmabcdxC+WB2tv
b1BZeshXYzWVRnYlHjqZBDyUlFYESKzySbiVR55I/10lX3js0XsW/n21yImZh8/P
GdZCDoYd
-----END CERTIFICATE-----

Now sign the EFI file:

$ pesign --certdir ./pesign --nss-token YubiHSM -c signer -s -i grubx64.efi.empty -o grubx64.efi.signed
Enter Password or Pin for "YubiHSM": ********

View the newly generated signature:

$ pesign -i ./grubx64.efi.signed -S
---------------------------------------------
certificate address is 0x7f520ad5ac08
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is EFI Signer
No signer email address.
Signing time: Tue Mar 07, 2023
There were certs or crls included.
---------------------------------------------

Alternatively, we can use sbverify to verify the signature:

$ yubihsm-shell -a get-opaque --label signer --outformat PEM --out cert.pem
Using default connector URL: http://localhost:12345
Session keepalive set up to run every 15 seconds
Enter password: ********
Created session 0
$ sbverify --cert cert.pem ./grubx64.efi.signed 
Signature verification OK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment