diff mbox series

[4/4] integrity: CA enforcement in machine keyring

Message ID 20220301173651.3435350-5-eric.snowberg@oracle.com (mailing list archive)
State Not Applicable
Delegated to: Herbert Xu
Headers show
Series Add CA enforcement in the machine keyring | expand

Commit Message

Eric Snowberg March 1, 2022, 5:36 p.m. UTC
When INTEGRITY_MACHINE_KEYRING is set, all Machine Owner Keys (MOK)
are loaded into the machine keyring.  Add a new
INTEGRITY_MACHINE_KEYRING_CA_ENFORCED option where only MOK CA keys are
added.  

Set the restriction check to restrict_link_by_ca.  This will only allow 
CA keys into the machine keyring. Unlike when INTEGRITY_MACHINE_KEYRING
is enabled, IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY may
also be enabled, allowing IMA to use keys in the machine keyring as
another trust anchor.

Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
 certs/system_keyring.c                        |  9 +++++---
 include/keys/system_keyring.h                 |  3 ++-
 security/integrity/Kconfig                    | 21 +++++++++++++++++++
 security/integrity/Makefile                   |  1 +
 security/integrity/digsig.c                   | 14 ++++++++++---
 security/integrity/integrity.h                |  3 ++-
 .../platform_certs/keyring_handler.c          |  4 +++-
 7 files changed, 46 insertions(+), 9 deletions(-)

Comments

Stefan Berger March 4, 2022, 11:19 p.m. UTC | #1
On 3/1/22 12:36, Eric Snowberg wrote:
> When INTEGRITY_MACHINE_KEYRING is set, all Machine Owner Keys (MOK)
> are loaded into the machine keyring.  Add a new
> INTEGRITY_MACHINE_KEYRING_CA_ENFORCED option where only MOK CA keys are
> added.
>
> Set the restriction check to restrict_link_by_ca.  This will only allow
> CA keys into the machine keyring. Unlike when INTEGRITY_MACHINE_KEYRING
> is enabled, IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY may
> also be enabled, allowing IMA to use keys in the machine keyring as
> another trust anchor.

I tried to test this but could only do it by disabling the 
MokListTrustedRT variable check and then also the check for secure boot. 
It did load the expected keys onto the .machine keyring, enforcing the 
x509 indicating a self-signed CA if the compile time option 
CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED=y was set, loading all keys 
in the case of CONFIG_INTEGRITY_MACHINE_KEYRING=y.

I tried with this branch here from mokutils 
https://github.com/esnowberg/mokutil/tree/trust-mok but this seems to 
create an EFI variable with a different name. I guess this is the wrong 
branch?

    Stefan

> Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
> ---
>   certs/system_keyring.c                        |  9 +++++---
>   include/keys/system_keyring.h                 |  3 ++-
>   security/integrity/Kconfig                    | 21 +++++++++++++++++++
>   security/integrity/Makefile                   |  1 +
>   security/integrity/digsig.c                   | 14 ++++++++++---
>   security/integrity/integrity.h                |  3 ++-
>   .../platform_certs/keyring_handler.c          |  4 +++-
>   7 files changed, 46 insertions(+), 9 deletions(-)
>
> diff --git a/certs/system_keyring.c b/certs/system_keyring.c
> index 05b66ce9d1c9..0811b44cf3bf 100644
> --- a/certs/system_keyring.c
> +++ b/certs/system_keyring.c
> @@ -22,7 +22,8 @@ static struct key *builtin_trusted_keys;
>   #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
>   static struct key *secondary_trusted_keys;
>   #endif
> -#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
> +#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
> +    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
>   static struct key *machine_trusted_keys;
>   #endif
>   #ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
> @@ -89,7 +90,8 @@ static __init struct key_restriction *get_builtin_and_secondary_restriction(void
>   	if (!restriction)
>   		panic("Can't allocate secondary trusted keyring restriction\n");
>   
> -	if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING))
> +	if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) ||
> +	    IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED))
>   		restriction->check = restrict_link_by_builtin_secondary_and_machine;
>   	else
>   		restriction->check = restrict_link_by_builtin_and_secondary_trusted;
> @@ -97,7 +99,8 @@ static __init struct key_restriction *get_builtin_and_secondary_restriction(void
>   	return restriction;
>   }
>   #endif
> -#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
> +#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
> +    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
>   void __init set_machine_trusted_keys(struct key *keyring)
>   {
>   	machine_trusted_keys = keyring;
> diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
> index 91e080efb918..e4a6574bbcb6 100644
> --- a/include/keys/system_keyring.h
> +++ b/include/keys/system_keyring.h
> @@ -45,7 +45,8 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
>   #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
>   #endif
>   
> -#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
> +#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
> +    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
>   extern int restrict_link_by_builtin_secondary_and_machine(
>   	struct key *dest_keyring,
>   	const struct key_type *type,
> diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
> index 599429f99f99..14c927eea5ee 100644
> --- a/security/integrity/Kconfig
> +++ b/security/integrity/Kconfig
> @@ -62,6 +62,14 @@ config INTEGRITY_PLATFORM_KEYRING
>            provided by the platform for verifying the kexec'ed kerned image
>            and, possibly, the initramfs signature.
>   
> +
> +choice
> +	prompt "Machine keyring"
> +	default INTEGRITY_MACHINE_NONE
> +
> +config INTEGRITY_MACHINE_NONE
> +	bool "Do not enable the Machine Owner Keyring"
> +
>   config INTEGRITY_MACHINE_KEYRING
>   	bool "Provide a keyring to which Machine Owner Keys may be added"
>   	depends on SECONDARY_TRUSTED_KEYRING
> @@ -75,6 +83,19 @@ config INTEGRITY_MACHINE_KEYRING
>   	 in the platform keyring, keys contained in the .machine keyring will
>   	 be trusted within the kernel.
>   
> +config INTEGRITY_MACHINE_KEYRING_CA_ENFORCED
> +	bool "Provide a keyring to which Machine Owner CA Keys may be added"
> +	depends on SECONDARY_TRUSTED_KEYRING
> +	depends on INTEGRITY_ASYMMETRIC_KEYS
> +	depends on SYSTEM_BLACKLIST_KEYRING
> +	depends on LOAD_UEFI_KEYS
> +	help
> +	 If set, provide a keyring to which CA Machine Owner Keys (MOK) may
> +	 be added. This keyring shall contain just CA MOK keys.  Unlike keys
> +	 in the platform keyring, keys contained in the .machine keyring will
> +	 be trusted within the kernel.
> +endchoice
> +
>   config LOAD_UEFI_KEYS
>          depends on INTEGRITY_PLATFORM_KEYRING
>          depends on EFI
> diff --git a/security/integrity/Makefile b/security/integrity/Makefile
> index d0ffe37dc1d6..370ee63774c3 100644
> --- a/security/integrity/Makefile
> +++ b/security/integrity/Makefile
> @@ -11,6 +11,7 @@ integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
>   integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
>   integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o
>   integrity-$(CONFIG_INTEGRITY_MACHINE_KEYRING) += platform_certs/machine_keyring.o
> +integrity-$(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED) += platform_certs/machine_keyring.o
>   integrity-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/efi_parser.o \
>   				      platform_certs/load_uefi.o \
>   				      platform_certs/keyring_handler.o
> diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
> index c8c8a4a4e7a0..041edd9744db 100644
> --- a/security/integrity/digsig.c
> +++ b/security/integrity/digsig.c
> @@ -34,7 +34,11 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
>   };
>   
>   #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
> +#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED
> +#define restrict_link_to_ima restrict_link_by_builtin_secondary_and_machine
> +#else
>   #define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted
> +#endif
>   #else
>   #define restrict_link_to_ima restrict_link_by_builtin_trusted
>   #endif
> @@ -130,19 +134,23 @@ int __init integrity_init_keyring(const unsigned int id)
>   		| KEY_USR_READ | KEY_USR_SEARCH;
>   
>   	if (id == INTEGRITY_KEYRING_PLATFORM ||
> -	    id == INTEGRITY_KEYRING_MACHINE) {
> +	   (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING))) {
>   		restriction = NULL;
>   		goto out;
>   	}
>   
> -	if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING))
> +	if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING) &&
> +	    id != INTEGRITY_KEYRING_MACHINE)
>   		return 0;
>   
>   	restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
>   	if (!restriction)
>   		return -ENOMEM;
>   
> -	restriction->check = restrict_link_to_ima;
> +	if (id == INTEGRITY_KEYRING_MACHINE)
> +		restriction->check = restrict_link_by_ca;
> +	else
> +		restriction->check = restrict_link_to_ima;
>   
>   	/*
>   	 * MOK keys can only be added through a read-only runtime services
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index 2e214c761158..ca4d72fbd045 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -285,7 +285,8 @@ static inline void __init add_to_platform_keyring(const char *source,
>   }
>   #endif
>   
> -#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
> +#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
> +    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
>   void __init add_to_machine_keyring(const char *source, const void *data, size_t len);
>   bool __init trust_moklist(void);
>   #else
> diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
> index a2464f3e66cc..9c456ad0ab67 100644
> --- a/security/integrity/platform_certs/keyring_handler.c
> +++ b/security/integrity/platform_certs/keyring_handler.c
> @@ -61,7 +61,9 @@ __init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type)
>   __init efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type)
>   {
>   	if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) {
> -		if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) && trust_moklist())
> +		if ((IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) ||
> +		     IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)) &&
> +		     trust_moklist())
>   			return add_to_machine_keyring;
>   		else
>   			return add_to_platform_keyring;
Eric Snowberg March 7, 2022, 6:13 p.m. UTC | #2
> On Mar 4, 2022, at 4:19 PM, Stefan Berger <stefanb@linux.ibm.com> wrote:
> 
> 
> On 3/1/22 12:36, Eric Snowberg wrote:
>> When INTEGRITY_MACHINE_KEYRING is set, all Machine Owner Keys (MOK)
>> are loaded into the machine keyring.  Add a new
>> INTEGRITY_MACHINE_KEYRING_CA_ENFORCED option where only MOK CA keys are
>> added.
>> 
>> Set the restriction check to restrict_link_by_ca.  This will only allow
>> CA keys into the machine keyring. Unlike when INTEGRITY_MACHINE_KEYRING
>> is enabled, IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY may
>> also be enabled, allowing IMA to use keys in the machine keyring as
>> another trust anchor.
> 
> I tried to test this but could only do it by disabling the MokListTrustedRT variable check and then also the check for secure boot. It did load the expected keys onto the .machine keyring, enforcing the x509 indicating a self-signed CA if the compile time option CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED=y was set, loading all keys in the case of CONFIG_INTEGRITY_MACHINE_KEYRING=y.
> 
> I tried with this branch here from mokutils https://github.com/esnowberg/mokutil/tree/trust-mok but this seems to create an EFI variable with a different name. I guess this is the wrong branch?

Thanks for testing.  During the shim review, Peter requested an EFI variable name
change. This did not impact anything in the kernel.  However it did impact mokutil. 
The necessary mokutil changes are available in this pull request:

https://github.com/lcp/mokutil/pull/49
Stefan Berger March 7, 2022, 6:36 p.m. UTC | #3
On 3/7/22 13:13, Eric Snowberg wrote:
> 
> 
>> On Mar 4, 2022, at 4:19 PM, Stefan Berger <stefanb@linux.ibm.com> wrote:
>>
>>
>> On 3/1/22 12:36, Eric Snowberg wrote:
>>> When INTEGRITY_MACHINE_KEYRING is set, all Machine Owner Keys (MOK)
>>> are loaded into the machine keyring.  Add a new
>>> INTEGRITY_MACHINE_KEYRING_CA_ENFORCED option where only MOK CA keys are
>>> added.
>>>
>>> Set the restriction check to restrict_link_by_ca.  This will only allow
>>> CA keys into the machine keyring. Unlike when INTEGRITY_MACHINE_KEYRING
>>> is enabled, IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY may
>>> also be enabled, allowing IMA to use keys in the machine keyring as
>>> another trust anchor.
>>
>> I tried to test this but could only do it by disabling the MokListTrustedRT variable check and then also the check for secure boot. It did load the expected keys onto the .machine keyring, enforcing the x509 indicating a self-signed CA if the compile time option CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED=y was set, loading all keys in the case of CONFIG_INTEGRITY_MACHINE_KEYRING=y.
>>
>> I tried with this branch here from mokutils https://github.com/esnowberg/mokutil/tree/trust-mok but this seems to create an EFI variable with a different name. I guess this is the wrong branch?
> 
> Thanks for testing.  During the shim review, Peter requested an EFI variable name
> change. This did not impact anything in the kernel.  However it did impact mokutil.
> The necessary mokutil changes are available in this pull request:
> 
> https://github.com/lcp/mokutil/pull/49
> 

The following is in Jarkko's tree:

https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git/commit/?id=4d83e5144e224b90f6589d11b5fecde33c0dd211


+
+/*
+ * Try to load the MokListTrustedRT MOK variable to see if we should trust
+ * the MOK keys within the kernel. It is not an error if this variable
+ * does not exist.  If it does not exist, MOK keys should not be trusted
+ * within the machine keyring.
+ */
+static __init bool uefi_check_trust_mok_keys(void)
+{
+	struct efi_mokvar_table_entry *mokvar_entry;
+
+	mokvar_entry = efi_mokvar_entry_find("MokListTrustedRT");
+
+	if (mokvar_entry)
+		return true;
+
+	return false;
+}

I don't think this works  with your mokutil PR:

static int
trust_mok_keys()
{
	return set_toggle("MokListTrustedNew", 0);
}

 From what I saw, MokListTrustedRT searches for a mok-variable entry in 
the MOK-specific directory in sysfs while MokListTrustedNew creates one 
in the EFI dir...

     Stefan
Eric Snowberg March 7, 2022, 6:48 p.m. UTC | #4
> On Mar 7, 2022, at 11:36 AM, Stefan Berger <stefanb@linux.ibm.com> wrote:
> 
> 
> 
> On 3/7/22 13:13, Eric Snowberg wrote:
>>> On Mar 4, 2022, at 4:19 PM, Stefan Berger <stefanb@linux.ibm.com> wrote:
>>> 
>>> 
>>> On 3/1/22 12:36, Eric Snowberg wrote:
>>>> When INTEGRITY_MACHINE_KEYRING is set, all Machine Owner Keys (MOK)
>>>> are loaded into the machine keyring.  Add a new
>>>> INTEGRITY_MACHINE_KEYRING_CA_ENFORCED option where only MOK CA keys are
>>>> added.
>>>> 
>>>> Set the restriction check to restrict_link_by_ca.  This will only allow
>>>> CA keys into the machine keyring. Unlike when INTEGRITY_MACHINE_KEYRING
>>>> is enabled, IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY may
>>>> also be enabled, allowing IMA to use keys in the machine keyring as
>>>> another trust anchor.
>>> 
>>> I tried to test this but could only do it by disabling the MokListTrustedRT variable check and then also the check for secure boot. It did load the expected keys onto the .machine keyring, enforcing the x509 indicating a self-signed CA if the compile time option CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED=y was set, loading all keys in the case of CONFIG_INTEGRITY_MACHINE_KEYRING=y.
>>> 
>>> I tried with this branch here from mokutils https://github.com/esnowberg/mokutil/tree/trust-mok but this seems to create an EFI variable with a different name. I guess this is the wrong branch?
>> Thanks for testing.  During the shim review, Peter requested an EFI variable name
>> change. This did not impact anything in the kernel.  However it did impact mokutil.
>> The necessary mokutil changes are available in this pull request:
>> https://github.com/lcp/mokutil/pull/49
> 
> The following is in Jarkko's tree:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git/commit/?id=4d83e5144e224b90f6589d11b5fecde33c0dd211
> 
> 
> +
> +/*
> + * Try to load the MokListTrustedRT MOK variable to see if we should trust
> + * the MOK keys within the kernel. It is not an error if this variable
> + * does not exist.  If it does not exist, MOK keys should not be trusted
> + * within the machine keyring.
> + */
> +static __init bool uefi_check_trust_mok_keys(void)
> +{
> +	struct efi_mokvar_table_entry *mokvar_entry;
> +
> +	mokvar_entry = efi_mokvar_entry_find("MokListTrustedRT");
> +
> +	if (mokvar_entry)
> +		return true;
> +
> +	return false;
> +}
> 
> I don't think this works  with your mokutil PR:
> 
> static int
> trust_mok_keys()
> {
> 	return set_toggle("MokListTrustedNew", 0);
> }
> 
> From what I saw, MokListTrustedRT searches for a mok-variable entry in the MOK-specific directory in sysfs while MokListTrustedNew creates one in the EFI dir…

MokListTrustedNew is set by mokutil.  The variable is then used by MokManager.  
When shim boots and sees the variable is set, it loads MokManager instead of grub.  
The MokManager then asks the user if they want to make the change.   If the user 
accepts the change, shim stores a new boot services variable and the MokListTrustedNew 
variable is deleted. Afterwards the machine is rebooted, shim creates the 
MokListTrustedRT based on the boot services variable previously set.
diff mbox series

Patch

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 05b66ce9d1c9..0811b44cf3bf 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -22,7 +22,8 @@  static struct key *builtin_trusted_keys;
 #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
 static struct key *secondary_trusted_keys;
 #endif
-#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
+#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
+    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
 static struct key *machine_trusted_keys;
 #endif
 #ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
@@ -89,7 +90,8 @@  static __init struct key_restriction *get_builtin_and_secondary_restriction(void
 	if (!restriction)
 		panic("Can't allocate secondary trusted keyring restriction\n");
 
-	if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING))
+	if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) ||
+	    IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED))
 		restriction->check = restrict_link_by_builtin_secondary_and_machine;
 	else
 		restriction->check = restrict_link_by_builtin_and_secondary_trusted;
@@ -97,7 +99,8 @@  static __init struct key_restriction *get_builtin_and_secondary_restriction(void
 	return restriction;
 }
 #endif
-#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
+#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
+    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
 void __init set_machine_trusted_keys(struct key *keyring)
 {
 	machine_trusted_keys = keyring;
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 91e080efb918..e4a6574bbcb6 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -45,7 +45,8 @@  extern int restrict_link_by_builtin_and_secondary_trusted(
 #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
 #endif
 
-#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
+#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
+    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
 extern int restrict_link_by_builtin_secondary_and_machine(
 	struct key *dest_keyring,
 	const struct key_type *type,
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 599429f99f99..14c927eea5ee 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -62,6 +62,14 @@  config INTEGRITY_PLATFORM_KEYRING
          provided by the platform for verifying the kexec'ed kerned image
          and, possibly, the initramfs signature.
 
+
+choice
+	prompt "Machine keyring"
+	default INTEGRITY_MACHINE_NONE
+
+config INTEGRITY_MACHINE_NONE
+	bool "Do not enable the Machine Owner Keyring"
+
 config INTEGRITY_MACHINE_KEYRING
 	bool "Provide a keyring to which Machine Owner Keys may be added"
 	depends on SECONDARY_TRUSTED_KEYRING
@@ -75,6 +83,19 @@  config INTEGRITY_MACHINE_KEYRING
 	 in the platform keyring, keys contained in the .machine keyring will
 	 be trusted within the kernel.
 
+config INTEGRITY_MACHINE_KEYRING_CA_ENFORCED
+	bool "Provide a keyring to which Machine Owner CA Keys may be added"
+	depends on SECONDARY_TRUSTED_KEYRING
+	depends on INTEGRITY_ASYMMETRIC_KEYS
+	depends on SYSTEM_BLACKLIST_KEYRING
+	depends on LOAD_UEFI_KEYS
+	help
+	 If set, provide a keyring to which CA Machine Owner Keys (MOK) may
+	 be added. This keyring shall contain just CA MOK keys.  Unlike keys
+	 in the platform keyring, keys contained in the .machine keyring will
+	 be trusted within the kernel.
+endchoice
+
 config LOAD_UEFI_KEYS
        depends on INTEGRITY_PLATFORM_KEYRING
        depends on EFI
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index d0ffe37dc1d6..370ee63774c3 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -11,6 +11,7 @@  integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
 integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
 integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o
 integrity-$(CONFIG_INTEGRITY_MACHINE_KEYRING) += platform_certs/machine_keyring.o
+integrity-$(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED) += platform_certs/machine_keyring.o
 integrity-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/efi_parser.o \
 				      platform_certs/load_uefi.o \
 				      platform_certs/keyring_handler.o
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index c8c8a4a4e7a0..041edd9744db 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -34,7 +34,11 @@  static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
 };
 
 #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
+#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED
+#define restrict_link_to_ima restrict_link_by_builtin_secondary_and_machine
+#else
 #define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted
+#endif
 #else
 #define restrict_link_to_ima restrict_link_by_builtin_trusted
 #endif
@@ -130,19 +134,23 @@  int __init integrity_init_keyring(const unsigned int id)
 		| KEY_USR_READ | KEY_USR_SEARCH;
 
 	if (id == INTEGRITY_KEYRING_PLATFORM ||
-	    id == INTEGRITY_KEYRING_MACHINE) {
+	   (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING))) {
 		restriction = NULL;
 		goto out;
 	}
 
-	if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING))
+	if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING) &&
+	    id != INTEGRITY_KEYRING_MACHINE)
 		return 0;
 
 	restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
 	if (!restriction)
 		return -ENOMEM;
 
-	restriction->check = restrict_link_to_ima;
+	if (id == INTEGRITY_KEYRING_MACHINE)
+		restriction->check = restrict_link_by_ca;
+	else
+		restriction->check = restrict_link_to_ima;
 
 	/*
 	 * MOK keys can only be added through a read-only runtime services
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 2e214c761158..ca4d72fbd045 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -285,7 +285,8 @@  static inline void __init add_to_platform_keyring(const char *source,
 }
 #endif
 
-#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
+#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING) || \
+    defined(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)
 void __init add_to_machine_keyring(const char *source, const void *data, size_t len);
 bool __init trust_moklist(void);
 #else
diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
index a2464f3e66cc..9c456ad0ab67 100644
--- a/security/integrity/platform_certs/keyring_handler.c
+++ b/security/integrity/platform_certs/keyring_handler.c
@@ -61,7 +61,9 @@  __init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type)
 __init efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type)
 {
 	if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) {
-		if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) && trust_moklist())
+		if ((IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) ||
+		     IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING_CA_ENFORCED)) &&
+		     trust_moklist())
 			return add_to_machine_keyring;
 		else
 			return add_to_platform_keyring;