This topic is derived from hibernate signature verification project. In the hibernate signature verification, Jiri Kosina provided a idea that kernel uses a secret key that it's created by EFI stub and stored in EFI boot service variable before ExitBootService. When EFI secure boot is enabled, the boot variables are secure because all execution code in boot time must be signed by the keys in db.
The hibernate signature verification direct uses the secret key (is named EFI SB root key in this article) as the HMAC key to sign the snapshot image. I think that we can extend this key with MOK to create a key storage in EFI NVRAM for KMK (Kernel Master Key) and encrypted key.
The benefit for creating KMK in EFI boot time environment
A key storage base on EFI boot service variable can be used to break away initrd. At least we do not need to keep the secret key in userland.
I have tried to implement hibernate verification by KMK/Encrypted Key similar to EVM. When the EVM mechanism runs with keyring, the KMK (Kernel Master Key) can be a trusted key (sealed by TPM) or a user key (enroll by user space). The user key is a plain text key that it can be used for development or testing. The EVM key is a encrypted key that it's encrypted by KMK (trusted key or user key). Either KMK or encrypted key must rely on user space to store the keys in disk or initrd file. Which means the KMK/encrypted can only be enrolled after user space takes the control.
The place for restoring keys is another problem especially for hibernation. If hibernation resuming wants to use the KMK to verify the signature of snapshot. Then the KEK/encrypted key must be enrolled before swap partition be mounted. Normally those keys are kept in root parition, which means those keys can not be found before hibernation resuming from swap. Unless the KMK can be stored in initrd and enrolled by systemd in very early stage, otherwise the hibernate signature verification will be fail.
Another benefit is that creating KMK in EFI boot time can be a alternative plan when the platform doesn't have TPM or user does not want to use TPM. The EFI secure boot protects the code/data in boot environment, and the chain of trusted can be extended to boot loader and kernel if those components are signed by keys in db/MOK. It's not that solid as TPM, but still better than other approach like storing keys in userland.
SB-KMK can be a MOK companion symmetric key
In the MOK mechanism, we only keep the public key in EFI boot service variable. Which means that kernel doesn't have private key for signing or decrypting at runtime. So creating a symmetric key to link with MOK as a companion for HMAC or AES encryption by kernel.
As the following figure, when EFI stub got a signal from EFI variable (which means the system must be rebooted). It creates a symmetric key (64 or 128 bytes) and stores the key's plain text in EFI boot variable. The index of symmetric key is the fingerprint of MOK. We can just call it "SB-KMK".
Once the SB-KMK is created, EFI stub loads and forwards the key to kernel. Kernel will wrap it as a encrypted key (encrypted by MOK public key) and put to root keyring. This KMK can be used to encrypted other keys like: evm-key or s4-signkey
As other kernel master key, SB-KMK can be used to create encrypted keys. The process is similar to SB-KMK, userland writes a EFI variable as a signal for asking EFI stub to generate a new symmetric key. The index of key is the MOK fingerprint with key description like "evm-key". The keys will be loaded by EFI stub and forwarded to kernel. Kernel will encrypt the plain text by SB-KMK then put to root keyring for other subsystem.
Choosing the root SB-KMK
Normally there have multiple enrolled MOK in system. Which means that have multiple SB-KMK and derivative keys hierarchy. User must chose a SB-KMK as the root key. Kernel can provides a kernel parameter for boot command, and a one way switch sysfs interface for initrd/dracut/userland. Kernel will put the chosen SB-KMK and derivative keys to root keyring, Then kernel erase other SB-KMK and keys from memory.
Export SB-KMK to userland
EFI firmware is not designed for storing keys as solid like TPM. In case the SB-KMK be removed by buggy firmware updating. User may wants to export SB-KMK for backup. The plain text of MOK-KMK and derivative keys can not be leaked to userland, so kernel encrypts KMK with MOK public key before exposes it to userland. Only the holder of MOK private key can decrypt it. On the other hand, the derivative key are encrypted by SB-KMK which is no problem to hold by userland.
Using EFI SB root key as the root of SB-KMK
Here has another approach for anyone does not want to enroll/maintain MOK by themself. They can use the EFI SB root key as the root of SB-KMK. If kernel is built with appropriate option, EFI SB root key will be created in the first boot on EFI machine. It's a 64 or 128 bytes symmetric key that it can be used for encrypt or HMAC. Hibernation signature verification uses it to create/verify the signature of snapshot image. Just like MOK, it can be used to encrypt SB-KMK.
The benefit for using EFI SB root key instead of MOK is that user doesn't need to enroll and maitain MOK key pair. EFI SB root key can be a default root key that it can be enabled by kernel parameter. The defect is EFI SB root key is a plain text key that it can not be export to userland. Unless user enrolled their own MOK, then kernel can uses MOK public key to encrypt EFI SB root key for exposing.
Need interactive with boot loader for KMK maintenance
Once the SB-KMK be created, there only way for maintenance is UI interactive with boot loader. Because we need to make sure user is physical accessing the machine, and user knows what is he doing.
Limitation
- The SB-KMK can not be trusted when secure boot is disabled. Which means that SB-KMK will not be loaded by kernel when secure boot is disabled. It may causes that integrity functions may work when secure boot disabled unless there have other way to provide KMK.
- EFI NVRAM has space limiation
...