This guide describes how to build RPMs that use pesign. Pesign is used for signing PE/COFF EFI executables so that they can be used with UEFI secure boot. Enrolling DB or MOK keys and signing kernel modules is beyond the scope of this guide.
-
Install pesign.
sudo dnf install pesign
-
Create a directory to hold the secure boot signing keys and the NSS database.
KEY_DIR=/path/to/keys sudo mkdir -m 700 "${KEY_DIR}"
-
Create an RSA keypair. This will be used for signing the kernel, kernel modules, and other EFI executables.
sudo openssl req \ -new \ -x509 \ -newkey rsa:2048 \ -sha256 \ -keyout "${KEY_DIR}/key.pem" \ -out "${KEY_DIR}/cert.pem" \ -days 3650 \ -subj "/CN=Secure Boot Signing Key/"
-
Export the keypair as PKCS#12 so that it can be imported into an NSS database.
sudo openssl pkcs12 \ -export \ -inkey "${KEY_DIR}/key.pem" \ -in "${KEY_DIR}/cert.pem" \ -name secure_boot \ -out "${KEY_DIR}/secure_boot.p12"
-
Create an NSS database. I prefer to use a different NSS database, but the default
/etc/pki/pesign
path also can be used. Note that/etc/pki/pesign
has no password by default, so anyone listed in/etc/pesign/groups
or/etc/pesign/users
can read private keys from that database. (Using smart cards is beyond the scope of this answer. There's an example in the Fedora infrastructure Ansible scripts.)sudo certutil -d "${KEY_DIR}/nss_db" -N
-
Import the private key and certificate into database:
sudo pk12util -d "${KEY_DIR}/nss_db" -i "${KEY_DIR}/secure_boot.p12"
-
Ensure that only root can access the keys and that the NSS database has the correct SELinux label.
sudo chmod -R 'go-rwx' "${KEY_DIR}" sudo chcon --reference=/etc/pki/pesign -R "${KEY_DIR}/nss_db"
-
If you are not using
/etc/pki/pesign
for the NSS database, configure the pesign service to point to the proper path.sudo mkdir /etc/systemd/system/pesign.service.d/ sudo tee /etc/systemd/system/pesign.service.d/custom_dir.conf << EOF [Service] ExecStart= ExecStart=/usr/bin/pesign --daemonize -n ${KEY_DIR}/nss_db EOF sudo systemctl daemon-reload
The changes should appear in the output of the following command.
sudo systemctl cat pesign
-
Add your user or a group to the pesign ACLs. This will give the specified users or groups access to the pesign daemon as well as
/etc/pki/pesign
.# To add the current user whoami | sudo tee -a /etc/pesign/users # To add a group sudo tee -a /etc/pesign/groups <<< 'group_name'
NOTE: You must make sure that the NSS database path is readable by root. SELinux does not give the
pesign_t
typedac_read_search
anddac_override
permissions, so pesign cannot bypass the Unix permission model, despite running as root. If you use/etc/pki/pesign
, then addroot
to/etc/pesign/users
or else pesign won't be able to read the files in the directory. -
Apply the ACL changes.
sudo /usr/libexec/pesign/pesign-authorize
-
Start the pesign daemon.
sudo systemctl start pesign # Optionally, enable to start pesign at boot sudo systemctl enable pesign
-
Set the
pesign_t
SELinux type to permissive. The current SELinux policy doesn't seem to allow the pesign daemon to do anything useful. For example, a spec file that tries to use the%pesign
macro will result in the following AVC denial.Dec 05 20:19:19 cxl-laptop-1 audit[6132]: AVC avc: denied { read } for pid=6132 comm="pesignd" path="/var/lib/mock/chenxiaolong-fedora-27-x86_64/root/builddir/build/BUILD/shim-signed-13/shimia32-unsigned.efi" dev="dm-1" ino=1711111 scontext=system_u:system_r:pesign_t:s0 tcontext=unconfined_u:object_r:mock_var_lib_t:s0 tclass=file permissive=0
To work around this, make
pesign_t
permissive. It's not the best solution, but at least SELinux doesn't need to be set to permissive globally.sudo semanage permissive -a pesign_t
-
Check if the NSS token is unlocked.
pesign-client -q
If the NSS token is locked, unlock it using the passphrase you used when creating the NSS database.
pesign-client -u
To build a package that uses pesign with rpmbuild, just define the pe_signing_token
and pe_signing_cert
macros. For example:
rpmbuild -bb -D 'pe_signing_token NSS Certificate DB' -D 'pe_signing_cert secure_boot' shim-signed.spec
Note that there's currently a typo (RHBZ#1508094) that prevents self-signing from working. This can be fixed by editing /usr/lib/rpm/macros.d/macros.pesign
manually or using a patched pesign package from my repo: https://copr.fedorainfracloud.org/coprs/chenxiaolong/rhbz1508094-fix/.
To build a package with mock, /var/run/pesign
needs to be bind mounted into the chroot so that processes inside the chroot can talk to the pesign daemon. To do that, add the following to either /etc/mock/site-defaults.cfg
or ~/.config/mock.cfg
.
config_opts['plugin_conf']['bind_mount_opts']['dirs'].append(('/var/run/pesign', '/var/run/pesign'))
To build a package, define the pe_signing_token
and pe_signing_cert
macros. Due to an issue with mock and systemd-nspawn, --old-chroot
is also required.
For example:
mock --rebuild shim-signed-13-0.7.src.rpm -D 'pe_signing_token NSS Certificate DB' -D 'pe_signing_cert secure_boot' --old-chroot
Note that there's currently a typo (RHBZ#1508094) that prevents self-signing from working. Unlike with rpmbuild, this can't be fixed by editing /usr/lib/rpm/macros.d/macros.pesign
because the chroot has its own copy of the file. The easiest way to fix this is to add my repo with a patched pesign package to the mock configuration: https://copr.fedorainfracloud.org/coprs/chenxiaolong/rhbz1508094-fix/.