diff mbox series

[v4] certs: Add EFI_CERT_X509_GUID support for dbx entries

Message ID 20200916004927.64276-1-eric.snowberg@oracle.com (mailing list archive)
State Not Applicable
Delegated to: Herbert Xu
Headers show
Series [v4] certs: Add EFI_CERT_X509_GUID support for dbx entries | expand

Commit Message

Eric Snowberg Sept. 16, 2020, 12:49 a.m. UTC
The Secure Boot Forbidden Signature Database, dbx, contains a list of now
revoked signatures and keys previously approved to boot with UEFI Secure
Boot enabled.  The dbx is capable of containing any number of
EFI_CERT_X509_SHA256_GUID, EFI_CERT_SHA256_GUID, and EFI_CERT_X509_GUID
entries.

Currently when EFI_CERT_X509_GUID are contained in the dbx, the entries are
skipped.

Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
is found, it is added as an asymmetrical key to the .blacklist keyring.
Anytime the .platform keyring is used, the keys in the .blacklist keyring
are referenced, if a matching key is found, the key will be rejected.

Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
v4:
Remove unneeded symbol export found by Jarkko Sakkinen

v3:
Fixed an issue when CONFIG_PKCS7_MESSAGE_PARSER is not builtin and defined
as a module instead, pointed out by Randy Dunlap

v2: 
Fixed build issue reported by kernel test robot <lkp@intel.com>
Commit message update (suggested by Jarkko Sakkinen)
---
 certs/blacklist.c                             | 32 +++++++++++++++++++
 certs/blacklist.h                             | 12 +++++++
 certs/system_keyring.c                        |  6 ++++
 include/keys/system_keyring.h                 | 11 +++++++
 .../platform_certs/keyring_handler.c          | 11 +++++++
 5 files changed, 72 insertions(+)

Comments

Jarkko Sakkinen Sept. 16, 2020, 6:09 p.m. UTC | #1
On Tue, Sep 15, 2020 at 08:49:27PM -0400, Eric Snowberg wrote:
> The Secure Boot Forbidden Signature Database, dbx, contains a list of now
> revoked signatures and keys previously approved to boot with UEFI Secure
> Boot enabled.  The dbx is capable of containing any number of
> EFI_CERT_X509_SHA256_GUID, EFI_CERT_SHA256_GUID, and EFI_CERT_X509_GUID
> entries.
> 
> Currently when EFI_CERT_X509_GUID are contained in the dbx, the entries are
> skipped.
> 
> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
> is found, it is added as an asymmetrical key to the .blacklist keyring.
> Anytime the .platform keyring is used, the keys in the .blacklist keyring
> are referenced, if a matching key is found, the key will be rejected.
> 
> Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>

Looks good to me.

Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>

/Jarkko
David Howells Dec. 10, 2020, 9:49 a.m. UTC | #2
Eric Snowberg <eric.snowberg@oracle.com> wrote:

> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
> is found, it is added as an asymmetrical key to the .blacklist keyring.
> Anytime the .platform keyring is used, the keys in the .blacklist keyring
> are referenced, if a matching key is found, the key will be rejected.

Ummm...  Why this way and not as a blacklist key which takes up less space?
I'm guessing that you're using the key chain matching logic.  We really only
need to blacklist the key IDs.

Also, what should happen if a revocation cert rejected by the blacklist?

> +int mark_key_revocationlisted(const char *data, size_t size)

Hmmm...  The name looks wrong, but I can see the potential issue that kernel
keys can actually be marked revoked as a separate concept.  How about
add_key_to_revocation_list() and is_key_on_revocation_list().

David
Eric Snowberg Dec. 10, 2020, 6:56 p.m. UTC | #3
> On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
> 
> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> 
>> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
>> is found, it is added as an asymmetrical key to the .blacklist keyring.
>> Anytime the .platform keyring is used, the keys in the .blacklist keyring
>> are referenced, if a matching key is found, the key will be rejected.
> 
> Ummm...  Why this way and not as a blacklist key which takes up less space?
> I'm guessing that you're using the key chain matching logic.  We really only
> need to blacklist the key IDs.

I implemented it this way so that certs in the dbx would only impact 
the .platform keyring. I was under the impression we didn’t want to have 
Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
see it done, let me know and I’ll make the change.

> Also, what should happen if a revocation cert rejected by the blacklist?

I’m not sure I understand the question. How would it be rejected?

>> +int mark_key_revocationlisted(const char *data, size_t size)
> 
> Hmmm...  The name looks wrong, but I can see the potential issue that kernel
> keys can actually be marked revoked as a separate concept.  How about
> add_key_to_revocation_list() and is_key_on_revocation_list().

I'll update the names in the next version.

Thanks.
David Howells Jan. 12, 2021, 2:57 p.m. UTC | #4
Eric Snowberg <eric.snowberg@oracle.com> wrote:

> > On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
> > 
> > Eric Snowberg <eric.snowberg@oracle.com> wrote:
> > 
> >> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
> >> is found, it is added as an asymmetrical key to the .blacklist keyring.
> >> Anytime the .platform keyring is used, the keys in the .blacklist keyring
> >> are referenced, if a matching key is found, the key will be rejected.
> > 
> > Ummm...  Why this way and not as a blacklist key which takes up less space?
> > I'm guessing that you're using the key chain matching logic.  We really only
> > need to blacklist the key IDs.
> 
> I implemented it this way so that certs in the dbx would only impact 
> the .platform keyring. I was under the impression we didn’t want to have 
> Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
> itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
> secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
> see it done, let me know and I’ll make the change.

I wonder if that is that the right thing to do.  I guess this is a policy
decision and may depend on the particular user.

> > Also, what should happen if a revocation cert rejected by the blacklist?
> 
> I’m not sure I understand the question. How would it be rejected?

The SHA256 of a revocation cert being loaded could match an
already-blacklisted SHA256 sum, either compiled in or already loaded from
UEFI.

David
David Howells Jan. 12, 2021, 5:10 p.m. UTC | #5
How about the attached?  I've changed the function names to something that I
think reads better, but otherwise it's the same.

David
---
commit 8913866babb96fcfe452aac6042ca8862d4c0b53
Author: Eric Snowberg <eric.snowberg@oracle.com>
Date:   Tue Sep 15 20:49:27 2020 -0400

    certs: Add EFI_CERT_X509_GUID support for dbx entries
    
    The Secure Boot Forbidden Signature Database, dbx, contains a list of now
    revoked signatures and keys previously approved to boot with UEFI Secure
    Boot enabled.  The dbx is capable of containing any number of
    EFI_CERT_X509_SHA256_GUID, EFI_CERT_SHA256_GUID, and EFI_CERT_X509_GUID
    entries.
    
    Currently when EFI_CERT_X509_GUID are contained in the dbx, the entries are
    skipped.
    
    Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
    is found, it is added as an asymmetrical key to the .blacklist keyring.
    Anytime the .platform keyring is used, the keys in the .blacklist keyring
    are referenced, if a matching key is found, the key will be rejected.
    
    Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
    Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
    Signed-off-by: David Howells <dhowells@redhat.com>

diff --git a/certs/blacklist.c b/certs/blacklist.c
index 6514f9ebc943..a7f021878a4b 100644
--- a/certs/blacklist.c
+++ b/certs/blacklist.c
@@ -100,6 +100,38 @@ int mark_hash_blacklisted(const char *hash)
 	return 0;
 }
 
+int add_key_to_revocation_list(const char *data, size_t size)
+{
+	key_ref_t key;
+
+	key = key_create_or_update(make_key_ref(blacklist_keyring, true),
+				   "asymmetric",
+				   NULL,
+				   data,
+				   size,
+				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW),
+				   KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN);
+
+	if (IS_ERR(key)) {
+		pr_err("Problem with revocation key (%ld)\n", PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+
+	return 0;
+}
+
+int is_key_on_revocation_list(struct pkcs7_message *pkcs7)
+{
+	int ret;
+
+	ret = validate_trust(pkcs7, blacklist_keyring);
+
+	if (ret == 0)
+		return -EKEYREJECTED;
+
+	return -ENOKEY;
+}
+
 /**
  * is_hash_blacklisted - Determine if a hash is blacklisted
  * @hash: The hash to be checked as a binary blob
diff --git a/certs/blacklist.h b/certs/blacklist.h
index 1efd6fa0dc60..420bb7c86e07 100644
--- a/certs/blacklist.h
+++ b/certs/blacklist.h
@@ -1,3 +1,15 @@
 #include <linux/kernel.h>
+#include <linux/errno.h>
+#include <crypto/pkcs7.h>
 
 extern const char __initconst *const blacklist_hashes[];
+
+#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
+#define validate_trust pkcs7_validate_trust
+#else
+static inline int validate_trust(struct pkcs7_message *pkcs7,
+				 struct key *trust_keyring)
+{
+	return -ENOKEY;
+}
+#endif
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 798291177186..cc165b359ea3 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -241,6 +241,12 @@ int verify_pkcs7_message_sig(const void *data, size_t len,
 			pr_devel("PKCS#7 platform keyring is not available\n");
 			goto error;
 		}
+
+		ret = is_key_on_revocation_list(pkcs7);
+		if (ret != -ENOKEY) {
+			pr_devel("PKCS#7 platform key is on revocation list\n");
+			goto error;
+		}
 	}
 	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
 	if (ret < 0) {
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index fb8b07daa9d1..61f98739e8b1 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -31,11 +31,14 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
 #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
 #endif
 
+extern struct pkcs7_message *pkcs7;
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
 extern int mark_hash_blacklisted(const char *hash);
+extern int add_key_to_revocation_list(const char *data, size_t size);
 extern int is_hash_blacklisted(const u8 *hash, size_t hash_len,
 			       const char *type);
 extern int is_binary_blacklisted(const u8 *hash, size_t hash_len);
+extern int is_key_on_revocation_list(struct pkcs7_message *pkcs7);
 #else
 static inline int is_hash_blacklisted(const u8 *hash, size_t hash_len,
 				      const char *type)
@@ -47,6 +50,14 @@ static inline int is_binary_blacklisted(const u8 *hash, size_t hash_len)
 {
 	return 0;
 }
+static inline int add_key_to_revocation_list(const char *data, size_t size)
+{
+	return 0;
+}
+static inline int is_key_on_revocation_list(struct pkcs7_message *pkcs7)
+{
+	return -ENOKEY;
+}
 #endif
 
 #ifdef CONFIG_IMA_BLACKLIST_KEYRING
diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
index c5ba695c10e3..5604bd57c990 100644
--- a/security/integrity/platform_certs/keyring_handler.c
+++ b/security/integrity/platform_certs/keyring_handler.c
@@ -55,6 +55,15 @@ static __init void uefi_blacklist_binary(const char *source,
 	uefi_blacklist_hash(source, data, len, "bin:", 4);
 }
 
+/*
+ * Add an X509 cert to the revocation list.
+ */
+static __init void uefi_revocation_list_x509(const char *source,
+					     const void *data, size_t len)
+{
+	add_key_to_revocation_list(data, len);
+}
+
 /*
  * Return the appropriate handler for particular signature list types found in
  * the UEFI db and MokListRT tables.
@@ -76,5 +85,7 @@ __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type)
 		return uefi_blacklist_x509_tbs;
 	if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
 		return uefi_blacklist_binary;
+	if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
+		return uefi_revocation_list_x509;
 	return 0;
 }
Eric Snowberg Jan. 12, 2021, 7:13 p.m. UTC | #6
> On Jan 12, 2021, at 10:10 AM, David Howells <dhowells@redhat.com> wrote:
> 
> How about the attached?

This looks good to me.

> I've changed the function names to something that I
> think reads better, but otherwise it's the same.

I agree, the function name changes you made sound better.

We are starting to see platforms with KEK signed DBX updates containing
certs like this following boothole, so it would be great if we could get
something like this in.  I also had a follow on series that allowed these
certs to be compiled into the kernel.

https://lkml.org/lkml/2020/9/30/1301

I’d appreciate any feedback on that series as well.

Thanks

> David
> ---
> commit 8913866babb96fcfe452aac6042ca8862d4c0b53
> Author: Eric Snowberg <eric.snowberg@oracle.com>
> Date:   Tue Sep 15 20:49:27 2020 -0400
> 
>    certs: Add EFI_CERT_X509_GUID support for dbx entries
> 
>    The Secure Boot Forbidden Signature Database, dbx, contains a list of now
>    revoked signatures and keys previously approved to boot with UEFI Secure
>    Boot enabled.  The dbx is capable of containing any number of
>    EFI_CERT_X509_SHA256_GUID, EFI_CERT_SHA256_GUID, and EFI_CERT_X509_GUID
>    entries.
> 
>    Currently when EFI_CERT_X509_GUID are contained in the dbx, the entries are
>    skipped.
> 
>    Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
>    is found, it is added as an asymmetrical key to the .blacklist keyring.
>    Anytime the .platform keyring is used, the keys in the .blacklist keyring
>    are referenced, if a matching key is found, the key will be rejected.
> 
>    Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
>    Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
>    Signed-off-by: David Howells <dhowells@redhat.com>
> 
> diff --git a/certs/blacklist.c b/certs/blacklist.c
> index 6514f9ebc943..a7f021878a4b 100644
> --- a/certs/blacklist.c
> +++ b/certs/blacklist.c
> @@ -100,6 +100,38 @@ int mark_hash_blacklisted(const char *hash)
> 	return 0;
> }
> 
> +int add_key_to_revocation_list(const char *data, size_t size)
> +{
> +	key_ref_t key;
> +
> +	key = key_create_or_update(make_key_ref(blacklist_keyring, true),
> +				   "asymmetric",
> +				   NULL,
> +				   data,
> +				   size,
> +				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW),
> +				   KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN);
> +
> +	if (IS_ERR(key)) {
> +		pr_err("Problem with revocation key (%ld)\n", PTR_ERR(key));
> +		return PTR_ERR(key);
> +	}
> +
> +	return 0;
> +}
> +
> +int is_key_on_revocation_list(struct pkcs7_message *pkcs7)
> +{
> +	int ret;
> +
> +	ret = validate_trust(pkcs7, blacklist_keyring);
> +
> +	if (ret == 0)
> +		return -EKEYREJECTED;
> +
> +	return -ENOKEY;
> +}
> +
> /**
>  * is_hash_blacklisted - Determine if a hash is blacklisted
>  * @hash: The hash to be checked as a binary blob
> diff --git a/certs/blacklist.h b/certs/blacklist.h
> index 1efd6fa0dc60..420bb7c86e07 100644
> --- a/certs/blacklist.h
> +++ b/certs/blacklist.h
> @@ -1,3 +1,15 @@
> #include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <crypto/pkcs7.h>
> 
> extern const char __initconst *const blacklist_hashes[];
> +
> +#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
> +#define validate_trust pkcs7_validate_trust
> +#else
> +static inline int validate_trust(struct pkcs7_message *pkcs7,
> +				 struct key *trust_keyring)
> +{
> +	return -ENOKEY;
> +}
> +#endif
> diff --git a/certs/system_keyring.c b/certs/system_keyring.c
> index 798291177186..cc165b359ea3 100644
> --- a/certs/system_keyring.c
> +++ b/certs/system_keyring.c
> @@ -241,6 +241,12 @@ int verify_pkcs7_message_sig(const void *data, size_t len,
> 			pr_devel("PKCS#7 platform keyring is not available\n");
> 			goto error;
> 		}
> +
> +		ret = is_key_on_revocation_list(pkcs7);
> +		if (ret != -ENOKEY) {
> +			pr_devel("PKCS#7 platform key is on revocation list\n");
> +			goto error;
> +		}
> 	}
> 	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
> 	if (ret < 0) {
> diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
> index fb8b07daa9d1..61f98739e8b1 100644
> --- a/include/keys/system_keyring.h
> +++ b/include/keys/system_keyring.h
> @@ -31,11 +31,14 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
> #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
> #endif
> 
> +extern struct pkcs7_message *pkcs7;
> #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
> extern int mark_hash_blacklisted(const char *hash);
> +extern int add_key_to_revocation_list(const char *data, size_t size);
> extern int is_hash_blacklisted(const u8 *hash, size_t hash_len,
> 			       const char *type);
> extern int is_binary_blacklisted(const u8 *hash, size_t hash_len);
> +extern int is_key_on_revocation_list(struct pkcs7_message *pkcs7);
> #else
> static inline int is_hash_blacklisted(const u8 *hash, size_t hash_len,
> 				      const char *type)
> @@ -47,6 +50,14 @@ static inline int is_binary_blacklisted(const u8 *hash, size_t hash_len)
> {
> 	return 0;
> }
> +static inline int add_key_to_revocation_list(const char *data, size_t size)
> +{
> +	return 0;
> +}
> +static inline int is_key_on_revocation_list(struct pkcs7_message *pkcs7)
> +{
> +	return -ENOKEY;
> +}
> #endif
> 
> #ifdef CONFIG_IMA_BLACKLIST_KEYRING
> diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
> index c5ba695c10e3..5604bd57c990 100644
> --- a/security/integrity/platform_certs/keyring_handler.c
> +++ b/security/integrity/platform_certs/keyring_handler.c
> @@ -55,6 +55,15 @@ static __init void uefi_blacklist_binary(const char *source,
> 	uefi_blacklist_hash(source, data, len, "bin:", 4);
> }
> 
> +/*
> + * Add an X509 cert to the revocation list.
> + */
> +static __init void uefi_revocation_list_x509(const char *source,
> +					     const void *data, size_t len)
> +{
> +	add_key_to_revocation_list(data, len);
> +}
> +
> /*
>  * Return the appropriate handler for particular signature list types found in
>  * the UEFI db and MokListRT tables.
> @@ -76,5 +85,7 @@ __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type)
> 		return uefi_blacklist_x509_tbs;
> 	if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
> 		return uefi_blacklist_binary;
> +	if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
> +		return uefi_revocation_list_x509;
> 	return 0;
> }
>
Jarkko Sakkinen Jan. 13, 2021, 8:41 p.m. UTC | #7
On Tue, Jan 12, 2021 at 02:57:39PM +0000, David Howells wrote:
> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> 
> > > On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
> > > 
> > > Eric Snowberg <eric.snowberg@oracle.com> wrote:
> > > 
> > >> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
> > >> is found, it is added as an asymmetrical key to the .blacklist keyring.
> > >> Anytime the .platform keyring is used, the keys in the .blacklist keyring
> > >> are referenced, if a matching key is found, the key will be rejected.
> > > 
> > > Ummm...  Why this way and not as a blacklist key which takes up less space?
> > > I'm guessing that you're using the key chain matching logic.  We really only
> > > need to blacklist the key IDs.
> > 
> > I implemented it this way so that certs in the dbx would only impact 
> > the .platform keyring. I was under the impression we didn’t want to have 
> > Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
> > itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
> > secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
> > see it done, let me know and I’ll make the change.
> 
> I wonder if that is that the right thing to do.  I guess this is a policy
> decision and may depend on the particular user.

Why would you want to allow dbx entry in any keyring?

/Jarkko
Eric Snowberg Jan. 14, 2021, 12:11 a.m. UTC | #8
> On Jan 13, 2021, at 1:41 PM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote:
> 
> On Tue, Jan 12, 2021 at 02:57:39PM +0000, David Howells wrote:
>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
>> 
>>>> On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
>>>> 
>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
>>>> 
>>>>> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
>>>>> is found, it is added as an asymmetrical key to the .blacklist keyring.
>>>>> Anytime the .platform keyring is used, the keys in the .blacklist keyring
>>>>> are referenced, if a matching key is found, the key will be rejected.
>>>> 
>>>> Ummm...  Why this way and not as a blacklist key which takes up less space?
>>>> I'm guessing that you're using the key chain matching logic.  We really only
>>>> need to blacklist the key IDs.
>>> 
>>> I implemented it this way so that certs in the dbx would only impact 
>>> the .platform keyring. I was under the impression we didn’t want to have 
>>> Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
>>> itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
>>> secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
>>> see it done, let me know and I’ll make the change.
>> 
>> I wonder if that is that the right thing to do.  I guess this is a policy
>> decision and may depend on the particular user.
> 
> Why would you want to allow dbx entry in any keyring?

Today, DB and MOK certs go into the platform keyring.  These certs are only
referenced during kexec.  They can’t be used for other things like validating
kernel module signatures.  If we follow the same pattern, the DBX and MOKX entries
in the blacklist keyring should only impact kexec. 

Currently, Mickaël Salaün has another outstanding series to allow root to update 
the blacklist keyring.  I assume the use case for this is around certificates used 
within the kernel, for example revoking kernel module signatures.  The question I have
is, should another keyring be introduced?  One that carries DBX and MOKX, which just
correspond to certs/hashes in the platform keyring; this keyring would only be
referenced for kexec, just like the platform keyring is today. Then, the current
blacklist keyring would be used for everything internal to the kernel.
Jarkko Sakkinen Jan. 15, 2021, 9:15 a.m. UTC | #9
On Wed, Jan 13, 2021 at 05:11:10PM -0700, Eric Snowberg wrote:
> 
> > On Jan 13, 2021, at 1:41 PM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote:
> > 
> > On Tue, Jan 12, 2021 at 02:57:39PM +0000, David Howells wrote:
> >> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> >> 
> >>>> On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
> >>>> 
> >>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> >>>> 
> >>>>> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
> >>>>> is found, it is added as an asymmetrical key to the .blacklist keyring.
> >>>>> Anytime the .platform keyring is used, the keys in the .blacklist keyring
> >>>>> are referenced, if a matching key is found, the key will be rejected.
> >>>> 
> >>>> Ummm...  Why this way and not as a blacklist key which takes up less space?
> >>>> I'm guessing that you're using the key chain matching logic.  We really only
> >>>> need to blacklist the key IDs.
> >>> 
> >>> I implemented it this way so that certs in the dbx would only impact 
> >>> the .platform keyring. I was under the impression we didn’t want to have 
> >>> Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
> >>> itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
> >>> secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
> >>> see it done, let me know and I’ll make the change.
> >> 
> >> I wonder if that is that the right thing to do.  I guess this is a policy
> >> decision and may depend on the particular user.
> > 
> > Why would you want to allow dbx entry in any keyring?
> 
> Today, DB and MOK certs go into the platform keyring.  These certs are only
> referenced during kexec.  They can’t be used for other things like validating
> kernel module signatures.  If we follow the same pattern, the DBX and MOKX entries
> in the blacklist keyring should only impact kexec. 
> 
> Currently, Mickaël Salaün has another outstanding series to allow root to update 
> the blacklist keyring.  I assume the use case for this is around certificates used 
> within the kernel, for example revoking kernel module signatures.  The question I have
> is, should another keyring be introduced?  One that carries DBX and MOKX, which just
> correspond to certs/hashes in the platform keyring; this keyring would only be
> referenced for kexec, just like the platform keyring is today. Then, the current
> blacklist keyring would be used for everything internal to the kernel.

Right, I'm following actively that series.

Why couldn't user space drive this process and use that feature to do it?

/Jarkko
Eric Snowberg Jan. 15, 2021, 4:49 p.m. UTC | #10
> On Jan 15, 2021, at 2:15 AM, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> 
> On Wed, Jan 13, 2021 at 05:11:10PM -0700, Eric Snowberg wrote:
>> 
>>> On Jan 13, 2021, at 1:41 PM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote:
>>> 
>>> On Tue, Jan 12, 2021 at 02:57:39PM +0000, David Howells wrote:
>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
>>>> 
>>>>>> On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
>>>>>> 
>>>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
>>>>>> 
>>>>>>> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
>>>>>>> is found, it is added as an asymmetrical key to the .blacklist keyring.
>>>>>>> Anytime the .platform keyring is used, the keys in the .blacklist keyring
>>>>>>> are referenced, if a matching key is found, the key will be rejected.
>>>>>> 
>>>>>> Ummm...  Why this way and not as a blacklist key which takes up less space?
>>>>>> I'm guessing that you're using the key chain matching logic.  We really only
>>>>>> need to blacklist the key IDs.
>>>>> 
>>>>> I implemented it this way so that certs in the dbx would only impact 
>>>>> the .platform keyring. I was under the impression we didn’t want to have 
>>>>> Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
>>>>> itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
>>>>> secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
>>>>> see it done, let me know and I’ll make the change.
>>>> 
>>>> I wonder if that is that the right thing to do.  I guess this is a policy
>>>> decision and may depend on the particular user.
>>> 
>>> Why would you want to allow dbx entry in any keyring?
>> 
>> Today, DB and MOK certs go into the platform keyring.  These certs are only
>> referenced during kexec.  They can’t be used for other things like validating
>> kernel module signatures.  If we follow the same pattern, the DBX and MOKX entries
>> in the blacklist keyring should only impact kexec. 
>> 
>> Currently, Mickaël Salaün has another outstanding series to allow root to update 
>> the blacklist keyring.  I assume the use case for this is around certificates used 
>> within the kernel, for example revoking kernel module signatures.  The question I have
>> is, should another keyring be introduced?  One that carries DBX and MOKX, which just
>> correspond to certs/hashes in the platform keyring; this keyring would only be
>> referenced for kexec, just like the platform keyring is today. Then, the current
>> blacklist keyring would be used for everything internal to the kernel.
> 
> Right, I'm following actively that series.
> 
> Why couldn't user space drive this process and use that feature to do it?

I could see where the user would want to use both. With Mickaël Salaün’s
series, the blacklist keyring is updated immediately.  However it does
not survive a reboot.  With my patch, the blacklist keyring is updated
during boot, based on what is in the dbx. Neither approach needs a new 
kernel build.
James Bottomley Jan. 15, 2021, 5:21 p.m. UTC | #11
On Tue, 2020-09-15 at 20:49 -0400, Eric Snowberg wrote:
> The Secure Boot Forbidden Signature Database, dbx, contains a list of
> now revoked signatures and keys previously approved to boot with UEFI
> Secure Boot enabled.  The dbx is capable of containing any number of
> EFI_CERT_X509_SHA256_GUID, EFI_CERT_SHA256_GUID, and
> EFI_CERT_X509_GUID entries.
> 
> Currently when EFI_CERT_X509_GUID are contained in the dbx, the
> entries are skipped.
> 
> Add support for EFI_CERT_X509_GUID dbx entries. When a
> EFI_CERT_X509_GUID is found, it is added as an asymmetrical key to
> the .blacklist keyring. Anytime the .platform keyring is used, the
> keys in the .blacklist keyring are referenced, if a matching key is
> found, the key will be rejected.
> 
> Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>

If you're using shim, as most of our users are, you have no access to
dbx to blacklist certificates.  Plus our security envelope includes the
Mok variables, so you should also be paying attestion to MokListX (or
it's RT equivalent: MokListXRT).

If you add this to the patch, we get something that is mechanistically
complete and which also allows users to add certs to their Mok
blacklist.

James
Eric Snowberg Jan. 15, 2021, 11:01 p.m. UTC | #12
> On Jan 15, 2021, at 10:21 AM, James Bottomley <James.Bottomley@HansenPartnership.com> wrote:
> 
> On Tue, 2020-09-15 at 20:49 -0400, Eric Snowberg wrote:
>> The Secure Boot Forbidden Signature Database, dbx, contains a list of
>> now revoked signatures and keys previously approved to boot with UEFI
>> Secure Boot enabled.  The dbx is capable of containing any number of
>> EFI_CERT_X509_SHA256_GUID, EFI_CERT_SHA256_GUID, and
>> EFI_CERT_X509_GUID entries.
>> 
>> Currently when EFI_CERT_X509_GUID are contained in the dbx, the
>> entries are skipped.
>> 
>> Add support for EFI_CERT_X509_GUID dbx entries. When a
>> EFI_CERT_X509_GUID is found, it is added as an asymmetrical key to
>> the .blacklist keyring. Anytime the .platform keyring is used, the
>> keys in the .blacklist keyring are referenced, if a matching key is
>> found, the key will be rejected.
>> 
>> Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
> 
> If you're using shim, as most of our users are, you have no access to
> dbx to blacklist certificates.  Plus our security envelope includes the
> Mok variables, so you should also be paying attestion to MokListX (or
> it's RT equivalent: MokListXRT).
> 
> If you add this to the patch, we get something that is mechanistically
> complete and which also allows users to add certs to their Mok
> blacklist.

That make sense. I’ll work on a patch to add this ability.
Jarkko Sakkinen Jan. 20, 2021, 11:26 a.m. UTC | #13
On Fri, Jan 15, 2021 at 09:49:02AM -0700, Eric Snowberg wrote:
> 
> > On Jan 15, 2021, at 2:15 AM, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > 
> > On Wed, Jan 13, 2021 at 05:11:10PM -0700, Eric Snowberg wrote:
> >> 
> >>> On Jan 13, 2021, at 1:41 PM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote:
> >>> 
> >>> On Tue, Jan 12, 2021 at 02:57:39PM +0000, David Howells wrote:
> >>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> >>>> 
> >>>>>> On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
> >>>>>> 
> >>>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> >>>>>> 
> >>>>>>> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
> >>>>>>> is found, it is added as an asymmetrical key to the .blacklist keyring.
> >>>>>>> Anytime the .platform keyring is used, the keys in the .blacklist keyring
> >>>>>>> are referenced, if a matching key is found, the key will be rejected.
> >>>>>> 
> >>>>>> Ummm...  Why this way and not as a blacklist key which takes up less space?
> >>>>>> I'm guessing that you're using the key chain matching logic.  We really only
> >>>>>> need to blacklist the key IDs.
> >>>>> 
> >>>>> I implemented it this way so that certs in the dbx would only impact 
> >>>>> the .platform keyring. I was under the impression we didn’t want to have 
> >>>>> Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
> >>>>> itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
> >>>>> secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
> >>>>> see it done, let me know and I’ll make the change.
> >>>> 
> >>>> I wonder if that is that the right thing to do.  I guess this is a policy
> >>>> decision and may depend on the particular user.
> >>> 
> >>> Why would you want to allow dbx entry in any keyring?
> >> 
> >> Today, DB and MOK certs go into the platform keyring.  These certs are only
> >> referenced during kexec.  They can’t be used for other things like validating
> >> kernel module signatures.  If we follow the same pattern, the DBX and MOKX entries
> >> in the blacklist keyring should only impact kexec. 
> >> 
> >> Currently, Mickaël Salaün has another outstanding series to allow root to update 
> >> the blacklist keyring.  I assume the use case for this is around certificates used 
> >> within the kernel, for example revoking kernel module signatures.  The question I have
> >> is, should another keyring be introduced?  One that carries DBX and MOKX, which just
> >> correspond to certs/hashes in the platform keyring; this keyring would only be
> >> referenced for kexec, just like the platform keyring is today. Then, the current
> >> blacklist keyring would be used for everything internal to the kernel.
> > 
> > Right, I'm following actively that series.
> > 
> > Why couldn't user space drive this process and use that feature to do it?
> 
> I could see where the user would want to use both. With Mickaël Salaün’s
> series, the blacklist keyring is updated immediately.  However it does
> not survive a reboot.  With my patch, the blacklist keyring is updated
> during boot, based on what is in the dbx. Neither approach needs a new 
> kernel build.

I don't want to purposely challenge this, but why does it matter
that it doesn't survive the boot? I'm referring here to the golden
principle of kernel defining a mechanism, not policy. User space
can do the population however it wants to for every boot.

E.g. systemd service could do this.

What am I missing here?

/Jarkko
Eric Snowberg Jan. 20, 2021, 10:13 p.m. UTC | #14
> On Jan 20, 2021, at 4:26 AM, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> 
> On Fri, Jan 15, 2021 at 09:49:02AM -0700, Eric Snowberg wrote:
>> 
>>> On Jan 15, 2021, at 2:15 AM, Jarkko Sakkinen <jarkko@kernel.org> wrote:
>>> 
>>> On Wed, Jan 13, 2021 at 05:11:10PM -0700, Eric Snowberg wrote:
>>>> 
>>>>> On Jan 13, 2021, at 1:41 PM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote:
>>>>> 
>>>>> On Tue, Jan 12, 2021 at 02:57:39PM +0000, David Howells wrote:
>>>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
>>>>>> 
>>>>>>>> On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
>>>>>>>> 
>>>>>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
>>>>>>>> 
>>>>>>>>> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
>>>>>>>>> is found, it is added as an asymmetrical key to the .blacklist keyring.
>>>>>>>>> Anytime the .platform keyring is used, the keys in the .blacklist keyring
>>>>>>>>> are referenced, if a matching key is found, the key will be rejected.
>>>>>>>> 
>>>>>>>> Ummm...  Why this way and not as a blacklist key which takes up less space?
>>>>>>>> I'm guessing that you're using the key chain matching logic.  We really only
>>>>>>>> need to blacklist the key IDs.
>>>>>>> 
>>>>>>> I implemented it this way so that certs in the dbx would only impact 
>>>>>>> the .platform keyring. I was under the impression we didn’t want to have 
>>>>>>> Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
>>>>>>> itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
>>>>>>> secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
>>>>>>> see it done, let me know and I’ll make the change.
>>>>>> 
>>>>>> I wonder if that is that the right thing to do.  I guess this is a policy
>>>>>> decision and may depend on the particular user.
>>>>> 
>>>>> Why would you want to allow dbx entry in any keyring?
>>>> 
>>>> Today, DB and MOK certs go into the platform keyring.  These certs are only
>>>> referenced during kexec.  They can’t be used for other things like validating
>>>> kernel module signatures.  If we follow the same pattern, the DBX and MOKX entries
>>>> in the blacklist keyring should only impact kexec. 
>>>> 
>>>> Currently, Mickaël Salaün has another outstanding series to allow root to update 
>>>> the blacklist keyring.  I assume the use case for this is around certificates used 
>>>> within the kernel, for example revoking kernel module signatures.  The question I have
>>>> is, should another keyring be introduced?  One that carries DBX and MOKX, which just
>>>> correspond to certs/hashes in the platform keyring; this keyring would only be
>>>> referenced for kexec, just like the platform keyring is today. Then, the current
>>>> blacklist keyring would be used for everything internal to the kernel.
>>> 
>>> Right, I'm following actively that series.
>>> 
>>> Why couldn't user space drive this process and use that feature to do it?
>> 
>> I could see where the user would want to use both. With Mickaël Salaün’s
>> series, the blacklist keyring is updated immediately.  However it does
>> not survive a reboot.  With my patch, the blacklist keyring is updated
>> during boot, based on what is in the dbx. Neither approach needs a new 
>> kernel build.
> 
> I don't want to purposely challenge this, but why does it matter
> that it doesn't survive the boot? I'm referring here to the golden
> principle of kernel defining a mechanism, not policy. User space
> can do the population however it wants to for every boot.
> 
> E.g. systemd service could do this.
> 
> What am I missing here?

This change simply adds support for a missing type.  The kernel 
already supports cert and hash entries (EFI_CERT_X509_SHA256_GUID,
EFI_CERT_SHA256_GUID) that originate from the dbx and are loaded 
into the blacklist keyring during boot.  I’m not sure why a cert 
defined with EFI_CERT_X509_GUID should be handled in a different 
manner.

I suppose a user space tool could be created. But wouldn’t what is
currently done in the kernel in this area need to be removed?
Jarkko Sakkinen Jan. 21, 2021, 12:36 a.m. UTC | #15
On Wed, Jan 20, 2021 at 03:13:11PM -0700, Eric Snowberg wrote:
> 
> > On Jan 20, 2021, at 4:26 AM, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > 
> > On Fri, Jan 15, 2021 at 09:49:02AM -0700, Eric Snowberg wrote:
> >> 
> >>> On Jan 15, 2021, at 2:15 AM, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> >>> 
> >>> On Wed, Jan 13, 2021 at 05:11:10PM -0700, Eric Snowberg wrote:
> >>>> 
> >>>>> On Jan 13, 2021, at 1:41 PM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote:
> >>>>> 
> >>>>> On Tue, Jan 12, 2021 at 02:57:39PM +0000, David Howells wrote:
> >>>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> >>>>>> 
> >>>>>>>> On Dec 10, 2020, at 2:49 AM, David Howells <dhowells@redhat.com> wrote:
> >>>>>>>> 
> >>>>>>>> Eric Snowberg <eric.snowberg@oracle.com> wrote:
> >>>>>>>> 
> >>>>>>>>> Add support for EFI_CERT_X509_GUID dbx entries. When a EFI_CERT_X509_GUID
> >>>>>>>>> is found, it is added as an asymmetrical key to the .blacklist keyring.
> >>>>>>>>> Anytime the .platform keyring is used, the keys in the .blacklist keyring
> >>>>>>>>> are referenced, if a matching key is found, the key will be rejected.
> >>>>>>>> 
> >>>>>>>> Ummm...  Why this way and not as a blacklist key which takes up less space?
> >>>>>>>> I'm guessing that you're using the key chain matching logic.  We really only
> >>>>>>>> need to blacklist the key IDs.
> >>>>>>> 
> >>>>>>> I implemented it this way so that certs in the dbx would only impact 
> >>>>>>> the .platform keyring. I was under the impression we didn’t want to have 
> >>>>>>> Secure Boot UEFI db/dbx certs dictate keyring functionality within the kernel
> >>>>>>> itself. Meaning if we have a matching dbx cert in any other keyring (builtin,
> >>>>>>> secondary, ima, etc.), it would be allowed. If that is not how you’d like to 
> >>>>>>> see it done, let me know and I’ll make the change.
> >>>>>> 
> >>>>>> I wonder if that is that the right thing to do.  I guess this is a policy
> >>>>>> decision and may depend on the particular user.
> >>>>> 
> >>>>> Why would you want to allow dbx entry in any keyring?
> >>>> 
> >>>> Today, DB and MOK certs go into the platform keyring.  These certs are only
> >>>> referenced during kexec.  They can’t be used for other things like validating
> >>>> kernel module signatures.  If we follow the same pattern, the DBX and MOKX entries
> >>>> in the blacklist keyring should only impact kexec. 
> >>>> 
> >>>> Currently, Mickaël Salaün has another outstanding series to allow root to update 
> >>>> the blacklist keyring.  I assume the use case for this is around certificates used 
> >>>> within the kernel, for example revoking kernel module signatures.  The question I have
> >>>> is, should another keyring be introduced?  One that carries DBX and MOKX, which just
> >>>> correspond to certs/hashes in the platform keyring; this keyring would only be
> >>>> referenced for kexec, just like the platform keyring is today. Then, the current
> >>>> blacklist keyring would be used for everything internal to the kernel.
> >>> 
> >>> Right, I'm following actively that series.
> >>> 
> >>> Why couldn't user space drive this process and use that feature to do it?
> >> 
> >> I could see where the user would want to use both. With Mickaël Salaün’s
> >> series, the blacklist keyring is updated immediately.  However it does
> >> not survive a reboot.  With my patch, the blacklist keyring is updated
> >> during boot, based on what is in the dbx. Neither approach needs a new 
> >> kernel build.
> > 
> > I don't want to purposely challenge this, but why does it matter
> > that it doesn't survive the boot? I'm referring here to the golden
> > principle of kernel defining a mechanism, not policy. User space
> > can do the population however it wants to for every boot.
> > 
> > E.g. systemd service could do this.
> > 
> > What am I missing here?
> 
> This change simply adds support for a missing type.  The kernel 
> already supports cert and hash entries (EFI_CERT_X509_SHA256_GUID,
> EFI_CERT_SHA256_GUID) that originate from the dbx and are loaded 
> into the blacklist keyring during boot.  I’m not sure why a cert 
> defined with EFI_CERT_X509_GUID should be handled in a different 
> manner.
> 
> I suppose a user space tool could be created. But wouldn’t what is
> currently done in the kernel in this area need to be removed?

Right. I don't think this was a great idea in the first place to
do to the kernel but since it exists, I guess the patch does make
sense.

/Jarkko
David Howells Jan. 27, 2021, 11:46 a.m. UTC | #16
Jarkko Sakkinen <jarkko@kernel.org> wrote:

> > I suppose a user space tool could be created. But wouldn’t what is
> > currently done in the kernel in this area need to be removed?
> 
> Right. I don't think this was a great idea in the first place to
> do to the kernel but since it exists, I guess the patch does make
> sense.

This information needs to be loaded from the UEFI tables before the system
starts loading any kernel modules or running any programs (if we do
verification of such, which I think IMA can do).

David
Mimi Zohar Jan. 27, 2021, 2:03 p.m. UTC | #17
[Cc'ing linux-integrity]

On Wed, 2021-01-27 at 11:46 +0000, David Howells wrote:
> Jarkko Sakkinen <jarkko@kernel.org> wrote:
> 
> > > I suppose a user space tool could be created. But wouldn’t what is
> > > currently done in the kernel in this area need to be removed?
> > 
> > Right. I don't think this was a great idea in the first place to
> > do to the kernel but since it exists, I guess the patch does make
> > sense.
> 
> This information needs to be loaded from the UEFI tables before the system
> starts loading any kernel modules or running any programs (if we do
> verification of such, which I think IMA can do).

There needs to a clear distinction between the pre-boot and post-boot
keys.  UEFI has its own trust model, which should be limited to UEFI. 
The .platform keyring was upstreamed and limited to verifying the kexec
kernel image.   Any other usage of the .platform keyring keys is
abusing its intended purpose.

The cover letter says,   "Anytime the .platform keyring is used, the
keys in the .blacklist keyring are referenced, if a matching key is
found, the key will be rejected."   I don't have a problem with loading
the UEFI X509 dbx entries as long as its usage is limited to verifying
the kexec kernel image.

Mimi
Eric Snowberg Jan. 27, 2021, 3:41 p.m. UTC | #18
> On Jan 27, 2021, at 7:03 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
> 
> [Cc'ing linux-integrity]
> 
> On Wed, 2021-01-27 at 11:46 +0000, David Howells wrote:
>> Jarkko Sakkinen <jarkko@kernel.org> wrote:
>> 
>>>> I suppose a user space tool could be created. But wouldn’t what is
>>>> currently done in the kernel in this area need to be removed?
>>> 
>>> Right. I don't think this was a great idea in the first place to
>>> do to the kernel but since it exists, I guess the patch does make
>>> sense.
>> 
>> This information needs to be loaded from the UEFI tables before the system
>> starts loading any kernel modules or running any programs (if we do
>> verification of such, which I think IMA can do).
> 
> There needs to a clear distinction between the pre-boot and post-boot
> keys.  UEFI has its own trust model, which should be limited to UEFI. 
> The .platform keyring was upstreamed and limited to verifying the kexec
> kernel image.   Any other usage of the .platform keyring keys is
> abusing its intended purpose.
> 
> The cover letter says,   "Anytime the .platform keyring is used, the
> keys in the .blacklist keyring are referenced, if a matching key is
> found, the key will be rejected."   I don't have a problem with loading
> the UEFI X509 dbx entries as long as its usage is limited to verifying
> the kexec kernel image.

Correct, with my patch, when EFI_CERT_X509_GUID entries are found in the
dbx, they will only be used during kexec.  I believe the latest dbx file on 
uefi.org contains three of these entires.

Based on my understanding of why the platform keyring was introduced, 
I intentionally only used these for kexec.  I do question the current 
upstream mainline code though.  Currently, when EFI_CERT_X509_SHA256_GUID
or EFI_CERT_SHA256_GUID entries are found in the dbx, they are applied 
everywhere.  It seems like there should be a dbx revocation keyring 
equivalent to the current platform keyring that is only used for pre-boot. 

If that is a direction you would like to see this go in the future, let
me know, I’d be happy to work on it.
Nayna Jan. 28, 2021, 4:13 a.m. UTC | #19
On 1/27/21 10:41 AM, Eric Snowberg wrote:
>> On Jan 27, 2021, at 7:03 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
>>
>> [Cc'ing linux-integrity]
>>
>> On Wed, 2021-01-27 at 11:46 +0000, David Howells wrote:
>>> Jarkko Sakkinen <jarkko@kernel.org> wrote:
>>>
>>>>> I suppose a user space tool could be created. But wouldn’t what is
>>>>> currently done in the kernel in this area need to be removed?
>>>> Right. I don't think this was a great idea in the first place to
>>>> do to the kernel but since it exists, I guess the patch does make
>>>> sense.
>>> This information needs to be loaded from the UEFI tables before the system
>>> starts loading any kernel modules or running any programs (if we do
>>> verification of such, which I think IMA can do).
>> There needs to a clear distinction between the pre-boot and post-boot
>> keys.  UEFI has its own trust model, which should be limited to UEFI.
>> The .platform keyring was upstreamed and limited to verifying the kexec
>> kernel image.   Any other usage of the .platform keyring keys is
>> abusing its intended purpose.
>>
>> The cover letter says,   "Anytime the .platform keyring is used, the
>> keys in the .blacklist keyring are referenced, if a matching key is
>> found, the key will be rejected."   I don't have a problem with loading
>> the UEFI X509 dbx entries as long as its usage is limited to verifying
>> the kexec kernel image.
> Correct, with my patch, when EFI_CERT_X509_GUID entries are found in the
> dbx, they will only be used during kexec.  I believe the latest dbx file on
> uefi.org contains three of these entires.
>
> Based on my understanding of why the platform keyring was introduced,
> I intentionally only used these for kexec.  I do question the current
> upstream mainline code though.  Currently, when EFI_CERT_X509_SHA256_GUID
> or EFI_CERT_SHA256_GUID entries are found in the dbx, they are applied
> everywhere.  It seems like there should be a dbx revocation keyring
> equivalent to the current platform keyring that is only used for pre-boot.
>
> If that is a direction you would like to see this go in the future, let
> me know, I’d be happy to work on it.
>
Yes, as you said, currently blacklist entries from dbx for 
EFI_CERT_X509_SHA256_GUID or EFI_CERT_SHA256_GUID are applied 
everywhere, and does not satisfy the trust model for .platform keyring. 
We should fix this, but changing now might break some existing systems. 
Probably it should be discussed as separate thread from this patchset.

Thanks & Regards,

       - Nayna
Jarkko Sakkinen Jan. 29, 2021, 11:27 p.m. UTC | #20
On Wed, Jan 27, 2021 at 09:03:59AM -0500, Mimi Zohar wrote:
> [Cc'ing linux-integrity]
> 
> On Wed, 2021-01-27 at 11:46 +0000, David Howells wrote:
> > Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > 
> > > > I suppose a user space tool could be created. But wouldn’t what is
> > > > currently done in the kernel in this area need to be removed?
> > > 
> > > Right. I don't think this was a great idea in the first place to
> > > do to the kernel but since it exists, I guess the patch does make
> > > sense.
> > 
> > This information needs to be loaded from the UEFI tables before the system
> > starts loading any kernel modules or running any programs (if we do
> > verification of such, which I think IMA can do).
> 
> There needs to a clear distinction between the pre-boot and post-boot
> keys.  UEFI has its own trust model, which should be limited to UEFI. 
> The .platform keyring was upstreamed and limited to verifying the kexec
> kernel image.   Any other usage of the .platform keyring keys is
> abusing its intended purpose.
> 
> The cover letter says,   "Anytime the .platform keyring is used, the
> keys in the .blacklist keyring are referenced, if a matching key is
> found, the key will be rejected."   I don't have a problem with loading
> the UEFI X509 dbx entries as long as its usage is limited to verifying
> the kexec kernel image.
> 
> Mimi

Thanks Mimi, this is a valid argument. I agree.

/Jarkko
Jarkko Sakkinen Jan. 30, 2021, 10:24 a.m. UTC | #21
On Wed, Jan 27, 2021 at 08:41:29AM -0700, Eric Snowberg wrote:
> 
> > On Jan 27, 2021, at 7:03 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
> > 
> > [Cc'ing linux-integrity]
> > 
> > On Wed, 2021-01-27 at 11:46 +0000, David Howells wrote:
> >> Jarkko Sakkinen <jarkko@kernel.org> wrote:
> >> 
> >>>> I suppose a user space tool could be created. But wouldn’t what is
> >>>> currently done in the kernel in this area need to be removed?
> >>> 
> >>> Right. I don't think this was a great idea in the first place to
> >>> do to the kernel but since it exists, I guess the patch does make
> >>> sense.
> >> 
> >> This information needs to be loaded from the UEFI tables before the system
> >> starts loading any kernel modules or running any programs (if we do
> >> verification of such, which I think IMA can do).
> > 
> > There needs to a clear distinction between the pre-boot and post-boot
> > keys.  UEFI has its own trust model, which should be limited to UEFI. 
> > The .platform keyring was upstreamed and limited to verifying the kexec
> > kernel image.   Any other usage of the .platform keyring keys is
> > abusing its intended purpose.
> > 
> > The cover letter says,   "Anytime the .platform keyring is used, the
> > keys in the .blacklist keyring are referenced, if a matching key is
> > found, the key will be rejected."   I don't have a problem with loading
> > the UEFI X509 dbx entries as long as its usage is limited to verifying
> > the kexec kernel image.
> 
> Correct, with my patch, when EFI_CERT_X509_GUID entries are found in the
> dbx, they will only be used during kexec.  I believe the latest dbx file on 
> uefi.org contains three of these entires.
> 
> Based on my understanding of why the platform keyring was introduced, 
> I intentionally only used these for kexec.  I do question the current 
> upstream mainline code though.  Currently, when EFI_CERT_X509_SHA256_GUID
> or EFI_CERT_SHA256_GUID entries are found in the dbx, they are applied 
> everywhere.  It seems like there should be a dbx revocation keyring 
> equivalent to the current platform keyring that is only used for pre-boot. 
> 
> If that is a direction you would like to see this go in the future, let
> me know, I’d be happy to work on it.

I would tend to agree with this.

/Jarkko
diff mbox series

Patch

diff --git a/certs/blacklist.c b/certs/blacklist.c
index 6514f9ebc943..4adac7f8fd94 100644
--- a/certs/blacklist.c
+++ b/certs/blacklist.c
@@ -100,6 +100,38 @@  int mark_hash_blacklisted(const char *hash)
 	return 0;
 }
 
+int mark_key_revocationlisted(const char *data, size_t size)
+{
+	key_ref_t key;
+
+	key = key_create_or_update(make_key_ref(blacklist_keyring, true),
+				   "asymmetric",
+				   NULL,
+				   data,
+				   size,
+				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW),
+				   KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN);
+
+	if (IS_ERR(key)) {
+		pr_err("Problem with revocation key (%ld)\n", PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+
+	return 0;
+}
+
+int is_key_revocationlisted(struct pkcs7_message *pkcs7)
+{
+	int ret;
+
+	ret = validate_trust(pkcs7, blacklist_keyring);
+
+	if (ret == 0)
+		return -EKEYREJECTED;
+
+	return -ENOKEY;
+}
+
 /**
  * is_hash_blacklisted - Determine if a hash is blacklisted
  * @hash: The hash to be checked as a binary blob
diff --git a/certs/blacklist.h b/certs/blacklist.h
index 1efd6fa0dc60..420bb7c86e07 100644
--- a/certs/blacklist.h
+++ b/certs/blacklist.h
@@ -1,3 +1,15 @@ 
 #include <linux/kernel.h>
+#include <linux/errno.h>
+#include <crypto/pkcs7.h>
 
 extern const char __initconst *const blacklist_hashes[];
+
+#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
+#define validate_trust pkcs7_validate_trust
+#else
+static inline int validate_trust(struct pkcs7_message *pkcs7,
+				 struct key *trust_keyring)
+{
+	return -ENOKEY;
+}
+#endif
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 798291177186..f8ea96219155 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -241,6 +241,12 @@  int verify_pkcs7_message_sig(const void *data, size_t len,
 			pr_devel("PKCS#7 platform keyring is not available\n");
 			goto error;
 		}
+
+		ret = is_key_revocationlisted(pkcs7);
+		if (ret != -ENOKEY) {
+			pr_devel("PKCS#7 platform key revocationlisted\n");
+			goto error;
+		}
 	}
 	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
 	if (ret < 0) {
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index fb8b07daa9d1..b6991cfe1b6d 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -31,11 +31,14 @@  extern int restrict_link_by_builtin_and_secondary_trusted(
 #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
 #endif
 
+extern struct pkcs7_message *pkcs7;
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
 extern int mark_hash_blacklisted(const char *hash);
+extern int mark_key_revocationlisted(const char *data, size_t size);
 extern int is_hash_blacklisted(const u8 *hash, size_t hash_len,
 			       const char *type);
 extern int is_binary_blacklisted(const u8 *hash, size_t hash_len);
+extern int is_key_revocationlisted(struct pkcs7_message *pkcs7);
 #else
 static inline int is_hash_blacklisted(const u8 *hash, size_t hash_len,
 				      const char *type)
@@ -47,6 +50,14 @@  static inline int is_binary_blacklisted(const u8 *hash, size_t hash_len)
 {
 	return 0;
 }
+static inline int mark_key_revocationlisted(const char *data, size_t size)
+{
+	return 0;
+}
+static inline int is_key_revocationlisted(struct pkcs7_message *pkcs7)
+{
+	return -ENOKEY;
+}
 #endif
 
 #ifdef CONFIG_IMA_BLACKLIST_KEYRING
diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
index c5ba695c10e3..cc5a43804bc4 100644
--- a/security/integrity/platform_certs/keyring_handler.c
+++ b/security/integrity/platform_certs/keyring_handler.c
@@ -55,6 +55,15 @@  static __init void uefi_blacklist_binary(const char *source,
 	uefi_blacklist_hash(source, data, len, "bin:", 4);
 }
 
+/*
+ * Revocationlist the X509 cert
+ */
+static __init void uefi_revocationlist_x509(const char *source,
+					    const void *data, size_t len)
+{
+	mark_key_revocationlisted(data, len);
+}
+
 /*
  * Return the appropriate handler for particular signature list types found in
  * the UEFI db and MokListRT tables.
@@ -76,5 +85,7 @@  __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type)
 		return uefi_blacklist_x509_tbs;
 	if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
 		return uefi_blacklist_binary;
+	if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
+		return uefi_revocationlist_x509;
 	return 0;
 }