Motivation: Each end-user has their own security threat model. What is important to one end-user may not be important to another. There is not a right or wrong threat model.
A common request made when adding new kernel changes that could impact the threat model around system kernel keys is to add additional Kconfig options. As kernel developers, it is challenging to both add and keep track of all the Kconfig options around security features that may limit or restrict system key usage. It is also difficult for a general purpose distro to take advantage of some of these features, since it may prevent some users from executing their workload. It is the author's belief that it is better left up to the end-user on how kernel keys should be used within their system. Throughout the Linux kernel, key usage is tracked when doing signature verification with keys contained within one of the system keyrings; however, there isn't a way for the end-user to enforce this usage. This series gives the end-user the ability to configure key usage based on their threat model. Having the ability to enforce key usage also improves security by reducing the attack surface should a system key be compromised. It allows new features to be added without the need for additional Kconfig options for fear of changing the end-user's threat model. It also allows a distro to build a kernel that suits various end-user's needs without resorting to selecting Kconfig options with the least restrictive security options. Solution: This series introduces a new LSM called Clavis (Latin word meaning key). This LSM leaves it up to the end-user to determine what system keys they want to use and for what purpose. The Clavis LSM adds the ability to do access control for all system keys. When enabled, until an ACL entry is added for a specific key, none of the system keys may be used for any type of verification purpose. When the kernel is built, typically kernel modules are signed with an ephemeral key, an ACL entry for the ephemeral key is pre-loaded, allowing the kernel modules to load during boot. At build time other ACL entries may also be included. The Clavis LSM requires the end-user to have their own public key infrastructure (PKI). In order for a Clavis ACL entry to be added, the ACL must be signed by what is being called the Clavis key. The Clavis key is owned by the end-user. The Clavis public key can be contained within the machine keyring, or it can be added after the machine boots. Not only is there a new Clavis key being introduced, but there is also a new .clavis keyring. The .clavis keyring contains a single Clavis key. It also contains any number of ACL entries that are signed by the Clavis key. It is believed that the most common setup would be to have the Clavis key contained within the machine keyring. Enabling the Clavis LSM during boot is accomplished by passing in the asymmetric key id for the Clavis key within a new "clavis=" boot param. The asymmetric key id must match one already contained within any of the system keyrings. If a match is found, a link is created into the new .clavis keyring. This Clavis key shall be used as the root of trust for any keyring ACL updates afterwards. On UEFI systems the "clavis" boot param is mirrored into a new UEFI variable within the EFI stub code. This variable will persist until the next reboot. This same type of functionality is done within shim. Since this variable is created before ExitBootServices (EBS) it will not have the NVRAM bit set, signifying it was created during the Boot Services phase. This is being used so the "clavis" boot param can not be changed via kexec, thereby preventing a pivot of the root of trust. As mentioned earlier, this LSM introduces a new .clavis keyring. Following boot, no new keys can be added to this keyring and only the key designated via the initial boot param may be used. If the clavis boot param was not used, the LSM can be enabled afterwards using the keyctl command. The end-user may add their Clavis key into the .clavis keyring and the Clavis LSM shall be enabled. The .clavis keyring also holds the access control list for system keys. A new key type called clavis_key_acl is being introduced. This contains the usage followed by the asymmetric key id. To be added to the clavis keyring, the clavis_key_acl must be S/MIME signed by the Clavis key. New ACL additions to the .clavis keyring may be added at any time. Currently this LSM does not require new changes or modifications to any user space tools. It also does not have a securityfs interface. Everything is done using the existing keyctl tool through the new .clavis keyring. The S/MIME signing can be done with a simple OpenSSL command. If additions or updates need to be added in the future, new ACL key types could be created. With this approach, maintainability should not be an issue in the future if missing items are identified. Clavis must be configured at build time with CONFIG_SECURITY_CLAVIS=y. The list of security modules enabled by default is set with CONFIG_LSM. The kernel configuration must contain CONFIG_LSM=[...],clavis with [...] as the list of other security modules for the running system. For setup and usage instructions, a clavis admin-guide has been included in Documentation/admin-guide/LSM/clavis.rst. Future enhancements to this LSM could include: 1. Subsystems that currently use system keys with VERIFYING_UNSPECIFIED_SIGNATURE could be updated with their specific usage type. For example, a usage type for IMA, BPF, etc could be added. 2. Having the ability to allow platform keys to be on par with all other system keys when using this LSM. This would be useful for a user that controls their entire UEFI SB DB key chain and doesn't want to use MOK keys. This could also potentially remove the need for the machine keyring all together. 3. Some of the Kconfig options around key usage and types could be deprecated. I would appreciate any feedback on this approach. Thanks. Changes in v3: Rebased to 6.12-rc3 Added Kunit test code Preload an ACL in the clavis keyring with the ephemeral module signing key Preload user defined ACL data into the clavis keyring with build time data Changes to the second patch recommended by Jarkko Reordered patches recommended by Mimi Documentation improvements recommended by Randy Changes in v2: Rebased to 6.10-rc1 Various cleanup in the first patch recommended by Jarkko Documentation improvements recommended by Randy Fixed lint warnings Other cleanup Eric Snowberg (13): certs: Remove CONFIG_INTEGRITY_PLATFORM_KEYRING check certs: Introduce ability to link to a system key clavis: Introduce a new system keyring called clavis keys: Add new verification type (VERIFYING_CLAVIS_SIGNATURE) clavis: Introduce a new key type called clavis_key_acl clavis: Populate clavis keyring acl with kernel module signature keys: Add ability to track intended usage of the public key clavis: Introduce new LSM called clavis clavis: Allow user to define acl at build time efi: Make clavis boot param persist across kexec clavis: Prevent boot param change during kexec clavis: Add function redirection for Kunit support clavis: Kunit support Documentation/admin-guide/LSM/clavis.rst | 191 ++++++ .../admin-guide/kernel-parameters.txt | 6 + MAINTAINERS | 7 + certs/.gitignore | 1 + certs/Makefile | 20 + certs/blacklist.c | 3 + certs/clavis_module_acl.c | 7 + certs/system_keyring.c | 36 +- crypto/asymmetric_keys/asymmetric_type.c | 1 + crypto/asymmetric_keys/pkcs7_trust.c | 20 + crypto/asymmetric_keys/pkcs7_verify.c | 5 + crypto/asymmetric_keys/signature.c | 4 + drivers/firmware/efi/Kconfig | 12 + drivers/firmware/efi/libstub/Makefile | 1 + drivers/firmware/efi/libstub/clavis.c | 33 + .../firmware/efi/libstub/efi-stub-helper.c | 2 + drivers/firmware/efi/libstub/efi-stub.c | 2 + drivers/firmware/efi/libstub/efistub.h | 8 + drivers/firmware/efi/libstub/x86-stub.c | 2 + include/crypto/pkcs7.h | 3 + include/crypto/public_key.h | 4 + include/keys/system_keyring.h | 7 +- include/linux/efi.h | 1 + include/linux/integrity.h | 8 + include/linux/lsm_count.h | 8 +- include/linux/lsm_hook_defs.h | 2 + include/linux/security.h | 7 + include/linux/verification.h | 2 + include/uapi/linux/lsm.h | 1 + security/Kconfig | 11 +- security/Makefile | 1 + security/clavis/.gitignore | 2 + security/clavis/.kunitconfig | 4 + security/clavis/Kconfig | 37 ++ security/clavis/Makefile | 156 +++++ security/clavis/clavis.c | 26 + security/clavis/clavis.h | 62 ++ security/clavis/clavis_builtin_acl.c | 7 + security/clavis/clavis_efi.c | 50 ++ security/clavis/clavis_keyring.c | 426 +++++++++++++ security/clavis/clavis_test.c | 566 ++++++++++++++++++ security/integrity/iint.c | 2 + security/security.c | 13 + .../selftests/lsm/lsm_list_modules_test.c | 3 + 44 files changed, 1757 insertions(+), 13 deletions(-) create mode 100644 Documentation/admin-guide/LSM/clavis.rst create mode 100644 certs/clavis_module_acl.c create mode 100644 drivers/firmware/efi/libstub/clavis.c create mode 100644 security/clavis/.gitignore create mode 100644 security/clavis/.kunitconfig create mode 100644 security/clavis/Kconfig create mode 100644 security/clavis/Makefile create mode 100644 security/clavis/clavis.c create mode 100644 security/clavis/clavis.h create mode 100644 security/clavis/clavis_builtin_acl.c create mode 100644 security/clavis/clavis_efi.c create mode 100644 security/clavis/clavis_keyring.c create mode 100644 security/clavis/clavis_test.c base-commit: 8e929cb546ee42c9a61d24fae60605e9e3192354 -- 2.45.0