All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]
@ 2016-01-19 11:30 David Howells
  2016-01-19 11:30 ` [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key " David Howells
                   ` (23 more replies)
  0 siblings, 24 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:30 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel


Here's a set of patches that changes how certificates/keys are determined
to be trusted.  That's currently a two-step process:

 (1) Up until recently, when an X.509 certificate was parsed - no matter
     the source - it was judged against the keys in .system_keyring,
     assuming those keys to be trusted if they have KEY_FLAG_TRUSTED set
     upon them.

     This has just been changed such that any key in the .ima_mok keyring
     may also be used to judge the trustwortiness of a new certificate,
     whether or not the .ima_mok keyring is meant to be consulted for
     whatever process is being undertaken.

     If a certificate is determined to be trustworthy, KEY_FLAG_TRUSTED
     will be set upon a key it is loaded into (if it is loaded into one),
     no matter what the key is going to be loaded for.

 (2) If an X.509 certificate is loaded into a key, then that key - if
     KEY_FLAG_TRUSTED gets set upon it - can be linked into any keyring
     with KEY_FLAG_TRUSTED_ONLY set upon it.  This was meant to be the
     system keyring only, but has been extended to various IMA keyrings.

     A user can at will link any key marked KEY_FLAG_TRUSTED into any
     keyring marked KEY_FLAG_TRUSTED_ONLY if the relevant permissions masks
     permit it.

These patches change that:

 (1) Trust becomes a matter of consulting the ring of trusted keys supplied
     when the trust is evaluated only.

 (2) Asymmetric keys retain the source certificate signature information
     for future evaluation rather than discarding it.

 (3) Every keyring can be supplied with its own manager function to
     restrict what may be added to that keyring.  This is called whenever a
     key is to be linked into the keyring to guard against a key being
     created in one keyring and then linked across.

     This function is supplied with the keyring and the key type and
     payload[*] of the key being linked in for use in its evaluation.  It
     is permitted to use other data also, such as the contents of other
     keyrings such as the system keyrings.

     [*] The type and payload are supplied instead of a key because as an
     	 optimisation this function may be called whilst creating a key and
     	 so may reject the proposed key between preparse and allocation.

 (4) A default manager function is provided that permits keys to be
     restricted to only asymmetric keys that are vouched for by the
     contents of the system keyring.

 (5) A key allocation flag, KEY_ALLOC_BYPASS_RESTRICTION, is made available
     so that the kernel can initialise keyrings with keys that form the
     root of the trust relationship.

 (6) KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed, along with
     key_preparsed_payload::trusted.

This change also makes it possible for userspace to create a private set of
trusted keys and then to seal it by setting a manager function where the
private set is wholly independent of the kernel's trust relationships.

Further changes in the set involve extracting certain IMA special keyrings
and making them generally global:

 (*) .system_keyring is renamed to .builtin_trusted_keys and remains read
     only.  It carries only keys built in to the kernel.  It may be where
     UEFI keys should be loaded - though that could better be the new
     secondary keyring (see below).

 (*) An optional system blacklist keyring is created to replace the IMA
     keyring.

     (*) A 'blacklist' key type is created that may contain a hex string in
         its description (it carries no payload).  When an X.509
         certificate is parsed, the system blacklist is searched for a
         blacklist key that matches the TBS hash of the X.509 certificate
         and if one is found, the certificate is considered blacklisted.

     (*) A list of blacklisted hashes can be added to the system blacklist
         keyring at compile time.  In the future it should also be possible
         to load this up from such as the UEFI blacklist.

     (*) Keys can be added to the blacklist keyring by root if the keys are
     	 signed by a key in the builtin system keyring.  These can then be
     	 searched for by asymmetric key ID.  This allows the functionality
     	 of the IMA blacklist keyring to be replicated.

 	 It might be worth making an asymmetric key subtype that carries no
 	 data to be used here as the cryptographic material is then just
 	 dead weight since the IDs are what matter.

 (*) An optional secondary system keyring (called .secondary_trusted_keys)
     is added to replace the IMA MOK keyring.

     (*) Keys can be added to the secondary keyring by root if the keys can
     	 be vouched for by either ring of system keys.

 (*) Module signing and kexec only use .builtin_trusted_keys and do not use
     the new secondary keyring, but they do consult the system blacklist.

 (*) If the kernel sees a PKCS#7 message with more than one signature, at
     least one of which is blacklisted, it will permit the message if at
     least one of the non-blacklisted signature chains is vouched for.  If
     none are, then EKEYREJECTED will be given.  This error takes priority
     over giving ENOPKG for unsupported encryption.

The patches can be found here also:

	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust

David
---
David Howells (20):
      KEYS: Add an alloc flag to convey the builtinness of a key
      KEYS: Add a system blacklist keyring
      X.509: Allow X.509 certs to be blacklisted
      X.509: Don't treat self-signed keys specially
      KEYS: Generalise system_verify_data() to provide access to internal content
      PKCS#7: Make trust determination dependent on contents of trust keyring
      KEYS: Add a facility to restrict new links into a keyring
      KEYS: Allow authentication data to be stored in an asymmetric key
      KEYS: Add identifier pointers to public_key_signature struct
      X.509: Retain the key verification data
      X.509: Extract signature digest and make self-signed cert checks earlier
      PKCS#7: Make the signature a pointer rather than embedding it
      X.509: Move the trust validation code out to its own file
      KEYS: Generalise x509_request_asymmetric_key()
      KEYS: Move the point of trust determination to __key_link()
      KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED
      PKCS#7: Handle blacklisted certificates
      IMA: Use the system blacklist keyring
      certs: Add a secondary system keyring that can be added to dynamically
      IMA: Replace the .ima_mok keyring with the secondary system keyring


 Documentation/security/keys.txt           |   14 +
 arch/x86/kernel/kexec-bzimage64.c         |   18 --
 certs/Kconfig                             |   26 ++
 certs/Makefile                            |    6 +
 certs/blacklist.c                         |  184 +++++++++++++++++
 certs/blacklist.h                         |    3 
 certs/blacklist_hashes.c                  |    6 +
 certs/blacklist_nohashes.c                |    5 
 certs/system_keyring.c                    |  141 ++++++++++---
 crypto/asymmetric_keys/Kconfig            |    1 
 crypto/asymmetric_keys/Makefile           |    2 
 crypto/asymmetric_keys/asymmetric_keys.h  |    2 
 crypto/asymmetric_keys/asymmetric_type.c  |    7 -
 crypto/asymmetric_keys/mscode_parser.c    |   21 +-
 crypto/asymmetric_keys/pkcs7_key_type.c   |   66 +++---
 crypto/asymmetric_keys/pkcs7_parser.c     |   59 +++--
 crypto/asymmetric_keys/pkcs7_parser.h     |   12 -
 crypto/asymmetric_keys/pkcs7_trust.c      |   44 ++--
 crypto/asymmetric_keys/pkcs7_verify.c     |  141 ++++++-------
 crypto/asymmetric_keys/public_key.c       |   24 ++
 crypto/asymmetric_keys/public_key.h       |    6 +
 crypto/asymmetric_keys/public_key_trust.c |  209 +++++++++++++++++++
 crypto/asymmetric_keys/verify_pefile.c    |   40 +---
 crypto/asymmetric_keys/verify_pefile.h    |    5 
 crypto/asymmetric_keys/x509_cert_parser.c |   51 +++--
 crypto/asymmetric_keys/x509_parser.h      |   13 +
 crypto/asymmetric_keys/x509_public_key.c  |  318 +++++++++--------------------
 fs/cifs/cifsacl.c                         |    2 
 fs/nfs/nfs4idmap.c                        |    2 
 include/crypto/pkcs7.h                    |    6 -
 include/crypto/public_key.h               |   35 +--
 include/keys/asymmetric-subtype.h         |    2 
 include/keys/asymmetric-type.h            |    8 -
 include/keys/system_keyring.h             |   52 ++---
 include/linux/key-type.h                  |    1 
 include/linux/key.h                       |   39 +++-
 include/linux/verification.h              |   49 ++++
 include/linux/verify_pefile.h             |   22 --
 kernel/module_signing.c                   |    7 -
 net/dns_resolver/dns_key.c                |    2 
 net/rxrpc/ar-key.c                        |    4 
 security/integrity/digsig.c               |   10 +
 security/integrity/digsig_asymmetric.c    |   18 +-
 security/integrity/ima/Kconfig            |   18 --
 security/integrity/ima/Makefile           |    1 
 security/integrity/ima/ima_mok.c          |   55 -----
 security/keys/key.c                       |   44 +++-
 security/keys/keyring.c                   |   26 ++
 security/keys/persistent.c                |    4 
 security/keys/process_keys.c              |   16 +
 security/keys/request_key.c               |    4 
 security/keys/request_key_auth.c          |    2 
 52 files changed, 1131 insertions(+), 722 deletions(-)
 create mode 100644 certs/blacklist.c
 create mode 100644 certs/blacklist.h
 create mode 100644 certs/blacklist_hashes.c
 create mode 100644 certs/blacklist_nohashes.c
 create mode 100644 crypto/asymmetric_keys/public_key_trust.c
 create mode 100644 include/linux/verification.h
 delete mode 100644 include/linux/verify_pefile.h
 delete mode 100644 security/integrity/ima/ima_mok.c

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
@ 2016-01-19 11:30 ` David Howells
  2016-01-20 18:58   ` Mimi Zohar
  2016-02-03 15:30   ` David Howells
  2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
                   ` (22 subsequent siblings)
  23 siblings, 2 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:30 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Add KEY_ALLOC_BUILT_IN to convey that a key should have KEY_FLAG_BUILTIN
set rather than setting it after the fact.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/system_keyring.c |    4 ++--
 include/linux/key.h    |    1 +
 security/keys/key.c    |    2 ++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 2570598b784d..f4180326c2e1 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -84,12 +84,12 @@ static __init int load_system_certificate_list(void)
 					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 					   KEY_USR_VIEW | KEY_USR_READ),
 					   KEY_ALLOC_NOT_IN_QUOTA |
-					   KEY_ALLOC_TRUSTED);
+					   KEY_ALLOC_TRUSTED |
+					   KEY_ALLOC_BUILT_IN);
 		if (IS_ERR(key)) {
 			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
 			       PTR_ERR(key));
 		} else {
-			set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
 			pr_notice("Loaded X.509 cert '%s'\n",
 				  key_ref_to_ptr(key)->description);
 			key_ref_put(key);
diff --git a/include/linux/key.h b/include/linux/key.h
index 7321ab8ef949..5f5b1129dc92 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -219,6 +219,7 @@ extern struct key *key_alloc(struct key_type *type,
 #define KEY_ALLOC_QUOTA_OVERRUN	0x0001	/* add to quota, permit even if overrun */
 #define KEY_ALLOC_NOT_IN_QUOTA	0x0002	/* not in quota */
 #define KEY_ALLOC_TRUSTED	0x0004	/* Key should be flagged as trusted */
+#define KEY_ALLOC_BUILT_IN	0x0008	/* Key is built into kernel */
 
 extern void key_revoke(struct key *key);
 extern void key_invalidate(struct key *key);
diff --git a/security/keys/key.c b/security/keys/key.c
index 07a87311055c..48dbfa543bcb 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -296,6 +296,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
 	if (flags & KEY_ALLOC_TRUSTED)
 		key->flags |= 1 << KEY_FLAG_TRUSTED;
+	if (flags & KEY_ALLOC_BUILT_IN)
+		key->flags |= 1 << KEY_FLAG_BUILTIN;
 
 #ifdef KEY_DEBUGGING
 	key->magic = KEY_DEBUG_MAGIC;

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
  2016-01-19 11:30 ` [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key " David Howells
@ 2016-01-19 11:30 ` David Howells
  2016-01-20 19:31   ` Mimi Zohar
                     ` (3 more replies)
  2016-01-19 11:30 ` [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted " David Howells
                   ` (21 subsequent siblings)
  23 siblings, 4 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:30 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Add the following:

 (1) A new system keyring that is used to store information about
     blacklisted certificates and signatures.

 (2) A new key type (called 'blacklist') that is used to store a
     blacklisted hash in its description as a hex string.  The key accepts
     no payload.

 (3) The ability to configure a list of blacklisted hashes into the kernel
     at build time.  This is done by setting
     CONFIG_SYSTEM_BLACKLIST_HASH_LIST to the filename of a list of hashes
     that are in the form:

	"<hash>", "<hash>", ..., "<hash>"

     where each <hash> is a hex string representation of the hash and must
     include all necessary leading zeros to pad the hash to the right size.

The above are enabled with CONFIG_SYSTEM_BLACKLIST_KEYRING.

Once the kernel is booted, the blacklist keyring can be listed:

	root@andromeda ~]# keyctl show %:.blacklist
	Keyring
	 723359729 ---lswrv      0     0  keyring: .blacklist
	 676257228 ---lswrv      0     0   \_ blacklist: 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46

The blacklist cannot currently be modified by userspace, but it will be
possible to load it, for example, from the UEFI blacklist database.

In the future, it should also be made possible to load blacklisted
asymmetric keys in here too.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/Kconfig                 |   18 +++++
 certs/Makefile                |    6 ++
 certs/blacklist.c             |  164 +++++++++++++++++++++++++++++++++++++++++
 certs/blacklist.h             |    3 +
 certs/blacklist_hashes.c      |    6 ++
 certs/blacklist_nohashes.c    |    5 +
 include/keys/system_keyring.h |   15 ++++
 7 files changed, 217 insertions(+)
 create mode 100644 certs/blacklist.c
 create mode 100644 certs/blacklist.h
 create mode 100644 certs/blacklist_hashes.c
 create mode 100644 certs/blacklist_nohashes.c

diff --git a/certs/Kconfig b/certs/Kconfig
index b030b9c7ed34..7ce41d4b541d 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -39,4 +39,22 @@ config SYSTEM_TRUSTED_KEYS
 	  form of DER-encoded *.x509 files in the top-level build directory,
 	  those are no longer used. You will need to set this option instead.
 
+config SYSTEM_BLACKLIST_KEYRING
+	bool "Provide system-wide ring of blacklisted keys"
+	depends on KEYS
+	help
+	  Provide a system keyring to which blacklisted keys can be added.
+	  Keys in the keyring are considered entirely untrusted.  Keys in this
+	  keyring are used by the module signature checking to reject loading
+	  of modules signed with a blacklisted key.
+
+config SYSTEM_BLACKLIST_HASH_LIST
+	string "Hashes to be preloaded into the system blacklist keyring"
+	depends on SYSTEM_BLACKLIST_KEYRING
+	help
+	  If set, this option should be the filename of a list of hashes in the
+	  form "<hash>", "<hash>", ... .  This will be included into a C
+	  wrapper to incorporate the list into the kernel.  Each <hash> should
+	  be a string of hex digits.
+
 endmenu
diff --git a/certs/Makefile b/certs/Makefile
index 28ac694dd11a..556705723c68 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -3,6 +3,12 @@
 #
 
 obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o
+ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"")
+obj-y += blacklist_hashes.o
+else
+obj-y += blacklist_nohashes.o
+endif
 
 ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
 
diff --git a/certs/blacklist.c b/certs/blacklist.c
new file mode 100644
index 000000000000..5f54baae3a32
--- /dev/null
+++ b/certs/blacklist.c
@@ -0,0 +1,164 @@
+/* System hash blacklist.
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "blacklist: "fmt
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/key.h>
+#include <linux/key-type.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <keys/system_keyring.h>
+#include "blacklist.h"
+
+static struct key *blacklist_keyring;
+
+/*
+ * The description must be an even number of hex digits.  We keep the hash
+ * here.
+ */
+static int blacklist_vet_description(const char *desc)
+{
+	int n = 0;
+
+	for (; *desc; desc++) {
+		if (!isxdigit(*desc))
+			return -EINVAL;
+		n++;
+	}
+
+	if (n == 0 || n & 1)
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * The hash to be blacklisted is expected to be in the description.  There will
+ * be no payload.
+ */
+static int blacklist_preparse(struct key_preparsed_payload *prep)
+{
+	if (prep->datalen > 0)
+		return -EINVAL;
+	return 0;
+}
+
+static void blacklist_free_preparse(struct key_preparsed_payload *prep)
+{
+}
+
+static struct key_type key_type_blacklist = {
+	.name			= "blacklist",
+	.vet_description	= blacklist_vet_description,
+	.preparse		= blacklist_preparse,
+	.free_preparse		= blacklist_free_preparse,
+	.instantiate		= generic_key_instantiate,
+};
+
+/**
+ * mark_hash_blacklisted - Add a hash to the system blacklist
+ * @hash - The hash as a hex string
+ */
+int mark_hash_blacklisted(const char *hash)
+{
+	key_ref_t key;
+
+	key = key_create_or_update(make_key_ref(blacklist_keyring, true),
+				   "blacklist",
+				   hash,
+				   NULL,
+				   0,
+				   ((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 blacklisting hash (%ld)\n",
+		       PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+	return 0;
+}
+
+/**
+ * is_hash_blacklisted - Determine if a hash is blacklisted
+ * @hash: The hash to be checked as a hex string.
+ */
+int is_hash_blacklisted(const char *hash)
+{
+	key_ref_t kref;
+
+	kref = keyring_search(make_key_ref(blacklist_keyring, true),
+			      &key_type_blacklist, hash);
+	if (!IS_ERR(kref)) {
+		key_ref_put(kref);
+		return -EKEYREJECTED;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(is_hash_blacklisted);
+
+/**
+ * is_bin_hash_blacklisted - Determine if a hash is blacklisted
+ * @hash: The hash to be checked as a binary blob
+ * @hash_len: The length of the binary hash
+ */
+int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len)
+{
+	char *buffer;
+	int ret;
+
+	buffer = kmalloc(hash_len * 2 + 1, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	bin2hex(buffer, hash, hash_len);
+	buffer[hash_len * 2] = 0;
+	ret = is_hash_blacklisted(buffer);
+	kfree(buffer);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(is_bin_hash_blacklisted);
+
+/*
+ * Intialise the blacklist
+ */
+static int __init blacklist_init(void)
+{
+	const char *const *bl;
+
+	if (register_key_type(&key_type_blacklist) < 0)
+		panic("Can't allocate system blacklist key type\n");
+
+	blacklist_keyring =
+		keyring_alloc(".blacklist",
+			      KUIDT_INIT(0), KGIDT_INIT(0),
+			      current_cred(),
+			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+			      KEY_USR_VIEW | KEY_USR_READ |
+			      KEY_USR_SEARCH,
+			      KEY_ALLOC_NOT_IN_QUOTA |
+			      KEY_FLAG_KEEP,
+			      NULL);
+	if (IS_ERR(blacklist_keyring))
+		panic("Can't allocate system blacklist keyring\n");
+
+	for (bl = blacklist_hashes; *bl; bl++)
+		if (mark_hash_blacklisted(*bl) < 0)
+			pr_err("- blacklisting failed\n");
+	return 0;
+}
+
+/*
+ * Must be initialised before we try and load the keys into the keyring.
+ */
+device_initcall(blacklist_init);
diff --git a/certs/blacklist.h b/certs/blacklist.h
new file mode 100644
index 000000000000..150d82da8e99
--- /dev/null
+++ b/certs/blacklist.h
@@ -0,0 +1,3 @@
+#include <linux/kernel.h>
+
+extern const char __initdata *const blacklist_hashes[];
diff --git a/certs/blacklist_hashes.c b/certs/blacklist_hashes.c
new file mode 100644
index 000000000000..5bd449f7db17
--- /dev/null
+++ b/certs/blacklist_hashes.c
@@ -0,0 +1,6 @@
+#include "blacklist.h"
+
+const char __initdata *const blacklist_hashes[] = {
+#include CONFIG_SYSTEM_BLACKLIST_HASH_LIST
+	, NULL
+};
diff --git a/certs/blacklist_nohashes.c b/certs/blacklist_nohashes.c
new file mode 100644
index 000000000000..851de10706a5
--- /dev/null
+++ b/certs/blacklist_nohashes.c
@@ -0,0 +1,5 @@
+#include "blacklist.h"
+
+const char __initdata *const blacklist_hashes[] = {
+	NULL
+};
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 39fd38cfa8c9..e8334d299314 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -35,6 +35,21 @@ extern int system_verify_data(const void *data, unsigned long len,
 			      enum key_being_used_for usage);
 #endif
 
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+extern int mark_hash_blacklisted(const char *hash);
+extern int is_hash_blacklisted(const char *hash);
+extern int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len);
+#else
+static inline int is_hash_blacklisted(const char *hash)
+{
+	return 0;
+}
+static inline int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_IMA_MOK_KEYRING
 extern struct key *ima_mok_keyring;
 extern struct key *ima_blacklist_keyring;

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
  2016-01-19 11:30 ` [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key " David Howells
  2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
@ 2016-01-19 11:30 ` David Howells
  2016-01-20 20:33   ` Mimi Zohar
  2016-02-03 15:46   ` David Howells
  2016-01-19 11:30 ` [RFC PATCH 04/20] X.509: Don't treat self-signed keys specially " David Howells
                   ` (20 subsequent siblings)
  23 siblings, 2 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:30 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Allow X.509 certs to be blacklisted based on their TBS hash.  This is
convenient since we have to determine this anyway to be able to check the
signature on an X.509 certificate.

If a certificate built into the kernel is blacklisted, something like the
following might then be seen during boot:

	X.509: Cert 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46 is blacklisted
	Problem loading in-kernel X.509 certificate (-129)

where the hex string shown is the blacklisted hash.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/x509_parser.h     |    1 +
 crypto/asymmetric_keys/x509_public_key.c |   19 +++++++++++++++++--
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index dbeed6018e63..be7cf2eae3bd 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -43,6 +43,7 @@ struct x509_certificate {
 	bool		verified;
 	bool		trusted;
 	bool		unsupported_crypto;	/* T if can't be verified due to missing crypto */
+	bool		blacklisted;
 };
 
 /*
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 9e9e5a6a9ed6..c4f3c40a4ab9 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -92,7 +92,7 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 		lookup = skid->data;
 		len = skid->len;
 	}
-	
+
 	/* Construct an identifier "id:<keyid>". */
 	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
 	if (!req)
@@ -141,7 +141,7 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 			goto reject;
 		}
 	}
-	
+
 	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
 	return key;
 
@@ -211,6 +211,16 @@ int x509_get_sig_params(struct x509_certificate *cert)
 		goto error;
 	might_sleep();
 	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
+	if (ret < 0)
+		goto error;
+
+	ret = is_bin_hash_blacklisted(digest, digest_size);
+	if (ret == -EKEYREJECTED) {
+		pr_err("Cert %*phN is blacklisted\n", (int)digest_size, digest);
+		cert->blacklisted = true;
+		ret = 0;
+	}
+
 error:
 	crypto_free_shash(tfm);
 	pr_devel("<==%s() = %d\n", __func__, ret);
@@ -327,6 +337,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 			prep->trusted = 1;
 	}
 
+	/* Don't permit addition of blacklisted keys */
+	ret = -EKEYREJECTED;
+	if (cert->blacklisted)
+		goto error_free_cert;
+
 	/* Propose a description */
 	sulen = strlen(cert->subject);
 	if (cert->raw_skid) {

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 04/20] X.509: Don't treat self-signed keys specially [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (2 preceding siblings ...)
  2016-01-19 11:30 ` [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted " David Howells
@ 2016-01-19 11:30 ` David Howells
  2016-01-20 20:40   ` Mimi Zohar
  2016-01-19 11:31 ` [RFC PATCH 05/20] KEYS: Generalise system_verify_data() to provide access to internal content " David Howells
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 56+ messages in thread
From: David Howells @ 2016-01-19 11:30 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Trust for a self-signed certificate can normally only be determined by
whether we obtained it from a trusted location (ie. it was built into the
kernel at compile time), so there's not really any point in checking it -
we could verify that the signature is valid, but it doesn't really tell us
anything if the signature checks out.

However, there's a bug in the code determining whether a certificate is
self-signed or not - if they have neither AKID nor SKID then we just assume
that the cert is self-signed, which may not be true.

Given this, remove the code that treats self-signed certs specially when it
comes to evaluating trustability and attempt to evaluate them as ordinary
signed certificates.  We then expect self-signed certificates to fail the
trustability check and be marked as untrustworthy in x509_key_preparse().

Note that there is the possibility of the trustability check on a
self-signed cert then succeeding.  This is most likely to happen when a
duplicate of the certificate is already on the trust keyring - in which
case it shouldn't be a problem.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: David Woodhouse <David.Woodhouse@intel.com>
cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
---

 crypto/asymmetric_keys/x509_public_key.c |   25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index c4f3c40a4ab9..630c1c331fe1 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -265,6 +265,9 @@ static int x509_validate_trust(struct x509_certificate *cert,
 	struct key *key;
 	int ret = 1;
 
+	if (!cert->akid_id && !cert->akid_skid)
+		return 1;
+
 	if (!trust_keyring)
 		return -EOPNOTSUPP;
 
@@ -322,19 +325,23 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
 	cert->pub->id_type = PKEY_ID_X509;
 
-	/* Check the signature on the key if it appears to be self-signed */
-	if ((!cert->akid_skid && !cert->akid_id) ||
-	    asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
-	    asymmetric_key_id_same(cert->id, cert->akid_id)) {
-		ret = x509_check_signature(cert->pub, cert); /* self-signed */
-		if (ret < 0)
-			goto error_free_cert;
-	} else if (!prep->trusted) {
+	/* See if we can derive the trustability of this certificate.
+	 *
+	 * When it comes to self-signed certificates, we cannot evaluate
+	 * trustedness except by the fact that we obtained it from a trusted
+	 * location.  So we just rely on x509_validate_trust() failing in this
+	 * case.
+	 *
+	 * Note that there's a possibility of a self-signed cert matching a
+	 * cert that we have (most likely a duplicate that we already trust) -
+	 * in which case it will be marked trusted.
+	 */
+	if (!prep->trusted) {
 		ret = x509_validate_trust(cert, get_system_trusted_keyring());
 		if (ret)
 			ret = x509_validate_trust(cert, get_ima_mok_keyring());
 		if (!ret)
-			prep->trusted = 1;
+			prep->trusted = true;
 	}
 
 	/* Don't permit addition of blacklisted keys */

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 05/20] KEYS: Generalise system_verify_data() to provide access to internal content [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (3 preceding siblings ...)
  2016-01-19 11:30 ` [RFC PATCH 04/20] X.509: Don't treat self-signed keys specially " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-01-19 11:31 ` [RFC PATCH 06/20] PKCS#7: Make trust determination dependent on contents of trust keyring " David Howells
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Generalise system_verify_data() to provide access to internal content
through a callback.  This allows all the PKCS#7 stuff to be hidden inside
this function and removed from the PE file parser and the PKCS#7 test key.

If external content is not required, NULL should be passed as data to the
function.  If the callback is not required, that can be set to NULL.

The function is now called verify_pkcs7_signature() to contrast with
verify_pefile_signature() and the definitions of both have been moved into
linux/verification.h along with the key_being_used_for enum.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 arch/x86/kernel/kexec-bzimage64.c       |   18 ++------
 certs/system_keyring.c                  |   45 ++++++++++++++++-----
 crypto/asymmetric_keys/Kconfig          |    1 
 crypto/asymmetric_keys/mscode_parser.c  |   21 +++-------
 crypto/asymmetric_keys/pkcs7_key_type.c |   66 +++++++++++++++----------------
 crypto/asymmetric_keys/pkcs7_parser.c   |   21 +++++-----
 crypto/asymmetric_keys/verify_pefile.c  |   40 ++++---------------
 crypto/asymmetric_keys/verify_pefile.h  |    5 +-
 include/crypto/pkcs7.h                  |    3 +
 include/crypto/public_key.h             |   14 -------
 include/keys/asymmetric-type.h          |    1 
 include/keys/system_keyring.h           |    7 ---
 include/linux/verification.h            |   50 +++++++++++++++++++++++
 include/linux/verify_pefile.h           |   22 ----------
 kernel/module_signing.c                 |    5 +-
 15 files changed, 157 insertions(+), 162 deletions(-)
 create mode 100644 include/linux/verification.h
 delete mode 100644 include/linux/verify_pefile.h

diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 0f8a6bbaaa44..0b5da62eb203 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -19,8 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/efi.h>
-#include <linux/verify_pefile.h>
-#include <keys/system_keyring.h>
+#include <linux/verification.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -529,18 +528,9 @@ static int bzImage64_cleanup(void *loader_data)
 #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
 static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
 {
-	bool trusted;
-	int ret;
-
-	ret = verify_pefile_signature(kernel, kernel_len,
-				      system_trusted_keyring,
-				      VERIFYING_KEXEC_PE_SIGNATURE,
-				      &trusted);
-	if (ret < 0)
-		return ret;
-	if (!trusted)
-		return -EKEYREJECTED;
-	return 0;
+	return verify_pefile_signature(kernel, kernel_len,
+				       NULL,
+				       VERIFYING_KEXEC_PE_SIGNATURE);
 }
 #endif
 
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index f4180326c2e1..a83bffedc0aa 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -108,16 +108,25 @@ late_initcall(load_system_certificate_list);
 #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
 
 /**
- * Verify a PKCS#7-based signature on system data.
- * @data: The data to be verified.
+ * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
+ * @data: The data to be verified (NULL if expecting internal data).
  * @len: Size of @data.
  * @raw_pkcs7: The PKCS#7 message that is the signature.
  * @pkcs7_len: The size of @raw_pkcs7.
+ * @trusted_keys: Trusted keys to use (NULL for system_trusted_keyring).
  * @usage: The use to which the key is being put.
+ * @view_content: Callback to gain access to content.
+ * @ctx: Context for callback.
  */
-int system_verify_data(const void *data, unsigned long len,
-		       const void *raw_pkcs7, size_t pkcs7_len,
-		       enum key_being_used_for usage)
+int verify_pkcs7_signature(const void *data, size_t len,
+			   const void *raw_pkcs7, size_t pkcs7_len,
+			   struct key *trusted_keys,
+			   int untrusted_error,
+			   enum key_being_used_for usage,
+			   int (*view_content)(void *ctx,
+					       const void *data, size_t len,
+					       size_t asn1hdrlen),
+			   void *ctx)
 {
 	struct pkcs7_message *pkcs7;
 	bool trusted;
@@ -128,7 +137,7 @@ int system_verify_data(const void *data, unsigned long len,
 		return PTR_ERR(pkcs7);
 
 	/* The data should be detached - so we need to supply it. */
-	if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
+	if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
 		pr_err("PKCS#7 signature with non-detached data\n");
 		ret = -EBADMSG;
 		goto error;
@@ -138,13 +147,29 @@ int system_verify_data(const void *data, unsigned long len,
 	if (ret < 0)
 		goto error;
 
-	ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
+	if (!trusted_keys)
+		trusted_keys = system_trusted_keyring;
+	ret = pkcs7_validate_trust(pkcs7, trusted_keys, &trusted);
 	if (ret < 0)
 		goto error;
 
-	if (!trusted) {
+	if (!trusted && untrusted_error) {
 		pr_err("PKCS#7 signature not signed with a trusted key\n");
-		ret = -ENOKEY;
+		ret = untrusted_error;
+		goto error;
+	}
+
+	if (view_content) {
+		size_t asn1hdrlen;
+
+		ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
+		if (ret < 0) {
+			if (ret == -ENODATA)
+				pr_devel("PKCS#7 message does not contain data\n");
+			goto error;
+		}
+
+		ret = view_content(ctx, data, len, asn1hdrlen);
 	}
 
 error:
@@ -152,6 +177,6 @@ error:
 	pr_devel("<==%s() = %d\n", __func__, ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(system_verify_data);
+EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
 
 #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 4870f28403f5..d071989142b5 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -61,6 +61,7 @@ config PKCS7_TEST_KEY
 config SIGNED_PE_FILE_VERIFICATION
 	bool "Support for PE file signature verification"
 	depends on PKCS7_MESSAGE_PARSER=y
+	depends on SYSTEM_DATA_VERIFICATION
 	select ASN1
 	select OID_REGISTRY
 	help
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c
index adcef59eec0b..b2fa9eea3ef6 100644
--- a/crypto/asymmetric_keys/mscode_parser.c
+++ b/crypto/asymmetric_keys/mscode_parser.c
@@ -21,19 +21,13 @@
 /*
  * Parse a Microsoft Individual Code Signing blob
  */
-int mscode_parse(struct pefile_context *ctx)
+int mscode_parse(void *_ctx, const void *content_data, size_t data_len,
+		 size_t asn1hdrlen)
 {
-	const void *content_data;
-	size_t data_len;
-	int ret;
-
-	ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
-
-	if (ret) {
-		pr_debug("PKCS#7 message does not contain data\n");
-		return ret;
-	}
+	struct pefile_context *ctx = _ctx;
 
+	content_data -= asn1hdrlen;
+	data_len += asn1hdrlen;
 	pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
 		 content_data);
 
@@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen,
 {
 	struct pefile_context *ctx = context;
 
-	ctx->digest = value;
-	ctx->digest_len = vlen;
-	return 0;
+	ctx->digest = kmemdup(value, vlen, GFP_KERNEL);
+	return ctx->digest ? 0 : -ENOMEM;
 }
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c
index e2d0edbbc71a..b74aaaefbc07 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -13,11 +13,11 @@
 #include <linux/key.h>
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/verification.h>
 #include <linux/key-type.h>
 #include <keys/asymmetric-type.h>
 #include <crypto/pkcs7.h>
 #include <keys/user-type.h>
-#include <keys/system_keyring.h>
 #include "pkcs7_parser.h"
 
 MODULE_LICENSE("GPL");
@@ -29,15 +29,37 @@ MODULE_PARM_DESC(pkcs7_usage,
 		 "Usage to specify when verifying the PKCS#7 message");
 
 /*
+ * Retrieve the PKCS#7 message content.
+ */
+static int pkcs7_view_content(void *ctx, const void *data, size_t len,
+			      size_t asn1hdrlen)
+{
+	struct key_preparsed_payload *prep = ctx;
+	const void *saved_prep_data;
+	size_t saved_prep_datalen;
+	int ret;
+
+	kenter(",%zu", len);
+
+	saved_prep_data = prep->data;
+	saved_prep_datalen = prep->datalen;
+	prep->data = data;
+	prep->datalen = len;
+
+	ret = user_preparse(prep);
+
+	prep->data = saved_prep_data;
+	prep->datalen = saved_prep_datalen;
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/*
  * Preparse a PKCS#7 wrapped and validated data blob.
  */
 static int pkcs7_preparse(struct key_preparsed_payload *prep)
 {
 	enum key_being_used_for usage = pkcs7_usage;
-	struct pkcs7_message *pkcs7;
-	const void *data, *saved_prep_data;
-	size_t datalen, saved_prep_datalen;
-	bool trusted;
 	int ret;
 
 	kenter("");
@@ -47,37 +69,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
 		return -EINVAL;
 	}
 
-	saved_prep_data = prep->data;
-	saved_prep_datalen = prep->datalen;
-	pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
-	if (IS_ERR(pkcs7)) {
-		ret = PTR_ERR(pkcs7);
-		goto error;
-	}
-
-	ret = pkcs7_verify(pkcs7, usage);
-	if (ret < 0)
-		goto error_free;
-
-	ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
-	if (ret < 0)
-		goto error_free;
-	if (!trusted)
-		pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
-
-	ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
-	if (ret < 0)
-		goto error_free;
-
-	prep->data = data;
-	prep->datalen = datalen;
-	ret = user_preparse(prep);
-	prep->data = saved_prep_data;
-	prep->datalen = saved_prep_datalen;
+	ret = verify_pkcs7_signature(NULL, 0,
+				     prep->data, prep->datalen,
+				     NULL, -ENOKEY, usage,
+				     pkcs7_view_content, prep);
 
-error_free:
-	pkcs7_free_message(pkcs7);
-error:
 	kleave(" = %d", ret);
 	return ret;
 }
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 758acabf2d81..7b69783cff99 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -165,24 +165,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message);
  * @pkcs7: The preparsed PKCS#7 message to access
  * @_data: Place to return a pointer to the data
  * @_data_len: Place to return the data length
- * @want_wrapper: True if the ASN.1 object header should be included in the data
+ * @_headerlen: Size of ASN.1 header not included in _data
  *
- * Get access to the data content of the PKCS#7 message, including, optionally,
- * the header of the ASN.1 object that contains it.  Returns -ENODATA if the
- * data object was missing from the message.
+ * Get access to the data content of the PKCS#7 message.  The size of the
+ * header of the ASN.1 object that contains it is also provided and can be used
+ * to adjust *_data and *_data_len to get the entire object.
+ *
+ * Returns -ENODATA if the data object was missing from the message.
  */
 int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
 			   const void **_data, size_t *_data_len,
-			   bool want_wrapper)
+			   size_t *_headerlen)
 {
-	size_t wrapper;
-
 	if (!pkcs7->data)
 		return -ENODATA;
 
-	wrapper = want_wrapper ? pkcs7->data_hdrlen : 0;
-	*_data = pkcs7->data - wrapper;
-	*_data_len = pkcs7->data_len + wrapper;
+	*_data = pkcs7->data;
+	*_data_len = pkcs7->data_len;
+	if (_headerlen)
+		*_headerlen = pkcs7->data_hdrlen;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 897b734dabf9..443a00f9cd7a 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -16,7 +16,7 @@
 #include <linux/err.h>
 #include <linux/pe.h>
 #include <linux/asn1.h>
-#include <crypto/pkcs7.h>
+#include <linux/verification.h>
 #include <crypto/hash.h>
 #include "verify_pefile.h"
 
@@ -392,9 +392,8 @@ error_no_desc:
  * verify_pefile_signature - Verify the signature on a PE binary image
  * @pebuf: Buffer containing the PE binary image
  * @pelen: Length of the binary image
- * @trust_keyring: Signing certificates to use as starting points
+ * @trust_keys: Signing certificate(s) to use as starting points
  * @usage: The use to which the key is being put.
- * @_trusted: Set to true if trustworth, false otherwise
  *
  * Validate that the certificate chain inside the PKCS#7 message inside the PE
  * binary image intersects keys we already know and trust.
@@ -418,14 +417,10 @@ error_no_desc:
  * May also return -ENOMEM.
  */
 int verify_pefile_signature(const void *pebuf, unsigned pelen,
-			    struct key *trusted_keyring,
-			    enum key_being_used_for usage,
-			    bool *_trusted)
+			    struct key *trusted_keys,
+			    enum key_being_used_for usage)
 {
-	struct pkcs7_message *pkcs7;
 	struct pefile_context ctx;
-	const void *data;
-	size_t datalen;
 	int ret;
 
 	kenter("");
@@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
 	if (ret < 0)
 		return ret;
 
-	pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
-	if (IS_ERR(pkcs7))
-		return PTR_ERR(pkcs7);
-	ctx.pkcs7 = pkcs7;
-
-	ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false);
-	if (ret < 0 || datalen == 0) {
-		pr_devel("PKCS#7 message does not contain data\n");
-		ret = -EBADMSG;
-		goto error;
-	}
-
-	ret = mscode_parse(&ctx);
+	ret = verify_pkcs7_signature(NULL, 0,
+				     pebuf + ctx.sig_offset, ctx.sig_len,
+				     trusted_keys, -EKEYREJECTED, usage,
+				     mscode_parse, &ctx);
 	if (ret < 0)
 		goto error;
 
@@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
 	 * contents.
 	 */
 	ret = pefile_digest_pe(pebuf, pelen, &ctx);
-	if (ret < 0)
-		goto error;
-
-	ret = pkcs7_verify(pkcs7, usage);
-	if (ret < 0)
-		goto error;
-
-	ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted);
 
 error:
-	pkcs7_free_message(ctx.pkcs7);
+	kfree(ctx.digest);
 	return ret;
 }
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h
index 55d5f7ebc45a..d6341d5406d4 100644
--- a/crypto/asymmetric_keys/verify_pefile.h
+++ b/crypto/asymmetric_keys/verify_pefile.h
@@ -9,7 +9,6 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
-#include <linux/verify_pefile.h>
 #include <crypto/pkcs7.h>
 #include <crypto/hash_info.h>
 
@@ -23,7 +22,6 @@ struct pefile_context {
 	unsigned	sig_offset;
 	unsigned	sig_len;
 	const struct section_header *secs;
-	struct pkcs7_message *pkcs7;
 
 	/* PKCS#7 MS Individual Code Signing content */
 	const void	*digest;		/* Digest */
@@ -39,4 +37,5 @@ struct pefile_context {
 /*
  * mscode_parser.c
  */
-extern int mscode_parse(struct pefile_context *ctx);
+extern int mscode_parse(void *_ctx, const void *content_data, size_t data_len,
+			size_t asn1hdrlen);
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
index 441aff9b5aa7..8323e3e57131 100644
--- a/include/crypto/pkcs7.h
+++ b/include/crypto/pkcs7.h
@@ -12,6 +12,7 @@
 #ifndef _CRYPTO_PKCS7_H
 #define _CRYPTO_PKCS7_H
 
+#include <linux/verification.h>
 #include <crypto/public_key.h>
 
 struct key;
@@ -26,7 +27,7 @@ extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
 
 extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
 				  const void **_data, size_t *_datalen,
-				  bool want_wrapper);
+				  size_t *_headerlen);
 
 /*
  * pkcs7_trust.c
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index cc2516df0efa..de50d026576d 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -39,20 +39,6 @@ enum pkey_id_type {
 extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
 
 /*
- * The use to which an asymmetric key is being put.
- */
-enum key_being_used_for {
-	VERIFYING_MODULE_SIGNATURE,
-	VERIFYING_FIRMWARE_SIGNATURE,
-	VERIFYING_KEXEC_PE_SIGNATURE,
-	VERIFYING_KEY_SIGNATURE,
-	VERIFYING_KEY_SELF_SIGNATURE,
-	VERIFYING_UNSPECIFIED_SIGNATURE,
-	NR__KEY_BEING_USED_FOR
-};
-extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
-
-/*
  * Cryptographic data for the public-key subtype of the asymmetric key type.
  *
  * Note that this may include private part of the key as well as the public
diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
index 59c1df9cf922..72c18c1f3308 100644
--- a/include/keys/asymmetric-type.h
+++ b/include/keys/asymmetric-type.h
@@ -15,6 +15,7 @@
 #define _KEYS_ASYMMETRIC_TYPE_H
 
 #include <linux/key-type.h>
+#include <linux/verification.h>
 
 extern struct key_type key_type_asymmetric;
 
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index e8334d299314..707229245c8f 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -15,6 +15,7 @@
 #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
 
 #include <linux/key.h>
+#include <linux/verification.h>
 #include <crypto/public_key.h>
 
 extern struct key *system_trusted_keyring;
@@ -29,12 +30,6 @@ static inline struct key *get_system_trusted_keyring(void)
 }
 #endif
 
-#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
-extern int system_verify_data(const void *data, unsigned long len,
-			      const void *raw_pkcs7, size_t pkcs7_len,
-			      enum key_being_used_for usage);
-#endif
-
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
 extern int mark_hash_blacklisted(const char *hash);
 extern int is_hash_blacklisted(const char *hash);
diff --git a/include/linux/verification.h b/include/linux/verification.h
new file mode 100644
index 000000000000..bb0fcf941cb7
--- /dev/null
+++ b/include/linux/verification.h
@@ -0,0 +1,50 @@
+/* Signature verification
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_VERIFICATION_H
+#define _LINUX_VERIFICATION_H
+
+/*
+ * The use to which an asymmetric key is being put.
+ */
+enum key_being_used_for {
+	VERIFYING_MODULE_SIGNATURE,
+	VERIFYING_FIRMWARE_SIGNATURE,
+	VERIFYING_KEXEC_PE_SIGNATURE,
+	VERIFYING_KEY_SIGNATURE,
+	VERIFYING_KEY_SELF_SIGNATURE,
+	VERIFYING_UNSPECIFIED_SIGNATURE,
+	NR__KEY_BEING_USED_FOR
+};
+extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
+
+#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
+
+struct key;
+
+extern int verify_pkcs7_signature(const void *data, size_t len,
+				  const void *raw_pkcs7, size_t pkcs7_len,
+				  struct key *trusted_keys,
+				  int untrusted_error,
+				  enum key_being_used_for usage,
+				  int (*view_content)(void *ctx,
+						      const void *data, size_t len,
+						      size_t asn1hdrlen),
+				  void *ctx);
+
+#ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
+extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
+				   struct key *trusted_keys,
+				   enum key_being_used_for usage);
+#endif
+
+#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
+#endif /* _LINUX_VERIFY_PEFILE_H */
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h
deleted file mode 100644
index da2049b5161c..000000000000
--- a/include/linux/verify_pefile.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Signed PE file verification
- *
- * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#ifndef _LINUX_VERIFY_PEFILE_H
-#define _LINUX_VERIFY_PEFILE_H
-
-#include <crypto/public_key.h>
-
-extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
-				   struct key *trusted_keyring,
-				   enum key_being_used_for usage,
-				   bool *_trusted);
-
-#endif /* _LINUX_VERIFY_PEFILE_H */
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 6528a79d998d..70cf0220efeb 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -73,6 +73,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
 		return -EBADMSG;
 	}
 
-	return system_verify_data(mod, modlen, mod + modlen, sig_len,
-				  VERIFYING_MODULE_SIGNATURE);
+	return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+				      NULL, -ENOKEY, VERIFYING_MODULE_SIGNATURE,
+				      NULL, NULL);
 }

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 06/20] PKCS#7: Make trust determination dependent on contents of trust keyring [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (4 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 05/20] KEYS: Generalise system_verify_data() to provide access to internal content " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-01-19 11:31 ` [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a " David Howells
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Make the determination of the trustworthiness of a key dependent on whether
a key that can verify it is present in the ring of trusted keys rather than
whether or not the verifying key has KEY_FLAG_TRUSTED set.

verify_pkcs7_signature() will return -ENOKEY if the PKCS#7 message trust
chain cannot be verified.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/system_keyring.c                  |   13 ++++---------
 crypto/asymmetric_keys/pkcs7_key_type.c |    2 +-
 crypto/asymmetric_keys/pkcs7_parser.h   |    1 -
 crypto/asymmetric_keys/pkcs7_trust.c    |   16 +++-------------
 crypto/asymmetric_keys/verify_pefile.c  |    2 +-
 crypto/asymmetric_keys/x509_parser.h    |    1 -
 include/crypto/pkcs7.h                  |    3 +--
 include/linux/verification.h            |    1 -
 kernel/module_signing.c                 |    2 +-
 9 files changed, 11 insertions(+), 30 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index a83bffedc0aa..dc18869ff680 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -121,7 +121,6 @@ late_initcall(load_system_certificate_list);
 int verify_pkcs7_signature(const void *data, size_t len,
 			   const void *raw_pkcs7, size_t pkcs7_len,
 			   struct key *trusted_keys,
-			   int untrusted_error,
 			   enum key_being_used_for usage,
 			   int (*view_content)(void *ctx,
 					       const void *data, size_t len,
@@ -129,7 +128,6 @@ int verify_pkcs7_signature(const void *data, size_t len,
 			   void *ctx)
 {
 	struct pkcs7_message *pkcs7;
-	bool trusted;
 	int ret;
 
 	pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
@@ -149,13 +147,10 @@ int verify_pkcs7_signature(const void *data, size_t len,
 
 	if (!trusted_keys)
 		trusted_keys = system_trusted_keyring;
-	ret = pkcs7_validate_trust(pkcs7, trusted_keys, &trusted);
-	if (ret < 0)
-		goto error;
-
-	if (!trusted && untrusted_error) {
-		pr_err("PKCS#7 signature not signed with a trusted key\n");
-		ret = untrusted_error;
+	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
+	if (ret < 0) {
+		if (ret == -ENOKEY)
+			pr_err("PKCS#7 signature not signed with a trusted key\n");
 		goto error;
 	}
 
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c
index b74aaaefbc07..a684e7ca4f13 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -71,7 +71,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
 
 	ret = verify_pkcs7_signature(NULL, 0,
 				     prep->data, prep->datalen,
-				     NULL, -ENOKEY, usage,
+				     NULL, usage,
 				     pkcs7_view_content, prep);
 
 	kleave(" = %d", ret);
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index a66b19ebcf47..c8159983ed8f 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -22,7 +22,6 @@ struct pkcs7_signed_info {
 	struct pkcs7_signed_info *next;
 	struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
 	unsigned	index;
-	bool		trusted;
 	bool		unsupported_crypto;	/* T if not usable due to missing crypto */
 
 	/* Message digest - the digest of the Content Data (or NULL) */
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 90d6d47965b0..388007fed3b2 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -30,7 +30,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	struct public_key_signature *sig = &sinfo->sig;
 	struct x509_certificate *x509, *last = NULL, *p;
 	struct key *key;
-	bool trusted;
 	int ret;
 
 	kenter(",%u,", sinfo->index);
@@ -42,10 +41,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
 	for (x509 = sinfo->signer; x509; x509 = x509->signer) {
 		if (x509->seen) {
-			if (x509->verified) {
-				trusted = x509->trusted;
+			if (x509->verified)
 				goto verified;
-			}
 			kleave(" = -ENOKEY [cached]");
 			return -ENOKEY;
 		}
@@ -122,7 +119,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
 matched:
 	ret = verify_signature(key, sig);
-	trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
 	key_put(key);
 	if (ret < 0) {
 		if (ret == -ENOMEM)
@@ -134,12 +130,9 @@ matched:
 verified:
 	if (x509) {
 		x509->verified = true;
-		for (p = sinfo->signer; p != x509; p = p->signer) {
+		for (p = sinfo->signer; p != x509; p = p->signer)
 			p->verified = true;
-			p->trusted = trusted;
-		}
 	}
-	sinfo->trusted = trusted;
 	kleave(" = 0");
 	return 0;
 }
@@ -148,7 +141,6 @@ verified:
  * pkcs7_validate_trust - Validate PKCS#7 trust chain
  * @pkcs7: The PKCS#7 certificate to validate
  * @trust_keyring: Signing certificates to use as starting points
- * @_trusted: Set to true if trustworth, false otherwise
  *
  * Validate that the certificate chain inside the PKCS#7 message intersects
  * keys we already know and trust.
@@ -170,8 +162,7 @@ verified:
  * May also return -ENOMEM.
  */
 int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
-			 struct key *trust_keyring,
-			 bool *_trusted)
+			 struct key *trust_keyring)
 {
 	struct pkcs7_signed_info *sinfo;
 	struct x509_certificate *p;
@@ -191,7 +182,6 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
 				cached_ret = -ENOPKG;
 			continue;
 		case 0:
-			*_trusted |= sinfo->trusted;
 			cached_ret = 0;
 			continue;
 		default:
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 443a00f9cd7a..4112f922cc66 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -436,7 +436,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
 
 	ret = verify_pkcs7_signature(NULL, 0,
 				     pebuf + ctx.sig_offset, ctx.sig_len,
-				     trusted_keys, -EKEYREJECTED, usage,
+				     trusted_keys, usage,
 				     mscode_parse, &ctx);
 	if (ret < 0)
 		goto error;
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index be7cf2eae3bd..b9108c170ceb 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -41,7 +41,6 @@ struct x509_certificate {
 	unsigned	index;
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
-	bool		trusted;
 	bool		unsupported_crypto;	/* T if can't be verified due to missing crypto */
 	bool		blacklisted;
 };
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
index 8323e3e57131..583f199400a3 100644
--- a/include/crypto/pkcs7.h
+++ b/include/crypto/pkcs7.h
@@ -33,8 +33,7 @@ extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
  * pkcs7_trust.c
  */
 extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
-				struct key *trust_keyring,
-				bool *_trusted);
+				struct key *trust_keyring);
 
 /*
  * pkcs7_verify.c
diff --git a/include/linux/verification.h b/include/linux/verification.h
index bb0fcf941cb7..a10549a6c7cd 100644
--- a/include/linux/verification.h
+++ b/include/linux/verification.h
@@ -33,7 +33,6 @@ struct key;
 extern int verify_pkcs7_signature(const void *data, size_t len,
 				  const void *raw_pkcs7, size_t pkcs7_len,
 				  struct key *trusted_keys,
-				  int untrusted_error,
 				  enum key_being_used_for usage,
 				  int (*view_content)(void *ctx,
 						      const void *data, size_t len,
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 70cf0220efeb..b3dafe4fd320 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -74,6 +74,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
 	}
 
 	return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
-				      NULL, -ENOKEY, VERIFYING_MODULE_SIGNATURE,
+				      NULL, VERIFYING_MODULE_SIGNATURE,
 				      NULL, NULL);
 }

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a keyring [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (5 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 06/20] PKCS#7: Make trust determination dependent on contents of trust keyring " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-02-08 11:59   ` Mimi Zohar
  2016-02-29 15:49   ` David Howells
  2016-01-19 11:31 ` [RFC PATCH 08/20] KEYS: Allow authentication data to be stored in an asymmetric key " David Howells
                   ` (16 subsequent siblings)
  23 siblings, 2 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Add a facility whereby proposed new links to be added to a keyring can be
vetted, permitting them to be rejected if necessary.  This can be used to
block public keys from which the signature cannot be verified or for which
the signature verification fails.  It could also be used to provide
blacklisting.

This affects operations like add_key(), KEYCTL_LINK and KEYCTL_INSTANTIATE.

To this end:

 (1) A function pointer is added to the key struct that, if set, points to
     the vetting function.  This is called as:

	int (*restrict_link)(struct key *keyring,
			     const struct key_type *key_type,
			     unsigned long key_flags,
			     const union key_payload *key_payload),

     where 'keyring' will be the keyring being added to, key_type and
     key_payload will describe the key being added and key_flags[*] can be
     AND'ed with KEY_FLAG_TRUSTED.

     [*] This parameter will be removed in a later patch when
     	 KEY_FLAG_TRUSTED is removed.

     The function should return 0 to allow the link to take place or an
     error (typically -ENOKEY, -ENOPKG or -EKEYREJECTED) to reject the
     link.

     The pointer should not be set directly, but rather should be set
     through keyring_alloc().

     Note that if called during add_key(), preparse is called before this
     method, but a key isn't actually allocated until after this function
     is called.

 (2) KEY_ALLOC_BYPASS_RESTRICTION is added.  This can be passed to
     key_create_or_update() or key_instantiate_and_link() to bypass the
     restriction check.

 (3) KEY_FLAG_TRUSTED_ONLY is removed.  The entire contents of a keyring
     with this restriction emplaced can be considered 'trustworthy' by
     virtue of being in the keyring when that keyring is consulted.

 (4) key_alloc() and keyring_alloc() take an extra argument that will be
     used to set restrict_link in the new key.  This ensures that the
     pointer is set before the key is published, thus preventing a window
     of unrestrictedness.  Normally this argument will be NULL.

 (5) As a temporary affair, keyring_restrict_trusted_only() is added.  It
     should be passed to keyring_alloc() as the extra argument instead of
     setting KEY_FLAG_TRUSTED_ONLY on a keyring.  This will be replaced in
     a later patch with functions that look in the appropriate places for
     authoritative keys.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 Documentation/security/keys.txt  |   14 ++++++++++
 certs/blacklist.c                |    2 +
 certs/system_keyring.c           |    8 +++---
 fs/cifs/cifsacl.c                |    2 +
 fs/nfs/nfs4idmap.c               |    2 +
 include/linux/key.h              |   48 ++++++++++++++++++++++++++++-------
 net/dns_resolver/dns_key.c       |    2 +
 net/rxrpc/ar-key.c               |    4 +--
 security/integrity/digsig.c      |    7 ++---
 security/integrity/ima/ima_mok.c |    8 +++---
 security/keys/key.c              |   43 ++++++++++++++++++++++++++-----
 security/keys/keyring.c          |   52 +++++++++++++++++++++++++++++++++-----
 security/keys/persistent.c       |    4 +--
 security/keys/process_keys.c     |   16 +++++++-----
 security/keys/request_key.c      |    4 +--
 security/keys/request_key_auth.c |    2 +
 16 files changed, 165 insertions(+), 53 deletions(-)

diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 8c183873b2b7..3e2e958f2091 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -999,6 +999,10 @@ payload contents" for more information.
 	struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
 				  const struct cred *cred,
 				  key_perm_t perm,
+				  int (*restrict_link)(struct key *,
+						       const struct key_type *,
+						       unsigned long,
+						       const union key_payload *),
 				  unsigned long flags,
 				  struct key *dest);
 
@@ -1010,6 +1014,16 @@ payload contents" for more information.
     KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
     towards the user's quota).  Error ENOMEM can also be returned.
 
+    If restrict_link not NULL, it should point to a function will be called to
+    vet all attempts to link keys into the keyring, though this can be
+    overridden by passing KEY_ALLOC_BYPASS_RESTRICTION to
+    key_create_or_update().
+
+    When called, the restriction function will be passed the keyring being
+    added to, the key flags value and the type and payload of the key being
+    added.  Note that when a new key is being created, this is called between
+    payload preparsing and actual key creation.
+
 
 (*) To check the validity of a key, this function can be called:
 
diff --git a/certs/blacklist.c b/certs/blacklist.c
index 5f54baae3a32..7f769479c17b 100644
--- a/certs/blacklist.c
+++ b/certs/blacklist.c
@@ -148,7 +148,7 @@ static int __init blacklist_init(void)
 			      KEY_USR_SEARCH,
 			      KEY_ALLOC_NOT_IN_QUOTA |
 			      KEY_FLAG_KEEP,
-			      NULL);
+			      NULL, NULL);
 	if (IS_ERR(blacklist_keyring))
 		panic("Can't allocate system blacklist keyring\n");
 
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index dc18869ff680..417d65882870 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -36,11 +36,10 @@ static __init int system_trusted_keyring_init(void)
 			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
 			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
-			      KEY_ALLOC_NOT_IN_QUOTA, NULL);
+			      KEY_ALLOC_NOT_IN_QUOTA,
+			      keyring_restrict_trusted_only, NULL);
 	if (IS_ERR(system_trusted_keyring))
 		panic("Can't allocate system trusted keyring\n");
-
-	set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
 	return 0;
 }
 
@@ -85,7 +84,8 @@ static __init int load_system_certificate_list(void)
 					   KEY_USR_VIEW | KEY_USR_READ),
 					   KEY_ALLOC_NOT_IN_QUOTA |
 					   KEY_ALLOC_TRUSTED |
-					   KEY_ALLOC_BUILT_IN);
+					   KEY_ALLOC_BUILT_IN |
+					   KEY_ALLOC_BYPASS_RESTRICTION);
 		if (IS_ERR(key)) {
 			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
 			       PTR_ERR(key));
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 3f93125916bf..71e8a56e9479 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -360,7 +360,7 @@ init_cifs_idmap(void)
 				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
 				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				KEY_USR_VIEW | KEY_USR_READ,
-				KEY_ALLOC_NOT_IN_QUOTA, NULL);
+				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
 	if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
 		goto failed_put_cred;
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index 5ba22c6b0ffa..c444285bb1b1 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -201,7 +201,7 @@ int nfs_idmap_init(void)
 				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
 				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				KEY_USR_VIEW | KEY_USR_READ,
-				KEY_ALLOC_NOT_IN_QUOTA, NULL);
+				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
 	if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
 		goto failed_put_cred;
diff --git a/include/linux/key.h b/include/linux/key.h
index 5f5b1129dc92..c331b8bed035 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -174,10 +174,9 @@ struct key {
 #define KEY_FLAG_ROOT_CAN_CLEAR	6	/* set if key can be cleared by root without permission */
 #define KEY_FLAG_INVALIDATED	7	/* set if key has been invalidated */
 #define KEY_FLAG_TRUSTED	8	/* set if key is trusted */
-#define KEY_FLAG_TRUSTED_ONLY	9	/* set if keyring only accepts links to trusted keys */
-#define KEY_FLAG_BUILTIN	10	/* set if key is builtin */
-#define KEY_FLAG_ROOT_CAN_INVAL	11	/* set if key can be invalidated by root without permission */
-#define KEY_FLAG_KEEP		12	/* set if key should not be removed */
+#define KEY_FLAG_BUILTIN	9	/* set if key is built in to the kernel */
+#define KEY_FLAG_ROOT_CAN_INVAL	10	/* set if key can be invalidated by root without permission */
+#define KEY_FLAG_KEEP		11	/* set if key should not be removed */
 
 	/* the key type and key description string
 	 * - the desc is used to match a key against search criteria
@@ -205,6 +204,21 @@ struct key {
 		};
 		int reject_error;
 	};
+
+	/* This is set on a keyring to restrict the addition of a link to a key
+	 * to it.  If this method isn't provided then it is assumed that the
+	 * keyring is open to any addition.  It is ignored for non-keyring
+	 * keys.
+	 *
+	 * This is intended for use with rings of trusted keys whereby addition
+	 * to the keyring needs to be controlled.  KEY_ALLOC_BYPASS_RESTRICTION
+	 * overrides this, allowing the kernel to add extra keys without
+	 * restriction.
+	 */
+	int (*restrict_link)(struct key *keyring,
+			     const struct key_type *type,
+			     unsigned long flags,
+			     const union key_payload *payload);
 };
 
 extern struct key *key_alloc(struct key_type *type,
@@ -212,14 +226,19 @@ extern struct key *key_alloc(struct key_type *type,
 			     kuid_t uid, kgid_t gid,
 			     const struct cred *cred,
 			     key_perm_t perm,
-			     unsigned long flags);
+			     unsigned long flags,
+			     int (*restrict_link)(struct key *,
+						  const struct key_type *,
+						  unsigned long,
+						  const union key_payload *));
 
 
-#define KEY_ALLOC_IN_QUOTA	0x0000	/* add to quota, reject if would overrun */
-#define KEY_ALLOC_QUOTA_OVERRUN	0x0001	/* add to quota, permit even if overrun */
-#define KEY_ALLOC_NOT_IN_QUOTA	0x0002	/* not in quota */
-#define KEY_ALLOC_TRUSTED	0x0004	/* Key should be flagged as trusted */
-#define KEY_ALLOC_BUILT_IN	0x0008	/* Key is built into kernel */
+#define KEY_ALLOC_IN_QUOTA		0x0000	/* add to quota, reject if would overrun */
+#define KEY_ALLOC_QUOTA_OVERRUN		0x0001	/* add to quota, permit even if overrun */
+#define KEY_ALLOC_NOT_IN_QUOTA		0x0002	/* not in quota */
+#define KEY_ALLOC_TRUSTED		0x0004	/* Key should be flagged as trusted */
+#define KEY_ALLOC_BUILT_IN		0x0008	/* Key is built into kernel */
+#define KEY_ALLOC_BYPASS_RESTRICTION	0x0010	/* Override the check on restricted keyrings */
 
 extern void key_revoke(struct key *key);
 extern void key_invalidate(struct key *key);
@@ -288,8 +307,17 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid
 				 const struct cred *cred,
 				 key_perm_t perm,
 				 unsigned long flags,
+				 int (*restrict_link)(struct key *,
+						      const struct key_type *,
+						      unsigned long,
+						      const union key_payload *),
 				 struct key *dest);
 
+extern int keyring_restrict_trusted_only(struct key *keyring,
+					 const struct key_type *type,
+					 unsigned long,
+					 const union key_payload *payload);
+
 extern int keyring_clear(struct key *keyring);
 
 extern key_ref_t keyring_search(key_ref_t keyring,
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index c79b85eb4d4c..8737412c7b27 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -281,7 +281,7 @@ static int __init init_dns_resolver(void)
 				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
 				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				KEY_USR_VIEW | KEY_USR_READ,
-				KEY_ALLOC_NOT_IN_QUOTA, NULL);
+				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
 	if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
 		goto failed_put_cred;
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index 3f6571651d32..b8e87a16c544 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -965,7 +965,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
 
 	key = key_alloc(&key_type_rxrpc, "x",
 			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
-			KEY_ALLOC_NOT_IN_QUOTA);
+			KEY_ALLOC_NOT_IN_QUOTA, NULL);
 	if (IS_ERR(key)) {
 		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
 		return -ENOMEM;
@@ -1012,7 +1012,7 @@ struct key *rxrpc_get_null_key(const char *keyname)
 
 	key = key_alloc(&key_type_rxrpc, keyname,
 			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
-			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
+			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
 	if (IS_ERR(key))
 		return key;
 
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 8ef15118cc78..659566c2200b 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -83,10 +83,9 @@ int __init integrity_init_keyring(const unsigned int id)
 				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				     KEY_USR_VIEW | KEY_USR_READ |
 				     KEY_USR_WRITE | KEY_USR_SEARCH),
-				    KEY_ALLOC_NOT_IN_QUOTA, NULL);
-	if (!IS_ERR(keyring[id]))
-		set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
-	else {
+				    KEY_ALLOC_NOT_IN_QUOTA,
+				    NULL, NULL);
+	if (IS_ERR(keyring[id])) {
 		err = PTR_ERR(keyring[id]);
 		pr_info("Can't allocate %s keyring (%d)\n",
 			keyring_name[id], err);
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index 676885e4320e..ef91248cb934 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -35,20 +35,20 @@ __init int ima_mok_init(void)
 			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
 			      KEY_USR_VIEW | KEY_USR_READ |
 			      KEY_USR_WRITE | KEY_USR_SEARCH,
-			      KEY_ALLOC_NOT_IN_QUOTA, NULL);
+			      KEY_ALLOC_NOT_IN_QUOTA,
+			      keyring_restrict_trusted_only, NULL);
 
 	ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
 				KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
 				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				KEY_USR_VIEW | KEY_USR_READ |
 				KEY_USR_WRITE | KEY_USR_SEARCH,
-				KEY_ALLOC_NOT_IN_QUOTA, NULL);
+				KEY_ALLOC_NOT_IN_QUOTA,
+				keyring_restrict_trusted_only, NULL);
 
 	if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
 		panic("Can't allocate IMA MOK or blacklist keyrings.");
-	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags);
 
-	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags);
 	set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
 	return 0;
 }
diff --git a/security/keys/key.c b/security/keys/key.c
index 48dbfa543bcb..23b271b1834d 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -201,6 +201,7 @@ serial_exists:
  * @cred: The credentials specifying UID namespace.
  * @perm: The permissions mask of the new key.
  * @flags: Flags specifying quota properties.
+ * @restrict_link: Optional link restriction method for new keyrings.
  *
  * Allocate a key of the specified type with the attributes given.  The key is
  * returned in an uninstantiated state and the caller needs to instantiate the
@@ -223,7 +224,11 @@ serial_exists:
  */
 struct key *key_alloc(struct key_type *type, const char *desc,
 		      kuid_t uid, kgid_t gid, const struct cred *cred,
-		      key_perm_t perm, unsigned long flags)
+		      key_perm_t perm, unsigned long flags,
+		      int (*restrict_link)(struct key *,
+					   const struct key_type *,
+					   unsigned long,
+					   const union key_payload *))
 {
 	struct key_user *user = NULL;
 	struct key *key;
@@ -291,6 +296,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 	key->uid = uid;
 	key->gid = gid;
 	key->perm = perm;
+	key->restrict_link = restrict_link;
 
 	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
 		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
@@ -495,6 +501,12 @@ int key_instantiate_and_link(struct key *key,
 	}
 
 	if (keyring) {
+		if (keyring->restrict_link) {
+			ret = keyring->restrict_link(keyring, key->type,
+						     key->flags, &prep.payload);
+			if (ret < 0)
+				goto error;
+		}
 		ret = __key_link_begin(keyring, &key->index_key, &edit);
 		if (ret < 0)
 			goto error;
@@ -550,8 +562,12 @@ int key_reject_and_link(struct key *key,
 	awaken = 0;
 	ret = -EBUSY;
 
-	if (keyring)
+	if (keyring) {
+		if (keyring->restrict_link)
+			return -EPERM;
+
 		link_ret = __key_link_begin(keyring, &key->index_key, &edit);
+	}
 
 	mutex_lock(&key_construction_mutex);
 
@@ -792,6 +808,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	struct key *keyring, *key = NULL;
 	key_ref_t key_ref;
 	int ret;
+	int (*restrict_link)(struct key *,
+			     const struct key_type *,
+			     unsigned long,
+			     const union key_payload *) = NULL;
 
 	/* look up the key type to see if it's one of the registered kernel
 	 * types */
@@ -810,6 +830,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 
 	key_check(keyring);
 
+	key_ref = ERR_PTR(-EPERM);
+	if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION))
+		restrict_link = keyring->restrict_link;
+
 	key_ref = ERR_PTR(-ENOTDIR);
 	if (keyring->type != &key_type_keyring)
 		goto error_put_type;
@@ -834,10 +858,15 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	}
 	index_key.desc_len = strlen(index_key.description);
 
-	key_ref = ERR_PTR(-EPERM);
-	if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags))
-		goto error_free_prep;
-	flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0;
+	if (restrict_link) {
+		unsigned long kflags = prep.trusted ? KEY_FLAG_TRUSTED : 0;
+		ret = restrict_link(keyring,
+				    index_key.type, kflags, &prep.payload);
+		if (ret < 0) {
+			key_ref = ERR_PTR(ret);
+			goto error_free_prep;
+		}
+	}
 
 	ret = __key_link_begin(keyring, &index_key, &edit);
 	if (ret < 0) {
@@ -878,7 +907,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 
 	/* allocate a new key */
 	key = key_alloc(index_key.type, index_key.description,
-			cred->fsuid, cred->fsgid, cred, perm, flags);
+			cred->fsuid, cred->fsgid, cred, perm, flags, NULL);
 	if (IS_ERR(key)) {
 		key_ref = ERR_CAST(key);
 		goto error_link_end;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index f931ccfeefb0..ea023ca6d217 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -491,13 +491,18 @@ static long keyring_read(const struct key *keyring,
  */
 struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 			  const struct cred *cred, key_perm_t perm,
-			  unsigned long flags, struct key *dest)
+			  unsigned long flags,
+			  int (*restrict_link)(struct key *,
+					       const struct key_type *,
+					       unsigned long,
+					       const union key_payload *),
+			  struct key *dest)
 {
 	struct key *keyring;
 	int ret;
 
 	keyring = key_alloc(&key_type_keyring, description,
-			    uid, gid, cred, perm, flags);
+			    uid, gid, cred, perm, flags, restrict_link);
 	if (!IS_ERR(keyring)) {
 		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
 		if (ret < 0) {
@@ -510,6 +515,30 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 }
 EXPORT_SYMBOL(keyring_alloc);
 
+/**
+ * keyring_restrict_trusted_only - Restrict additions to a keyring to trusted keys only
+ * @keyring: The keyring being added to.
+ * @type: The type of key being added.
+ * @flags: The key flags.
+ * @payload: The payload of the key intended to be added.
+ *
+ * Reject the addition of any links to a keyring that point to keys that aren't
+ * marked as being trusted.  It can be overridden by passing
+ * KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when adding a key
+ * to a keyring.
+ *
+ * This is meant to be passed as the restrict_link parameter to
+ * keyring_alloc().
+ */
+int keyring_restrict_trusted_only(struct key *keyring,
+				  const struct key_type *type,
+				  unsigned long flags,
+				  const union key_payload *payload)
+{
+	
+	return flags & KEY_FLAG_TRUSTED ? 0 : -EPERM;
+}
+
 /*
  * By default, we keys found by getting an exact match on their descriptions.
  */
@@ -1191,6 +1220,17 @@ void __key_link_end(struct key *keyring,
 	up_write(&keyring->sem);
 }
 
+/*
+ * Check addition of keys to restricted keyrings.
+ */
+static int __key_link_check_restriction(struct key *keyring, struct key *key)
+{
+	if (!keyring->restrict_link)
+		return 0;
+	return keyring->restrict_link(keyring,
+				      key->type, key->flags, &key->payload);
+}
+
 /**
  * key_link - Link a key to a keyring
  * @keyring: The keyring to make the link in.
@@ -1221,14 +1261,12 @@ int key_link(struct key *keyring, struct key *key)
 	key_check(keyring);
 	key_check(key);
 
-	if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) &&
-	    !test_bit(KEY_FLAG_TRUSTED, &key->flags))
-		return -EPERM;
-
 	ret = __key_link_begin(keyring, &key->index_key, &edit);
 	if (ret == 0) {
 		kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage));
-		ret = __key_link_check_live_key(keyring, key);
+		ret = __key_link_check_restriction(keyring, key);
+		if (ret == 0)
+			ret = __key_link_check_live_key(keyring, key);
 		if (ret == 0)
 			__key_link(key, &edit);
 		__key_link_end(keyring, &key->index_key, edit);
diff --git a/security/keys/persistent.c b/security/keys/persistent.c
index c9fae5ea89fe..2ef45b319dd9 100644
--- a/security/keys/persistent.c
+++ b/security/keys/persistent.c
@@ -26,7 +26,7 @@ static int key_create_persistent_register(struct user_namespace *ns)
 					current_cred(),
 					((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 					 KEY_USR_VIEW | KEY_USR_READ),
-					KEY_ALLOC_NOT_IN_QUOTA, NULL);
+					KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
 	if (IS_ERR(reg))
 		return PTR_ERR(reg);
 
@@ -60,7 +60,7 @@ static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid,
 				   uid, INVALID_GID, current_cred(),
 				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				    KEY_USR_VIEW | KEY_USR_READ),
-				   KEY_ALLOC_NOT_IN_QUOTA,
+				   KEY_ALLOC_NOT_IN_QUOTA, NULL,
 				   ns->persistent_keyring_register);
 	if (IS_ERR(persistent))
 		return ERR_CAST(persistent);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index a3f85d2a00bb..9bb6bb5fd845 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -76,7 +76,8 @@ int install_user_keyrings(void)
 		if (IS_ERR(uid_keyring)) {
 			uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
 						    cred, user_keyring_perm,
-						    KEY_ALLOC_IN_QUOTA, NULL);
+						    KEY_ALLOC_IN_QUOTA,
+						    NULL, NULL);
 			if (IS_ERR(uid_keyring)) {
 				ret = PTR_ERR(uid_keyring);
 				goto error;
@@ -92,7 +93,8 @@ int install_user_keyrings(void)
 			session_keyring =
 				keyring_alloc(buf, user->uid, INVALID_GID,
 					      cred, user_keyring_perm,
-					      KEY_ALLOC_IN_QUOTA, NULL);
+					      KEY_ALLOC_IN_QUOTA,
+					      NULL, NULL);
 			if (IS_ERR(session_keyring)) {
 				ret = PTR_ERR(session_keyring);
 				goto error_release;
@@ -134,7 +136,8 @@ int install_thread_keyring_to_cred(struct cred *new)
 
 	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
 				KEY_POS_ALL | KEY_USR_VIEW,
-				KEY_ALLOC_QUOTA_OVERRUN, NULL);
+				KEY_ALLOC_QUOTA_OVERRUN,
+				NULL, NULL);
 	if (IS_ERR(keyring))
 		return PTR_ERR(keyring);
 
@@ -180,7 +183,8 @@ int install_process_keyring_to_cred(struct cred *new)
 
 	keyring = keyring_alloc("_pid", new->uid, new->gid, new,
 				KEY_POS_ALL | KEY_USR_VIEW,
-				KEY_ALLOC_QUOTA_OVERRUN, NULL);
+				KEY_ALLOC_QUOTA_OVERRUN,
+				NULL, NULL);
 	if (IS_ERR(keyring))
 		return PTR_ERR(keyring);
 
@@ -231,7 +235,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 
 		keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
 					KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
-					flags, NULL);
+					flags, NULL, NULL);
 		if (IS_ERR(keyring))
 			return PTR_ERR(keyring);
 	} else {
@@ -785,7 +789,7 @@ long join_session_keyring(const char *name)
 		keyring = keyring_alloc(
 			name, old->uid, old->gid, old,
 			KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK,
-			KEY_ALLOC_IN_QUOTA, NULL);
+			KEY_ALLOC_IN_QUOTA, NULL, NULL);
 		if (IS_ERR(keyring)) {
 			ret = PTR_ERR(keyring);
 			goto error2;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index c7a117c9a8f3..a29e3554751e 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -116,7 +116,7 @@ static int call_sbin_request_key(struct key_construction *cons,
 	cred = get_current_cred();
 	keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
 				KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
-				KEY_ALLOC_QUOTA_OVERRUN, NULL);
+				KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL);
 	put_cred(cred);
 	if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
@@ -355,7 +355,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
 
 	key = key_alloc(ctx->index_key.type, ctx->index_key.description,
 			ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
-			perm, flags);
+			perm, flags, NULL);
 	if (IS_ERR(key))
 		goto alloc_failed;
 
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 4f0f112fe276..9db8b4a82787 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -202,7 +202,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
 	authkey = key_alloc(&key_type_request_key_auth, desc,
 			    cred->fsuid, cred->fsgid, cred,
 			    KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
-			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
+			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL);
 	if (IS_ERR(authkey)) {
 		ret = PTR_ERR(authkey);
 		goto error_alloc;

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 08/20] KEYS: Allow authentication data to be stored in an asymmetric key [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (6 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-01-19 11:31 ` [RFC PATCH 09/20] KEYS: Add identifier pointers to public_key_signature struct " David Howells
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Allow authentication data to be stored in an asymmetric key in the 4th
element of the key payload and provide a way for it to be destroyed.

For the public key subtype, this will be a public_key_signature struct.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/asymmetric_type.c  |    7 +++++--
 crypto/asymmetric_keys/public_key.c       |   22 +++++++++++++++++++---
 crypto/asymmetric_keys/x509_cert_parser.c |    2 +-
 include/crypto/public_key.h               |    5 +++--
 include/keys/asymmetric-subtype.h         |    2 +-
 include/keys/asymmetric-type.h            |    7 ++++---
 6 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 9f2165b27d52..a79d30128821 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -331,7 +331,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 	pr_devel("==>%s()\n", __func__);
 
 	if (subtype) {
-		subtype->destroy(prep->payload.data[asym_crypto]);
+		subtype->destroy(prep->payload.data[asym_crypto],
+				 prep->payload.data[asym_auth]);
 		module_put(subtype->owner);
 	}
 	asymmetric_key_free_kids(kids);
@@ -346,13 +347,15 @@ static void asymmetric_key_destroy(struct key *key)
 	struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
 	struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
 	void *data = key->payload.data[asym_crypto];
+	void *auth = key->payload.data[asym_auth];
 
 	key->payload.data[asym_crypto] = NULL;
 	key->payload.data[asym_subtype] = NULL;
 	key->payload.data[asym_key_ids] = NULL;
+	key->payload.data[asym_auth] = NULL;
 
 	if (subtype) {
-		subtype->destroy(data);
+		subtype->destroy(data, auth);
 		module_put(subtype->owner);
 	}
 
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 6db4c01c6503..e537aaeafdbf 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -59,18 +59,34 @@ static void public_key_describe(const struct key *asymmetric_key,
 /*
  * Destroy a public key algorithm key.
  */
-void public_key_destroy(void *payload)
+void public_key_free(struct public_key *key,
+		     struct public_key_signature *sig)
 {
-	struct public_key *key = payload;
 	int i;
 
 	if (key) {
 		for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
 			mpi_free(key->mpi[i]);
 		kfree(key);
+		key = NULL;
 	}
+
+	if (sig) {
+		for (i = 0; i < ARRAY_SIZE(sig->mpi); i++)
+			mpi_free(sig->mpi[i]);
+		kfree(sig->digest);
+		kfree(sig);
+	}
+}
+EXPORT_SYMBOL_GPL(public_key_free);
+
+/*
+ * Destroy a public key algorithm key.
+ */
+static void public_key_destroy(void *payload0, void *payload3)
+{
+	public_key_free(payload0, payload3);
 }
-EXPORT_SYMBOL_GPL(public_key_destroy);
 
 /*
  * Verify a signature using a public key.
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 021d39c0ba75..74152f1e99eb 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -48,7 +48,7 @@ struct x509_parse_context {
 void x509_free_certificate(struct x509_certificate *cert)
 {
 	if (cert) {
-		public_key_destroy(cert->pub);
+		public_key_free(cert->pub, NULL);
 		kfree(cert->issuer);
 		kfree(cert->subject);
 		kfree(cert->id);
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index de50d026576d..a3f8f8268e23 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -72,8 +72,6 @@ struct public_key {
 	};
 };
 
-extern void public_key_destroy(void *payload);
-
 /*
  * Public key cryptography signature data
  */
@@ -95,6 +93,9 @@ struct public_key_signature {
 	};
 };
 
+extern void public_key_free(struct public_key *key,
+			    struct public_key_signature *sig);
+
 struct key;
 extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h
index 4915d40d3c3c..2480469ce8fb 100644
--- a/include/keys/asymmetric-subtype.h
+++ b/include/keys/asymmetric-subtype.h
@@ -32,7 +32,7 @@ struct asymmetric_key_subtype {
 	void (*describe)(const struct key *key, struct seq_file *m);
 
 	/* Destroy a key of this subtype */
-	void (*destroy)(void *payload);
+	void (*destroy)(void *payload_crypto, void *payload_auth);
 
 	/* Verify the signature on a key of this subtype (optional) */
 	int (*verify_signature)(const struct key *key,
diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
index 72c18c1f3308..d1e23dda4363 100644
--- a/include/keys/asymmetric-type.h
+++ b/include/keys/asymmetric-type.h
@@ -24,9 +24,10 @@ extern struct key_type key_type_asymmetric;
  * follows:
  */
 enum asymmetric_payload_bits {
-	asym_crypto,
-	asym_subtype,
-	asym_key_ids,
+	asym_crypto,		/* The data representing the key */
+	asym_subtype,		/* Pointer to an asymmetric_key_subtype struct */
+	asym_key_ids,		/* Pointer to an asymmetric_key_ids struct */
+	asym_auth		/* The key's authorisation (signature, parent key ID) */
 };
 
 /*

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 09/20] KEYS: Add identifier pointers to public_key_signature struct [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (7 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 08/20] KEYS: Allow authentication data to be stored in an asymmetric key " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-01-19 11:31 ` [RFC PATCH 10/20] X.509: Retain the key verification data " David Howells
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Add key identifier pointers to public_key_signature struct so that they can
be used to retain the identifier of the key to be used to verify the
signature in both PKCS#7 and X.509.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/public_key.c |    2 ++
 include/crypto/public_key.h         |    1 +
 2 files changed, 3 insertions(+)

diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index e537aaeafdbf..f5b4824b7c77 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -72,6 +72,8 @@ void public_key_free(struct public_key *key,
 	}
 
 	if (sig) {
+		for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
+			kfree(sig->auth_ids[i]);
 		for (i = 0; i < ARRAY_SIZE(sig->mpi); i++)
 			mpi_free(sig->mpi[i]);
 		kfree(sig->digest);
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index a3f8f8268e23..ed86bfb23e89 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -76,6 +76,7 @@ struct public_key {
  * Public key cryptography signature data
  */
 struct public_key_signature {
+	struct asymmetric_key_id *auth_ids[2];
 	u8 *digest;
 	u8 digest_size;			/* Number of bytes in digest */
 	u8 nr_mpi;			/* Occupancy of mpi[] */

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 10/20] X.509: Retain the key verification data [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (8 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 09/20] KEYS: Add identifier pointers to public_key_signature struct " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-01-19 11:31 ` [RFC PATCH 11/20] X.509: Extract signature digest and make self-signed cert checks earlier " David Howells
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Retain the key verification data (ie. the struct public_key_signature)
including the digest and the key identifiers.

Note that this means that we need to take a separate copy of the digest in
x509_get_sig_params() rather than lumping it in with the crypto layer data.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/pkcs7_trust.c      |    8 ++--
 crypto/asymmetric_keys/pkcs7_verify.c     |   20 +++++----
 crypto/asymmetric_keys/x509_cert_parser.c |   41 +++++++++---------
 crypto/asymmetric_keys/x509_parser.h      |    4 --
 crypto/asymmetric_keys/x509_public_key.c  |   66 +++++++++++++++--------------
 5 files changed, 70 insertions(+), 69 deletions(-)

diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 388007fed3b2..7bb9389fd644 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -77,16 +77,16 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
 		might_sleep();
 		last = x509;
-		sig = &last->sig;
+		sig = last->sig;
 	}
 
 	/* No match - see if the root certificate has a signer amongst the
 	 * trusted keys.
 	 */
-	if (last && (last->akid_id || last->akid_skid)) {
+	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
 		key = x509_request_asymmetric_key(trust_keyring,
-						  last->akid_id,
-						  last->akid_skid,
+						  last->sig->auth_ids[0],
+						  last->sig->auth_ids[1],
 						  false);
 		if (!IS_ERR(key)) {
 			x509 = last;
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 325575caf6b4..8af45c5d4b6d 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -176,6 +176,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 				  struct pkcs7_signed_info *sinfo)
 {
+	struct public_key_signature *sig;
 	struct x509_certificate *x509 = sinfo->signer, *p;
 	struct asymmetric_key_id *auth;
 	int ret;
@@ -195,14 +196,15 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 			goto maybe_missing_crypto_in_x509;
 
 		pr_debug("- issuer %s\n", x509->issuer);
-		if (x509->akid_id)
+		sig = x509->sig;
+		if (sig->auth_ids[0])
 			pr_debug("- authkeyid.id %*phN\n",
-				 x509->akid_id->len, x509->akid_id->data);
-		if (x509->akid_skid)
+				 sig->auth_ids[0]->len, sig->auth_ids[0]->data);
+		if (sig->auth_ids[1])
 			pr_debug("- authkeyid.skid %*phN\n",
-				 x509->akid_skid->len, x509->akid_skid->data);
+				 sig->auth_ids[1]->len, sig->auth_ids[1]->data);
 
-		if ((!x509->akid_id && !x509->akid_skid) ||
+		if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) ||
 		    strcmp(x509->subject, x509->issuer) == 0) {
 			/* If there's no authority certificate specified, then
 			 * the certificate must be self-signed and is the root
@@ -226,7 +228,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		/* Look through the X.509 certificates in the PKCS#7 message's
 		 * list to see if the next one is there.
 		 */
-		auth = x509->akid_id;
+		auth = sig->auth_ids[0];
 		if (auth) {
 			pr_debug("- want %*phN\n", auth->len, auth->data);
 			for (p = pkcs7->certs; p; p = p->next) {
@@ -236,7 +238,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 					goto found_issuer_check_skid;
 			}
 		} else {
-			auth = x509->akid_skid;
+			auth = sig->auth_ids[1];
 			pr_debug("- want %*phN\n", auth->len, auth->data);
 			for (p = pkcs7->certs; p; p = p->next) {
 				if (!p->skid)
@@ -256,8 +258,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		/* We matched issuer + serialNumber, but if there's an
 		 * authKeyId.keyId, that must match the CA subjKeyId also.
 		 */
-		if (x509->akid_skid &&
-		    !asymmetric_key_id_same(p->skid, x509->akid_skid)) {
+		if (sig->auth_ids[1] &&
+		    !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) {
 			pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
 				sinfo->index, x509->index, p->index);
 			return -EKEYREJECTED;
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 74152f1e99eb..c32912c1d84d 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -48,15 +48,11 @@ struct x509_parse_context {
 void x509_free_certificate(struct x509_certificate *cert)
 {
 	if (cert) {
-		public_key_free(cert->pub, NULL);
+		public_key_free(cert->pub, cert->sig);
 		kfree(cert->issuer);
 		kfree(cert->subject);
 		kfree(cert->id);
 		kfree(cert->skid);
-		kfree(cert->akid_id);
-		kfree(cert->akid_skid);
-		kfree(cert->sig.digest);
-		mpi_free(cert->sig.rsa.s);
 		kfree(cert);
 	}
 }
@@ -79,6 +75,9 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
 	if (!cert->pub)
 		goto error_no_ctx;
+	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
+	if (!cert->sig)
+		goto error_no_ctx;
 	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
 	if (!ctx)
 		goto error_no_ctx;
@@ -188,33 +187,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
 		return -ENOPKG; /* Unsupported combination */
 
 	case OID_md4WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_MD5;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_MD5;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha1WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA1;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA1;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha256WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA256;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA256;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha384WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA384;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA384;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha512WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA512;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA512;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha224WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA224;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA224;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 	}
 
@@ -595,14 +594,14 @@ int x509_akid_note_kid(void *context, size_t hdrlen,
 
 	pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
 
-	if (ctx->cert->akid_skid)
+	if (ctx->cert->sig->auth_ids[1])
 		return 0;
 
 	kid = asymmetric_key_generate_id(value, vlen, "", 0);
 	if (IS_ERR(kid))
 		return PTR_ERR(kid);
 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
-	ctx->cert->akid_skid = kid;
+	ctx->cert->sig->auth_ids[1] = kid;
 	return 0;
 }
 
@@ -634,7 +633,7 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
 
 	pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
 
-	if (!ctx->akid_raw_issuer || ctx->cert->akid_id)
+	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
 		return 0;
 
 	kid = asymmetric_key_generate_id(value,
@@ -645,6 +644,6 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
 		return PTR_ERR(kid);
 
 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
-	ctx->cert->akid_id = kid;
+	ctx->cert->sig->auth_ids[0] = kid;
 	return 0;
 }
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index b9108c170ceb..600df3bebed4 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -17,13 +17,11 @@ struct x509_certificate {
 	struct x509_certificate *next;
 	struct x509_certificate *signer;	/* Certificate that signed this one */
 	struct public_key *pub;			/* Public key details */
-	struct public_key_signature sig;	/* Signature parameters */
+	struct public_key_signature *sig;	/* Signature parameters */
 	char		*issuer;		/* Name of certificate issuer */
 	char		*subject;		/* Name of certificate subject */
 	struct asymmetric_key_id *id;		/* Issuer + Serial number */
 	struct asymmetric_key_id *skid;		/* Subject + subjectKeyId (optional) */
-	struct asymmetric_key_id *akid_id;	/* CA AuthKeyId matching ->id (optional) */
-	struct asymmetric_key_id *akid_skid;	/* CA AuthKeyId matching ->skid (optional) */
 	time64_t	valid_from;
 	time64_t	valid_to;
 	const void	*tbs;			/* Signed data */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 630c1c331fe1..8626e84450e4 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -157,28 +157,28 @@ EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
  */
 int x509_get_sig_params(struct x509_certificate *cert)
 {
+	struct public_key_signature *sig = cert->sig;
 	struct crypto_shash *tfm;
 	struct shash_desc *desc;
-	size_t digest_size, desc_size;
-	void *digest;
+	size_t desc_size;
 	int ret;
 
 	pr_devel("==>%s()\n", __func__);
 
 	if (cert->unsupported_crypto)
 		return -ENOPKG;
-	if (cert->sig.rsa.s)
+	if (sig->rsa.s)
 		return 0;
 
-	cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
-	if (!cert->sig.rsa.s)
+	sig->rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
+	if (!sig->rsa.s)
 		return -ENOMEM;
-	cert->sig.nr_mpi = 1;
+	sig->nr_mpi = 1;
 
 	/* Allocate the hashing algorithm we're going to need and find out how
 	 * big the hash operational data will be.
 	 */
-	tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
+	tfm = crypto_alloc_shash(hash_algo_name[sig->pkey_hash_algo], 0, 0);
 	if (IS_ERR(tfm)) {
 		if (PTR_ERR(tfm) == -ENOENT) {
 			cert->unsupported_crypto = true;
@@ -188,39 +188,38 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	}
 
 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
-	digest_size = crypto_shash_digestsize(tfm);
+	sig->digest_size = crypto_shash_digestsize(tfm);
 
-	/* We allocate the hash operational data storage on the end of the
-	 * digest storage space.
-	 */
 	ret = -ENOMEM;
-	digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
-			 GFP_KERNEL);
-	if (!digest)
+	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
+	if (!sig->digest)
 		goto error;
 
-	cert->sig.digest = digest;
-	cert->sig.digest_size = digest_size;
+	desc = kzalloc(desc_size, GFP_KERNEL);
+	if (!desc)
+		goto error;
 
-	desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
 	desc->tfm = tfm;
 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
 	ret = crypto_shash_init(desc);
 	if (ret < 0)
-		goto error;
+		goto error_2;
 	might_sleep();
-	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
+	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
 	if (ret < 0)
-		goto error;
+		goto error_2;
 
-	ret = is_bin_hash_blacklisted(digest, digest_size);
+	ret = is_bin_hash_blacklisted(sig->digest, sig->digest_size);
 	if (ret == -EKEYREJECTED) {
-		pr_err("Cert %*phN is blacklisted\n", (int)digest_size, digest);
+		pr_err("Cert %*phN is blacklisted\n",
+		       sig->digest_size, sig->digest);
 		cert->blacklisted = true;
 		ret = 0;
 	}
 
+error_2:
+	kfree(desc);
 error:
 	crypto_free_shash(tfm);
 	pr_devel("<==%s() = %d\n", __func__, ret);
@@ -242,7 +241,7 @@ int x509_check_signature(const struct public_key *pub,
 	if (ret < 0)
 		return ret;
 
-	ret = public_key_verify_signature(pub, &cert->sig);
+	ret = public_key_verify_signature(pub, cert->sig);
 	if (ret == -ENOPKG)
 		cert->unsupported_crypto = true;
 	pr_debug("Cert Verification: %d\n", ret);
@@ -262,20 +261,21 @@ EXPORT_SYMBOL_GPL(x509_check_signature);
 static int x509_validate_trust(struct x509_certificate *cert,
 			       struct key *trust_keyring)
 {
+	struct public_key_signature *sig = cert->sig;
 	struct key *key;
 	int ret = 1;
 
-	if (!cert->akid_id && !cert->akid_skid)
+	if (!sig->auth_ids[0] && !sig->auth_ids[1])
 		return 1;
 
 	if (!trust_keyring)
 		return -EOPNOTSUPP;
 
-	if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
+	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
 		return -EPERM;
 
 	key = x509_request_asymmetric_key(trust_keyring,
-					  cert->akid_id, cert->akid_skid,
+					  sig->auth_ids[0], sig->auth_ids[1],
 					  false);
 	if (!IS_ERR(key))  {
 		if (!use_builtin_keys
@@ -307,11 +307,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	pr_devel("Cert Subject: %s\n", cert->subject);
 
 	if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
-	    cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
-	    cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
+	    cert->sig->pkey_algo >= PKEY_ALGO__LAST ||
+	    cert->sig->pkey_hash_algo >= PKEY_HASH__LAST ||
 	    !pkey_algo[cert->pub->pkey_algo] ||
-	    !pkey_algo[cert->sig.pkey_algo] ||
-	    !hash_algo_name[cert->sig.pkey_hash_algo]) {
+	    !pkey_algo[cert->sig->pkey_algo] ||
+	    !hash_algo_name[cert->sig->pkey_hash_algo]) {
 		ret = -ENOPKG;
 		goto error_free_cert;
 	}
@@ -319,8 +319,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
 	pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
 	pr_devel("Cert Signature: %s + %s\n",
-		 pkey_algo_name[cert->sig.pkey_algo],
-		 hash_algo_name[cert->sig.pkey_hash_algo]);
+		 pkey_algo_name[cert->sig->pkey_algo],
+		 hash_algo_name[cert->sig->pkey_hash_algo]);
 
 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
 	cert->pub->id_type = PKEY_ID_X509;
@@ -381,6 +381,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	prep->payload.data[asym_subtype] = &public_key_subtype;
 	prep->payload.data[asym_key_ids] = kids;
 	prep->payload.data[asym_crypto] = cert->pub;
+	prep->payload.data[asym_auth] = cert->sig;
 	prep->description = desc;
 	prep->quotalen = 100;
 
@@ -388,6 +389,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	cert->pub = NULL;
 	cert->id = NULL;
 	cert->skid = NULL;
+	cert->sig = NULL;
 	desc = NULL;
 	ret = 0;
 

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 11/20] X.509: Extract signature digest and make self-signed cert checks earlier [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (9 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 10/20] X.509: Retain the key verification data " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-01-19 11:31 ` [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it " David Howells
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Extract the signature digest for an X.509 certificate earlier, at the end
of x509_cert_parse() rather than leaving it to the callers thereof.

Further, immediately after that, check the signature on self-signed
certificates, also rather in the callers of x509_cert_parse().

This we need to determine whether or not the X.509 cert requires crypto
that we don't support before we do the above two steps.

We note in the x509_certificate struct the following bits of information:

 (1) Whether the signature is self-signed (even if we can't check the
     signature due to missing crypto).

 (2) Whether the key held in the certificate needs unsupported crypto to be
     used.  We may get a PKCS#7 message with X.509 certs that we can't make
     use of - we just ignore them and give ENOPKG at the end it we couldn't
     verify anything if at least one of these unusable certs are in the
     chain of trust.

 (3) Whether the signature held in the certificate needs unsupported crypto
     to be checked.  We can still use the key held in this certificate,
     even if we can't check the signature on it - if it is held in the
     system trusted keyring, for instance.  We just can't add it to a ring
     of trusted keys or follow it further up the chain of trust.

Making these checks earlier allows x509_check_signature() to be removed and
replaced with direct calls to public_key_verify_signature().

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/pkcs7_verify.c     |   38 ++-------
 crypto/asymmetric_keys/x509_cert_parser.c |   10 ++
 crypto/asymmetric_keys/x509_parser.h      |    7 +-
 crypto/asymmetric_keys/x509_public_key.c  |  118 +++++++++++++++++++++--------
 4 files changed, 108 insertions(+), 65 deletions(-)

diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 8af45c5d4b6d..0d1173081b5c 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -191,9 +191,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 			 x509->subject,
 			 x509->raw_serial_size, x509->raw_serial);
 		x509->seen = true;
-		ret = x509_get_sig_params(x509);
-		if (ret < 0)
-			goto maybe_missing_crypto_in_x509;
+		if (x509->unsupported_key)
+			goto unsupported_crypto_in_x509;
 
 		pr_debug("- issuer %s\n", x509->issuer);
 		sig = x509->sig;
@@ -204,22 +203,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 			pr_debug("- authkeyid.skid %*phN\n",
 				 sig->auth_ids[1]->len, sig->auth_ids[1]->data);
 
-		if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) ||
-		    strcmp(x509->subject, x509->issuer) == 0) {
+		if (x509->self_signed) {
 			/* If there's no authority certificate specified, then
 			 * the certificate must be self-signed and is the root
 			 * of the chain.  Likewise if the cert is its own
 			 * authority.
 			 */
-			pr_debug("- no auth?\n");
-			if (x509->raw_subject_size != x509->raw_issuer_size ||
-			    memcmp(x509->raw_subject, x509->raw_issuer,
-				   x509->raw_issuer_size) != 0)
-				return 0;
-
-			ret = x509_check_signature(x509->pub, x509);
-			if (ret < 0)
-				goto maybe_missing_crypto_in_x509;
+			if (x509->unsupported_sig)
+				goto unsupported_crypto_in_x509;
 			x509->signer = x509;
 			pr_debug("- self-signed\n");
 			return 0;
@@ -271,7 +262,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 				sinfo->index);
 			return 0;
 		}
-		ret = x509_check_signature(p->pub, x509);
+		ret = public_key_verify_signature(p->pub, p->sig);
 		if (ret < 0)
 			return ret;
 		x509->signer = p;
@@ -283,16 +274,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		might_sleep();
 	}
 
-maybe_missing_crypto_in_x509:
+unsupported_crypto_in_x509:
 	/* Just prune the certificate chain at this point if we lack some
 	 * crypto module to go further.  Note, however, we don't want to set
-	 * sinfo->missing_crypto as the signed info block may still be
+	 * sinfo->unsupported_crypto as the signed info block may still be
 	 * validatable against an X.509 cert lower in the chain that we have a
 	 * trusted copy of.
 	 */
-	if (ret == -ENOPKG)
-		return 0;
-	return ret;
+	return 0;
 }
 
 /*
@@ -379,9 +368,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
 		 enum key_being_used_for usage)
 {
 	struct pkcs7_signed_info *sinfo;
-	struct x509_certificate *x509;
 	int enopkg = -ENOPKG;
-	int ret, n;
+	int ret;
 
 	kenter("");
 
@@ -423,12 +411,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
 		return -EINVAL;
 	}
 
-	for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
-		ret = x509_get_sig_params(x509);
-		if (ret < 0)
-			return ret;
-	}
-
 	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
 		ret = pkcs7_verify_one(pkcs7, sinfo);
 		if (ret < 0) {
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index c32912c1d84d..5bfaf1112a15 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -108,6 +108,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 	if (ret < 0)
 		goto error_decode;
 
+	/* Grab the signature bits */
+	ret = x509_get_sig_params(cert);
+	if (ret < 0)
+		goto error_decode;
+
 	/* Generate cert issuer + serial number key ID */
 	kid = asymmetric_key_generate_id(cert->raw_serial,
 					 cert->raw_serial_size,
@@ -119,6 +124,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 	}
 	cert->id = kid;
 
+	/* Detect self-signed certificates */
+	ret = x509_check_for_self_signed(cert);
+	if (ret < 0)
+		goto error_decode;
+
 	kfree(ctx);
 	return cert;
 
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 600df3bebed4..e373e7483812 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -39,7 +39,9 @@ struct x509_certificate {
 	unsigned	index;
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
-	bool		unsupported_crypto;	/* T if can't be verified due to missing crypto */
+	bool		self_signed;		/* T if self-signed (check unsupported_sig too) */
+	bool		unsupported_key;	/* T if key uses unsupported crypto */
+	bool		unsupported_sig;	/* T if signature uses unsupported crypto */
 	bool		blacklisted;
 };
 
@@ -56,5 +58,4 @@ extern int x509_decode_time(time64_t *_t,  size_t hdrlen,
  * x509_public_key.c
  */
 extern int x509_get_sig_params(struct x509_certificate *cert);
-extern int x509_check_signature(const struct public_key *pub,
-				struct x509_certificate *cert);
+extern int x509_check_for_self_signed(struct x509_certificate *cert);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 8626e84450e4..00aef0d121b2 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -165,10 +165,20 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
 	pr_devel("==>%s()\n", __func__);
 
-	if (cert->unsupported_crypto)
-		return -ENOPKG;
-	if (sig->rsa.s)
+	if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
+	    !pkey_algo[cert->pub->pkey_algo])
+		cert->unsupported_key = true;
+
+	if (sig->pkey_algo >= PKEY_ALGO__LAST ||
+	    !pkey_algo[sig->pkey_algo])
+		cert->unsupported_sig = true;
+
+	/* We check the hash if we can - even if we can't then verify it */
+	if (sig->pkey_hash_algo >= PKEY_HASH__LAST ||
+	    !hash_algo_name[sig->pkey_hash_algo]) {
+		cert->unsupported_sig = true;
 		return 0;
+	}
 
 	sig->rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
 	if (!sig->rsa.s)
@@ -181,8 +191,8 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	tfm = crypto_alloc_shash(hash_algo_name[sig->pkey_hash_algo], 0, 0);
 	if (IS_ERR(tfm)) {
 		if (PTR_ERR(tfm) == -ENOENT) {
-			cert->unsupported_crypto = true;
-			return -ENOPKG;
+			cert->unsupported_sig = true;
+			return 0;
 		}
 		return PTR_ERR(tfm);
 	}
@@ -228,26 +238,60 @@ error:
 EXPORT_SYMBOL_GPL(x509_get_sig_params);
 
 /*
- * Check the signature on a certificate using the provided public key
+ * Check for self-signedness in an X.509 cert and if found, check the signature
+ * immediately if we can.
  */
-int x509_check_signature(const struct public_key *pub,
-			 struct x509_certificate *cert)
+int x509_check_for_self_signed(struct x509_certificate *cert)
 {
-	int ret;
+	int ret = 0;
 
 	pr_devel("==>%s()\n", __func__);
 
-	ret = x509_get_sig_params(cert);
-	if (ret < 0)
-		return ret;
+	if (cert->raw_subject_size != cert->raw_issuer_size ||
+	    memcmp(cert->raw_subject, cert->raw_issuer,
+		   cert->raw_issuer_size) != 0)
+		goto not_self_signed;
+
+	if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) {
+		/* If the AKID is present it may have one or two parts.  If
+		 * both are supplied, both must match.
+		 */
+		bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]);
+		bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]);
+
+		if (!a && !b)
+			goto not_self_signed;
+
+		ret = -EKEYREJECTED;
+		if (((a && !b) || (b && !a)) &&
+		    cert->sig->auth_ids[0] && cert->sig->auth_ids[1])
+			goto out;
+	}
 
-	ret = public_key_verify_signature(pub, cert->sig);
-	if (ret == -ENOPKG)
-		cert->unsupported_crypto = true;
-	pr_debug("Cert Verification: %d\n", ret);
+	ret = -EKEYREJECTED;
+	if (cert->pub->pkey_algo != cert->sig->pkey_algo)
+		goto out;
+
+	ret = public_key_verify_signature(cert->pub, cert->sig);
+	if (ret < 0) {
+		if (ret == -ENOPKG) {
+			cert->unsupported_sig = true;
+			ret = 0;
+		}
+		goto out;
+	}
+
+	pr_devel("Cert Self-signature verified");
+	cert->self_signed = true;
+
+out:
+	pr_devel("<==%s() = %d\n", __func__, ret);
 	return ret;
+
+not_self_signed:
+	pr_devel("<==%s() = 0 [not]\n", __func__);
+	return 0;
 }
-EXPORT_SYMBOL_GPL(x509_check_signature);
 
 /*
  * Check the new certificate against the ones in the trust keyring.  If one of
@@ -270,20 +314,25 @@ static int x509_validate_trust(struct x509_certificate *cert,
 
 	if (!trust_keyring)
 		return -EOPNOTSUPP;
-
 	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
 		return -EPERM;
+	if (cert->unsupported_sig)
+		return -ENOPKG;
 
 	key = x509_request_asymmetric_key(trust_keyring,
 					  sig->auth_ids[0], sig->auth_ids[1],
 					  false);
-	if (!IS_ERR(key))  {
-		if (!use_builtin_keys
-		    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
-			ret = x509_check_signature(key->payload.data[asym_crypto],
-						   cert);
-		key_put(key);
+	if (IS_ERR(key))
+		return PTR_ERR(key);
+
+	if (!use_builtin_keys ||
+	    test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
+		ret = public_key_verify_signature(
+			key->payload.data[asym_crypto], cert->sig);
+		if (ret == -ENOPKG)
+			cert->unsupported_sig = true;
 	}
+	key_put(key);
 	return ret;
 }
 
@@ -306,21 +355,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	pr_devel("Cert Issuer: %s\n", cert->issuer);
 	pr_devel("Cert Subject: %s\n", cert->subject);
 
-	if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
-	    cert->sig->pkey_algo >= PKEY_ALGO__LAST ||
-	    cert->sig->pkey_hash_algo >= PKEY_HASH__LAST ||
-	    !pkey_algo[cert->pub->pkey_algo] ||
-	    !pkey_algo[cert->sig->pkey_algo] ||
-	    !hash_algo_name[cert->sig->pkey_hash_algo]) {
+	if (cert->unsupported_key) {
 		ret = -ENOPKG;
 		goto error_free_cert;
 	}
 
 	pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
 	pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
-	pr_devel("Cert Signature: %s + %s\n",
-		 pkey_algo_name[cert->sig->pkey_algo],
-		 hash_algo_name[cert->sig->pkey_hash_algo]);
 
 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
 	cert->pub->id_type = PKEY_ID_X509;
@@ -336,10 +377,19 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	 * cert that we have (most likely a duplicate that we already trust) -
 	 * in which case it will be marked trusted.
 	 */
-	if (!prep->trusted) {
+	if (cert->unsupported_sig || cert->self_signed) {
+		public_key_free(NULL, cert->sig);
+		cert->sig = NULL;
+	} else {
+		pr_devel("Cert Signature: %s + %s\n",
+			 pkey_algo_name[cert->sig->pkey_algo],
+			 hash_algo_name[cert->sig->pkey_hash_algo]);
+
 		ret = x509_validate_trust(cert, get_system_trusted_keyring());
 		if (ret)
 			ret = x509_validate_trust(cert, get_ima_mok_keyring());
+		if (ret == -EKEYREJECTED)
+			goto error_free_cert;
 		if (!ret)
 			prep->trusted = true;
 	}

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (10 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 11/20] X.509: Extract signature digest and make self-signed cert checks earlier " David Howells
@ 2016-01-19 11:31 ` David Howells
  2016-02-08 12:00   ` Mimi Zohar
  2016-02-19 11:56   ` David Howells
  2016-01-19 11:32 ` [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file " David Howells
                   ` (11 subsequent siblings)
  23 siblings, 2 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:31 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Point to the public_key_signature struct from the pkcs7_signed_info struct
rather than embedding it.  This makes it easier to have it take an
arbitrary number of MPIs in future.

We also save a copy of the digest in the signature without sharing the
memory with the crypto layer metadata.  This means we can use
public_key_free() to get rid of the signature record.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/pkcs7_parser.c |   38 ++++++++++++++----------
 crypto/asymmetric_keys/pkcs7_parser.h |   10 ++----
 crypto/asymmetric_keys/pkcs7_trust.c  |    4 +-
 crypto/asymmetric_keys/pkcs7_verify.c |   53 +++++++++++++++++----------------
 4 files changed, 56 insertions(+), 49 deletions(-)

diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 7b69783cff99..8454ae5b5aa8 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -44,9 +44,7 @@ struct pkcs7_parse_context {
 static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
 {
 	if (sinfo) {
-		mpi_free(sinfo->sig.mpi[0]);
-		kfree(sinfo->sig.digest);
-		kfree(sinfo->signing_cert_id);
+		public_key_free(NULL, sinfo->sig);
 		kfree(sinfo);
 	}
 }
@@ -125,6 +123,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
 	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 	if (!ctx->sinfo)
 		goto out_no_sinfo;
+	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
+				  GFP_KERNEL);
+	if (!ctx->sinfo->sig)
+		goto out_no_sig;
 
 	ctx->data = (unsigned long)data;
 	ctx->ppcerts = &ctx->certs;
@@ -150,6 +152,7 @@ out:
 		ctx->certs = cert->next;
 		x509_free_certificate(cert);
 	}
+out_no_sig:
 	pkcs7_free_signed_info(ctx->sinfo);
 out_no_sinfo:
 	pkcs7_free_message(ctx->msg);
@@ -219,25 +222,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
 
 	switch (ctx->last_oid) {
 	case OID_md4:
-		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4;
+		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_MD4;
 		break;
 	case OID_md5:
-		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5;
+		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_MD5;
 		break;
 	case OID_sha1:
-		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1;
+		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA1;
 		break;
 	case OID_sha256:
-		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
+		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA256;
 		break;
 	case OID_sha384:
-		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384;
+		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA384;
 		break;
 	case OID_sha512:
-		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512;
+		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA512;
 		break;
 	case OID_sha224:
-		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224;
+		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA224;
 	default:
 		printk("Unsupported digest algo: %u\n", ctx->last_oid);
 		return -ENOPKG;
@@ -256,7 +259,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
 
 	switch (ctx->last_oid) {
 	case OID_rsaEncryption:
-		ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->sinfo->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 	default:
 		printk("Unsupported pkey algo: %u\n", ctx->last_oid);
@@ -617,16 +620,17 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen,
 			     const void *value, size_t vlen)
 {
 	struct pkcs7_parse_context *ctx = context;
+	struct public_key_signature *sig = ctx->sinfo->sig;
 	MPI mpi;
 
-	BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
+	BUG_ON(sig->pkey_algo != PKEY_ALGO_RSA);
 
 	mpi = mpi_read_raw_data(value, vlen);
 	if (!mpi)
 		return -ENOMEM;
 
-	ctx->sinfo->sig.mpi[0] = mpi;
-	ctx->sinfo->sig.nr_mpi = 1;
+	sig->mpi[0] = mpi;
+	sig->nr_mpi = 1;
 	return 0;
 }
 
@@ -662,12 +666,16 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
 
 	pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
 
-	sinfo->signing_cert_id = kid;
+	sinfo->sig->auth_ids[0] = kid;
 	sinfo->index = ++ctx->sinfo_index;
 	*ctx->ppsinfo = sinfo;
 	ctx->ppsinfo = &sinfo->next;
 	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 	if (!ctx->sinfo)
 		return -ENOMEM;
+	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
+				  GFP_KERNEL);
+	if (!ctx->sinfo->sig)
+		return -ENOMEM;
 	return 0;
 }
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index c8159983ed8f..f4e81074f5e0 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -40,19 +40,17 @@ struct pkcs7_signed_info {
 #define	sinfo_has_ms_statement_type	5
 	time64_t	signing_time;
 
-	/* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
-	 * or issuing cert's SKID [CMS ver 3].
-	 */
-	struct asymmetric_key_id *signing_cert_id;
-
 	/* Message signature.
 	 *
 	 * This contains the generated digest of _either_ the Content Data or
 	 * the Authenticated Attributes [RFC2315 9.3].  If the latter, one of
 	 * the attributes contains the digest of the the Content Data within
 	 * it.
+	 *
+	 * THis also contains the issuing cert serial number and issuer's name
+	 * [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3].
 	 */
-	struct public_key_signature sig;
+	struct public_key_signature *sig;
 };
 
 struct pkcs7_message {
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 7bb9389fd644..400ef359448a 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -27,7 +27,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 				    struct pkcs7_signed_info *sinfo,
 				    struct key *trust_keyring)
 {
-	struct public_key_signature *sig = &sinfo->sig;
+	struct public_key_signature *sig = sinfo->sig;
 	struct x509_certificate *x509, *last = NULL, *p;
 	struct key *key;
 	int ret;
@@ -102,7 +102,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	 * the signed info directly.
 	 */
 	key = x509_request_asymmetric_key(trust_keyring,
-					  sinfo->signing_cert_id,
+					  sinfo->sig->auth_ids[0],
 					  NULL,
 					  false);
 	if (!IS_ERR(key)) {
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 0d1173081b5c..3b8124c2cd91 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -25,36 +25,38 @@
 static int pkcs7_digest(struct pkcs7_message *pkcs7,
 			struct pkcs7_signed_info *sinfo)
 {
+	struct public_key_signature *sig = sinfo->sig;
 	struct crypto_shash *tfm;
 	struct shash_desc *desc;
-	size_t digest_size, desc_size;
-	void *digest;
+	size_t desc_size;
 	int ret;
 
-	kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
+	kenter(",%u,%u", sinfo->index, sig->pkey_hash_algo);
 
-	if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
-	    !hash_algo_name[sinfo->sig.pkey_hash_algo])
+	if (sig->pkey_hash_algo >= PKEY_HASH__LAST ||
+	    !hash_algo_name[sig->pkey_hash_algo])
 		return -ENOPKG;
 
 	/* Allocate the hashing algorithm we're going to need and find out how
 	 * big the hash operational data will be.
 	 */
-	tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo],
+	tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig->pkey_hash_algo],
 				 0, 0);
 	if (IS_ERR(tfm))
 		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
 
 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
-	sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
+	sig->digest_size = crypto_shash_digestsize(tfm);
 
 	ret = -ENOMEM;
-	digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
-			 GFP_KERNEL);
-	if (!digest)
+	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
+	if (!sig->digest)
+		goto error_no_desc;
+
+	desc = kzalloc(desc_size, GFP_KERNEL);
+	if (!desc)
 		goto error_no_desc;
 
-	desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
 	desc->tfm   = tfm;
 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
@@ -62,10 +64,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	ret = crypto_shash_init(desc);
 	if (ret < 0)
 		goto error;
-	ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
+	ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len,
+				 sig->digest);
 	if (ret < 0)
 		goto error;
-	pr_devel("MsgDigest = [%*ph]\n", 8, digest);
+	pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
 
 	/* However, if there are authenticated attributes, there must be a
 	 * message digest attribute amongst them which corresponds to the
@@ -80,14 +83,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 			goto error;
 		}
 
-		if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
+		if (sinfo->msgdigest_len != sig->digest_size) {
 			pr_debug("Sig %u: Invalid digest size (%u)\n",
 				 sinfo->index, sinfo->msgdigest_len);
 			ret = -EBADMSG;
 			goto error;
 		}
 
-		if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
+		if (memcmp(sig->digest, sinfo->msgdigest,
+			   sinfo->msgdigest_len) != 0) {
 			pr_debug("Sig %u: Message digest doesn't match\n",
 				 sinfo->index);
 			ret = -EKEYREJECTED;
@@ -99,7 +103,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 		 * convert the attributes from a CONT.0 into a SET before we
 		 * hash it.
 		 */
-		memset(digest, 0, sinfo->sig.digest_size);
+		memset(sig->digest, 0, sig->digest_size);
 
 		ret = crypto_shash_init(desc);
 		if (ret < 0)
@@ -109,17 +113,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 		if (ret < 0)
 			goto error;
 		ret = crypto_shash_finup(desc, sinfo->authattrs,
-					 sinfo->authattrs_len, digest);
+					 sinfo->authattrs_len, sig->digest);
 		if (ret < 0)
 			goto error;
-		pr_devel("AADigest = [%*ph]\n", 8, digest);
+		pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
 	}
 
-	sinfo->sig.digest = digest;
-	digest = NULL;
-
 error:
-	kfree(digest);
+	kfree(desc);
 error_no_desc:
 	crypto_free_shash(tfm);
 	kleave(" = %d", ret);
@@ -146,12 +147,12 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 		 * PKCS#7 message - but I can't be 100% sure of that.  It's
 		 * possible this will need element-by-element comparison.
 		 */
-		if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
+		if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0]))
 			continue;
 		pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
 			 sinfo->index, certix);
 
-		if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
+		if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) {
 			pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
 				sinfo->index);
 			continue;
@@ -166,7 +167,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 	 */
 	pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
 		 sinfo->index,
-		 sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
+		 sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data);
 	return 0;
 }
 
@@ -325,7 +326,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 	}
 
 	/* Verify the PKCS#7 binary against the key */
-	ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
+	ret = public_key_verify_signature(sinfo->signer->pub, sinfo->sig);
 	if (ret < 0)
 		return ret;
 

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (11 preceding siblings ...)
  2016-01-19 11:31 ` [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-02-08 11:59   ` Mimi Zohar
  2016-01-19 11:32 ` [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() " David Howells
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Move the X.509 trust validation code out to its own file so that it can be
generalised.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/Makefile           |    2 
 crypto/asymmetric_keys/public_key_trust.c |  195 +++++++++++++++++++++++++++++
 crypto/asymmetric_keys/x509_parser.h      |    6 +
 crypto/asymmetric_keys/x509_public_key.c  |  170 -------------------------
 4 files changed, 202 insertions(+), 171 deletions(-)
 create mode 100644 crypto/asymmetric_keys/public_key_trust.c

diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index cd1406f9b14a..3f291bbf7b74 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
 
 asymmetric_keys-y := asymmetric_type.o signature.o
 
-obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o public_key_trust.o
 obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
 
 #
diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
new file mode 100644
index 000000000000..9febe612e659
--- /dev/null
+++ b/crypto/asymmetric_keys/public_key_trust.c
@@ -0,0 +1,195 @@
+/* Instantiate a public key crypto key from an X.509 Certificate
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "X.509: "fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/mpi.h>
+#include <linux/asn1_decoder.h>
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+#include <keys/system_keyring.h>
+#include <crypto/hash.h>
+#include "asymmetric_keys.h"
+#include "public_key.h"
+#include "x509_parser.h"
+
+static bool use_builtin_keys;
+static struct asymmetric_key_id *ca_keyid;
+
+#ifndef MODULE
+static struct {
+	struct asymmetric_key_id id;
+	unsigned char data[10];
+} cakey;
+
+static int __init ca_keys_setup(char *str)
+{
+	if (!str)		/* default system keyring */
+		return 1;
+
+	if (strncmp(str, "id:", 3) == 0) {
+		struct asymmetric_key_id *p = &cakey.id;
+		size_t hexlen = (strlen(str) - 3) / 2;
+		int ret;
+
+		if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
+			pr_err("Missing or invalid ca_keys id\n");
+			return 1;
+		}
+
+		ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
+		if (ret < 0)
+			pr_err("Unparsable ca_keys id hex string\n");
+		else
+			ca_keyid = p;	/* owner key 'id:xxxxxx' */
+	} else if (strcmp(str, "builtin") == 0) {
+		use_builtin_keys = true;
+	}
+
+	return 1;
+}
+__setup("ca_keys=", ca_keys_setup);
+#endif
+
+/**
+ * x509_request_asymmetric_key - Request a key by X.509 certificate params.
+ * @keyring: The keys to search.
+ * @id: The issuer & serialNumber to look for or NULL.
+ * @skid: The subjectKeyIdentifier to look for or NULL.
+ * @partial: Use partial match if true, exact if false.
+ *
+ * Find a key in the given keyring by identifier.  The preferred identifier is
+ * the issuer + serialNumber and the fallback identifier is the
+ * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
+ * the latter must also match.
+ */
+struct key *x509_request_asymmetric_key(struct key *keyring,
+					const struct asymmetric_key_id *id,
+					const struct asymmetric_key_id *skid,
+					bool partial)
+{
+	struct key *key;
+	key_ref_t ref;
+	const char *lookup;
+	char *req, *p;
+	int len;
+
+	if (id) {
+		lookup = id->data;
+		len = id->len;
+	} else {
+		lookup = skid->data;
+		len = skid->len;
+	}
+
+	/* Construct an identifier "id:<keyid>". */
+	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
+	if (!req)
+		return ERR_PTR(-ENOMEM);
+
+	if (partial) {
+		*p++ = 'i';
+		*p++ = 'd';
+	} else {
+		*p++ = 'e';
+		*p++ = 'x';
+	}
+	*p++ = ':';
+	p = bin2hex(p, lookup, len);
+	*p = 0;
+
+	pr_debug("Look up: \"%s\"\n", req);
+
+	ref = keyring_search(make_key_ref(keyring, 1),
+			     &key_type_asymmetric, req);
+	if (IS_ERR(ref))
+		pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
+	kfree(req);
+
+	if (IS_ERR(ref)) {
+		switch (PTR_ERR(ref)) {
+			/* Hide some search errors */
+		case -EACCES:
+		case -ENOTDIR:
+		case -EAGAIN:
+			return ERR_PTR(-ENOKEY);
+		default:
+			return ERR_CAST(ref);
+		}
+	}
+
+	key = key_ref_to_ptr(ref);
+	if (id && skid) {
+		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+		if (!kids->id[1]) {
+			pr_debug("issuer+serial match, but expected SKID missing\n");
+			goto reject;
+		}
+		if (!asymmetric_key_id_same(skid, kids->id[1])) {
+			pr_debug("issuer+serial match, but SKID does not\n");
+			goto reject;
+		}
+	}
+
+	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
+	return key;
+
+reject:
+	key_put(key);
+	return ERR_PTR(-EKEYREJECTED);
+}
+EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
+
+/*
+ * Check the new certificate against the ones in the trust keyring.  If one of
+ * those is the signing key and validates the new certificate, then mark the
+ * new certificate as being trusted.
+ *
+ * Return 0 if the new certificate was successfully validated, 1 if we couldn't
+ * find a matching parent certificate in the trusted list and an error if there
+ * is a matching certificate but the signature check fails.
+ */
+int x509_validate_trust(struct x509_certificate *cert,
+			struct key *trust_keyring)
+{
+	struct public_key_signature *sig = cert->sig;
+	struct key *key;
+	int ret = 1;
+
+	if (!sig->auth_ids[0] && !sig->auth_ids[1])
+		return 1;
+
+	if (!trust_keyring)
+		return -EOPNOTSUPP;
+	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
+		return -EPERM;
+	if (cert->unsupported_sig)
+		return -ENOPKG;
+
+	key = x509_request_asymmetric_key(trust_keyring,
+					  sig->auth_ids[0], sig->auth_ids[1],
+					  false);
+	if (IS_ERR(key))
+		return PTR_ERR(key);
+
+	if (!use_builtin_keys ||
+	    test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
+		ret = public_key_verify_signature(
+			key->payload.data[asym_crypto], cert->sig);
+		if (ret == -ENOPKG)
+			cert->unsupported_sig = true;
+	}
+	key_put(key);
+	return ret;
+}
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index e373e7483812..0cf670b196c8 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -59,3 +59,9 @@ extern int x509_decode_time(time64_t *_t,  size_t hdrlen,
  */
 extern int x509_get_sig_params(struct x509_certificate *cert);
 extern int x509_check_for_self_signed(struct x509_certificate *cert);
+
+/*
+ * public_key_trust.c
+ */
+extern int x509_validate_trust(struct x509_certificate *cert,
+			       struct key *trust_keyring);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 00aef0d121b2..7397edb6cefb 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -24,133 +24,6 @@
 #include "public_key.h"
 #include "x509_parser.h"
 
-static bool use_builtin_keys;
-static struct asymmetric_key_id *ca_keyid;
-
-#ifndef MODULE
-static struct {
-	struct asymmetric_key_id id;
-	unsigned char data[10];
-} cakey;
-
-static int __init ca_keys_setup(char *str)
-{
-	if (!str)		/* default system keyring */
-		return 1;
-
-	if (strncmp(str, "id:", 3) == 0) {
-		struct asymmetric_key_id *p = &cakey.id;
-		size_t hexlen = (strlen(str) - 3) / 2;
-		int ret;
-
-		if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
-			pr_err("Missing or invalid ca_keys id\n");
-			return 1;
-		}
-
-		ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
-		if (ret < 0)
-			pr_err("Unparsable ca_keys id hex string\n");
-		else
-			ca_keyid = p;	/* owner key 'id:xxxxxx' */
-	} else if (strcmp(str, "builtin") == 0) {
-		use_builtin_keys = true;
-	}
-
-	return 1;
-}
-__setup("ca_keys=", ca_keys_setup);
-#endif
-
-/**
- * x509_request_asymmetric_key - Request a key by X.509 certificate params.
- * @keyring: The keys to search.
- * @id: The issuer & serialNumber to look for or NULL.
- * @skid: The subjectKeyIdentifier to look for or NULL.
- * @partial: Use partial match if true, exact if false.
- *
- * Find a key in the given keyring by identifier.  The preferred identifier is
- * the issuer + serialNumber and the fallback identifier is the
- * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
- * the latter must also match.
- */
-struct key *x509_request_asymmetric_key(struct key *keyring,
-					const struct asymmetric_key_id *id,
-					const struct asymmetric_key_id *skid,
-					bool partial)
-{
-	struct key *key;
-	key_ref_t ref;
-	const char *lookup;
-	char *req, *p;
-	int len;
-
-	if (id) {
-		lookup = id->data;
-		len = id->len;
-	} else {
-		lookup = skid->data;
-		len = skid->len;
-	}
-
-	/* Construct an identifier "id:<keyid>". */
-	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
-	if (!req)
-		return ERR_PTR(-ENOMEM);
-
-	if (partial) {
-		*p++ = 'i';
-		*p++ = 'd';
-	} else {
-		*p++ = 'e';
-		*p++ = 'x';
-	}
-	*p++ = ':';
-	p = bin2hex(p, lookup, len);
-	*p = 0;
-
-	pr_debug("Look up: \"%s\"\n", req);
-
-	ref = keyring_search(make_key_ref(keyring, 1),
-			     &key_type_asymmetric, req);
-	if (IS_ERR(ref))
-		pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
-	kfree(req);
-
-	if (IS_ERR(ref)) {
-		switch (PTR_ERR(ref)) {
-			/* Hide some search errors */
-		case -EACCES:
-		case -ENOTDIR:
-		case -EAGAIN:
-			return ERR_PTR(-ENOKEY);
-		default:
-			return ERR_CAST(ref);
-		}
-	}
-
-	key = key_ref_to_ptr(ref);
-	if (id && skid) {
-		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
-		if (!kids->id[1]) {
-			pr_debug("issuer+serial match, but expected SKID missing\n");
-			goto reject;
-		}
-		if (!asymmetric_key_id_same(skid, kids->id[1])) {
-			pr_debug("issuer+serial match, but SKID does not\n");
-			goto reject;
-		}
-	}
-
-	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
-	return key;
-
-reject:
-	key_put(key);
-	return ERR_PTR(-EKEYREJECTED);
-}
-EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
-
 /*
  * Set up the signature parameters in an X.509 certificate.  This involves
  * digesting the signed data and extracting the signature.
@@ -294,49 +167,6 @@ not_self_signed:
 }
 
 /*
- * Check the new certificate against the ones in the trust keyring.  If one of
- * those is the signing key and validates the new certificate, then mark the
- * new certificate as being trusted.
- *
- * Return 0 if the new certificate was successfully validated, 1 if we couldn't
- * find a matching parent certificate in the trusted list and an error if there
- * is a matching certificate but the signature check fails.
- */
-static int x509_validate_trust(struct x509_certificate *cert,
-			       struct key *trust_keyring)
-{
-	struct public_key_signature *sig = cert->sig;
-	struct key *key;
-	int ret = 1;
-
-	if (!sig->auth_ids[0] && !sig->auth_ids[1])
-		return 1;
-
-	if (!trust_keyring)
-		return -EOPNOTSUPP;
-	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
-		return -EPERM;
-	if (cert->unsupported_sig)
-		return -ENOPKG;
-
-	key = x509_request_asymmetric_key(trust_keyring,
-					  sig->auth_ids[0], sig->auth_ids[1],
-					  false);
-	if (IS_ERR(key))
-		return PTR_ERR(key);
-
-	if (!use_builtin_keys ||
-	    test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
-		ret = public_key_verify_signature(
-			key->payload.data[asym_crypto], cert->sig);
-		if (ret == -ENOPKG)
-			cert->unsupported_sig = true;
-	}
-	key_put(key);
-	return ret;
-}
-
-/*
  * Attempt to parse a data blob for a key as an X509 certificate.
  */
 static int x509_key_preparse(struct key_preparsed_payload *prep)

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (12 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-02-08 11:59   ` Mimi Zohar
  2016-01-19 11:32 ` [RFC PATCH 15/20] KEYS: Move the point of trust determination to __key_link() " David Howells
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Generalise x509_request_asymmetric_key().  It doesn't really have any
dependencies on X.509 features as it uses generalised IDs and the
public_key structs that contain data extracted from X.509.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/asymmetric_keys.h  |    2 +
 crypto/asymmetric_keys/pkcs7_trust.c      |   22 +++++------
 crypto/asymmetric_keys/public_key_trust.c |   60 +++++++++++++----------------
 include/crypto/public_key.h               |    8 ++--
 security/integrity/digsig_asymmetric.c    |    5 +-
 5 files changed, 46 insertions(+), 51 deletions(-)

diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h
index 1d450b580245..ca8e9ac34ce6 100644
--- a/crypto/asymmetric_keys/asymmetric_keys.h
+++ b/crypto/asymmetric_keys/asymmetric_keys.h
@@ -9,6 +9,8 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#include <keys/asymmetric-type.h>
+
 extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
 
 extern int __asymmetric_key_hex_to_key_id(const char *id,
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 400ef359448a..8760bc566902 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -51,9 +51,9 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 		/* Look to see if this certificate is present in the trusted
 		 * keys.
 		 */
-		key = x509_request_asymmetric_key(trust_keyring,
-						  x509->id, x509->skid,
-						  false);
+		key = request_asymmetric_key(trust_keyring,
+					     x509->id, x509->skid,
+					     false);
 		if (!IS_ERR(key)) {
 			/* One of the X.509 certificates in the PKCS#7 message
 			 * is apparently the same as one we already trust.
@@ -84,10 +84,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	 * trusted keys.
 	 */
 	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
-		key = x509_request_asymmetric_key(trust_keyring,
-						  last->sig->auth_ids[0],
-						  last->sig->auth_ids[1],
-						  false);
+		key = request_asymmetric_key(trust_keyring,
+					     last->sig->auth_ids[0],
+					     last->sig->auth_ids[1],
+					     false);
 		if (!IS_ERR(key)) {
 			x509 = last;
 			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
@@ -101,10 +101,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	/* As a last resort, see if we have a trusted public key that matches
 	 * the signed info directly.
 	 */
-	key = x509_request_asymmetric_key(trust_keyring,
-					  sinfo->sig->auth_ids[0],
-					  NULL,
-					  false);
+	key = request_asymmetric_key(trust_keyring,
+				     sinfo->sig->auth_ids[0],
+				     NULL,
+				     false);
 	if (!IS_ERR(key)) {
 		pr_devel("sinfo %u: Direct signer is key %x\n",
 			 sinfo->index, key_serial(key));
diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
index 9febe612e659..afb2a3eb583a 100644
--- a/crypto/asymmetric_keys/public_key_trust.c
+++ b/crypto/asymmetric_keys/public_key_trust.c
@@ -1,6 +1,6 @@
-/* Instantiate a public key crypto key from an X.509 Certificate
+/* Validate one public key against another to determine trust chaining.
  *
- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -9,17 +9,10 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
-#define pr_fmt(fmt) "X.509: "fmt
-#include <linux/module.h>
+#define pr_fmt(fmt) "PKEY: "fmt
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/mpi.h>
-#include <linux/asn1_decoder.h>
-#include <keys/asymmetric-subtype.h>
-#include <keys/asymmetric-parser.h>
-#include <keys/system_keyring.h>
-#include <crypto/hash.h>
 #include "asymmetric_keys.h"
 #include "public_key.h"
 #include "x509_parser.h"
@@ -63,21 +56,20 @@ __setup("ca_keys=", ca_keys_setup);
 #endif
 
 /**
- * x509_request_asymmetric_key - Request a key by X.509 certificate params.
+ * request_asymmetric_key - Request a key by ID.
  * @keyring: The keys to search.
- * @id: The issuer & serialNumber to look for or NULL.
- * @skid: The subjectKeyIdentifier to look for or NULL.
+ * @id_0: The first ID to look for or NULL.
+ * @id_1: The second ID to look for or NULL.
  * @partial: Use partial match if true, exact if false.
  *
  * Find a key in the given keyring by identifier.  The preferred identifier is
- * the issuer + serialNumber and the fallback identifier is the
- * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
- * the latter must also match.
+ * the id_0 and the fallback identifier is the id_1.  If both are given, the
+ * lookup is by the former, but the latter must also match.
  */
-struct key *x509_request_asymmetric_key(struct key *keyring,
-					const struct asymmetric_key_id *id,
-					const struct asymmetric_key_id *skid,
-					bool partial)
+struct key *request_asymmetric_key(struct key *keyring,
+				   const struct asymmetric_key_id *id_0,
+				   const struct asymmetric_key_id *id_1,
+				   bool partial)
 {
 	struct key *key;
 	key_ref_t ref;
@@ -85,12 +77,12 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 	char *req, *p;
 	int len;
 
-	if (id) {
-		lookup = id->data;
-		len = id->len;
+	if (id_0) {
+		lookup = id_0->data;
+		len = id_0->len;
 	} else {
-		lookup = skid->data;
-		len = skid->len;
+		lookup = id_1->data;
+		len = id_1->len;
 	}
 
 	/* Construct an identifier "id:<keyid>". */
@@ -130,14 +122,15 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 	}
 
 	key = key_ref_to_ptr(ref);
-	if (id && skid) {
+	if (id_0 && id_1) {
 		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
-		if (!kids->id[1]) {
-			pr_debug("issuer+serial match, but expected SKID missing\n");
+
+		if (!kids->id[0]) {
+			pr_debug("First ID matches, but second is missing\n");
 			goto reject;
 		}
-		if (!asymmetric_key_id_same(skid, kids->id[1])) {
-			pr_debug("issuer+serial match, but SKID does not\n");
+		if (!asymmetric_key_id_same(id_1, kids->id[1])) {
+			pr_debug("First ID matches, but second does not\n");
 			goto reject;
 		}
 	}
@@ -149,7 +142,7 @@ reject:
 	key_put(key);
 	return ERR_PTR(-EKEYREJECTED);
 }
-EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
+EXPORT_SYMBOL_GPL(request_asymmetric_key);
 
 /*
  * Check the new certificate against the ones in the trust keyring.  If one of
@@ -177,9 +170,8 @@ int x509_validate_trust(struct x509_certificate *cert,
 	if (cert->unsupported_sig)
 		return -ENOPKG;
 
-	key = x509_request_asymmetric_key(trust_keyring,
-					  sig->auth_ids[0], sig->auth_ids[1],
-					  false);
+	key = request_asymmetric_key(trust_keyring,
+				     sig->auth_ids[0], sig->auth_ids[1], false);
 	if (IS_ERR(key))
 		return PTR_ERR(key);
 
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index ed86bfb23e89..eaaf261d398a 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -102,9 +102,9 @@ extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
 
 struct asymmetric_key_id;
-extern struct key *x509_request_asymmetric_key(struct key *keyring,
-					       const struct asymmetric_key_id *id,
-					       const struct asymmetric_key_id *skid,
-					       bool partial);
+extern struct key *request_asymmetric_key(struct key *keyring,
+					  const struct asymmetric_key_id *id_0,
+					  const struct asymmetric_key_id *id_1,
+					  bool partial);
 
 #endif /* _LINUX_PUBLIC_KEY_H */
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 5ade2a7517a6..be1af41b5c2a 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -24,7 +24,8 @@
 /*
  * Request an asymmetric key.
  */
-static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
+static struct key *ds_request_asymmetric_key(struct key *keyring,
+					     uint32_t keyid)
 {
 	struct key *key;
 	char name[12];
@@ -97,7 +98,7 @@ int asymmetric_verify(struct key *keyring, const char *sig,
 	if (hdr->hash_algo >= PKEY_HASH__LAST)
 		return -ENOPKG;
 
-	key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
+	key = ds_request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
 	if (IS_ERR(key))
 		return PTR_ERR(key);
 

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 15/20] KEYS: Move the point of trust determination to __key_link() [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (13 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-01-19 11:32 ` [RFC PATCH 16/20] KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED " David Howells
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Move the point at which a key is determined to be trustworthy to
__key_link() so that we use the contents of the keyring being linked in to
to determine whether the key being linked in is trusted or not.

What is 'trusted' then becomes a matter of what's in the keyring.

Currently, the test is done when the key is parsed, but given that at that
point we can only sensibly refer to the contents of the system trusted
keyring, we can only use that as the basis for working out the
trustworthiness of a new key.

With this change, a trusted keyring is a set of keys that once the
trusted-only flag is set cannot be added to except by verification through
one of the contained keys.

Further, adding a key into a trusted keyring, whilst it might grant
trustworthiness in the context of that keyring, does not automatically
grant trustworthiness in the context of a second keyring to which it could
be secondarily linked.

To accomplish this, the authentication data associated with the key source
must now be retained.  For an X.509 cert, this means the contents of the
AuthorityKeyIdentifier and the signature data.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/system_keyring.c                    |   19 ++++++-
 crypto/asymmetric_keys/public_key.h       |    6 ++
 crypto/asymmetric_keys/public_key_trust.c |   76 +++++++++++++++++++----------
 crypto/asymmetric_keys/x509_parser.h      |    6 --
 crypto/asymmetric_keys/x509_public_key.c  |   22 --------
 include/crypto/public_key.h               |    7 +++
 include/keys/system_keyring.h             |   16 ++----
 kernel/module_signing.c                   |    2 -
 security/integrity/digsig.c               |   31 +++++++++++-
 security/integrity/ima/ima_mok.c          |    6 +-
 10 files changed, 117 insertions(+), 74 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 417d65882870..6e069246c168 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -18,12 +18,25 @@
 #include <keys/system_keyring.h>
 #include <crypto/pkcs7.h>
 
-struct key *system_trusted_keyring;
-EXPORT_SYMBOL_GPL(system_trusted_keyring);
+static struct key *system_trusted_keyring;
 
 extern __initconst const u8 system_certificate_list[];
 extern __initconst const unsigned long system_certificate_list_size;
 
+/**
+ * restrict_link_to_system_trusted - Restrict keyring addition by system CA
+ *
+ * Restrict the addition of keys into a keyring based on the key-to-be-added
+ * being vouched for by a key in the system keyring.
+ */
+int restrict_link_by_system_trusted(struct key *keyring,
+				    const struct key_type *type,
+				    unsigned long flags,
+				    const union key_payload *payload)
+{
+	return public_key_restrict_link(system_trusted_keyring, type, payload);
+}
+
 /*
  * Load the compiled-in keys
  */
@@ -37,7 +50,7 @@ static __init int system_trusted_keyring_init(void)
 			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
 			      KEY_ALLOC_NOT_IN_QUOTA,
-			      keyring_restrict_trusted_only, NULL);
+			      restrict_link_by_system_trusted, NULL);
 	if (IS_ERR(system_trusted_keyring))
 		panic("Can't allocate system trusted keyring\n");
 	return 0;
diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h
index 5c37a22a0637..2962025e1c09 100644
--- a/crypto/asymmetric_keys/public_key.h
+++ b/crypto/asymmetric_keys/public_key.h
@@ -34,3 +34,9 @@ extern const struct public_key_algorithm RSA_public_key_algorithm;
  */
 extern int public_key_verify_signature(const struct public_key *pk,
 				       const struct public_key_signature *sig);
+
+/*
+ * public_key_trust.c
+ */
+extern int public_key_validate_trust(const struct public_key_signature *sig,
+				     struct key *trust_keyring);
diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
index afb2a3eb583a..26d8e6547104 100644
--- a/crypto/asymmetric_keys/public_key_trust.c
+++ b/crypto/asymmetric_keys/public_key_trust.c
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include "asymmetric_keys.h"
 #include "public_key.h"
-#include "x509_parser.h"
 
 static bool use_builtin_keys;
 static struct asymmetric_key_id *ca_keyid;
@@ -145,43 +144,66 @@ reject:
 EXPORT_SYMBOL_GPL(request_asymmetric_key);
 
 /*
+ * Try to find a trust relationship for a new key.
+ */
+static int public_key_verify_trust(struct key *trust_keyring,
+				   const struct public_key_signature *sig)
+{
+	struct key *key;
+	int ret;
+
+
+	/* See if we have a key that signed this one. */
+	key = request_asymmetric_key(trust_keyring,
+				     sig->auth_ids[0],
+				     sig->auth_ids[1],
+				     false);
+	if (IS_ERR(key))
+		return -ENOKEY;
+
+	if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags))
+		ret = -ENOKEY;
+	else
+		ret = verify_signature(key, sig);
+	key_put(key);
+	return ret;
+}
+
+/**
+ * public_key_restrict_link - Restrict additions to a ring of public keys
+ * @trust_keyring: A ring of keys that can be used to vouch for the new cert.
+ * @type: The type of key being added.
+ * @payload: The payload of the new key.
+ *
  * Check the new certificate against the ones in the trust keyring.  If one of
  * those is the signing key and validates the new certificate, then mark the
  * new certificate as being trusted.
  *
- * Return 0 if the new certificate was successfully validated, 1 if we couldn't
- * find a matching parent certificate in the trusted list and an error if there
- * is a matching certificate but the signature check fails.
+ * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a
+ * matching parent certificate in the trusted list, -EKEYREJECTED if the
+ * signature check fails or the key is blacklisted and some other error if
+ * there is a matching certificate but the signature check cannot be performed.
  */
-int x509_validate_trust(struct x509_certificate *cert,
-			struct key *trust_keyring)
+int public_key_restrict_link(struct key *trust_keyring,
+			     const struct key_type *type,
+			     const union key_payload *payload)
 {
-	struct public_key_signature *sig = cert->sig;
-	struct key *key;
-	int ret = 1;
+	const struct public_key_signature *sig;
 
-	if (!sig->auth_ids[0] && !sig->auth_ids[1])
-		return 1;
+	pr_devel("==>%s()\n", __func__);
 
 	if (!trust_keyring)
+		return -ENOKEY;
+	
+	if (type != &key_type_asymmetric)
 		return -EOPNOTSUPP;
+
+	sig = payload->data[asym_auth];
+	if (!sig->auth_ids[0] && !sig->auth_ids[1])
+		return 0;
+
 	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
 		return -EPERM;
-	if (cert->unsupported_sig)
-		return -ENOPKG;
 
-	key = request_asymmetric_key(trust_keyring,
-				     sig->auth_ids[0], sig->auth_ids[1], false);
-	if (IS_ERR(key))
-		return PTR_ERR(key);
-
-	if (!use_builtin_keys ||
-	    test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
-		ret = public_key_verify_signature(
-			key->payload.data[asym_crypto], cert->sig);
-		if (ret == -ENOPKG)
-			cert->unsupported_sig = true;
-	}
-	key_put(key);
-	return ret;
+	return public_key_verify_trust(trust_keyring, sig);
 }
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 0cf670b196c8..e373e7483812 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -59,9 +59,3 @@ extern int x509_decode_time(time64_t *_t,  size_t hdrlen,
  */
 extern int x509_get_sig_params(struct x509_certificate *cert);
 extern int x509_check_for_self_signed(struct x509_certificate *cert);
-
-/*
- * public_key_trust.c
- */
-extern int x509_validate_trust(struct x509_certificate *cert,
-			       struct key *trust_keyring);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 7397edb6cefb..7c6a87e3b151 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -108,7 +108,6 @@ error:
 	pr_devel("<==%s() = %d\n", __func__, ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(x509_get_sig_params);
 
 /*
  * Check for self-signedness in an X.509 cert and if found, check the signature
@@ -196,32 +195,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
 	cert->pub->id_type = PKEY_ID_X509;
 
-	/* See if we can derive the trustability of this certificate.
-	 *
-	 * When it comes to self-signed certificates, we cannot evaluate
-	 * trustedness except by the fact that we obtained it from a trusted
-	 * location.  So we just rely on x509_validate_trust() failing in this
-	 * case.
-	 *
-	 * Note that there's a possibility of a self-signed cert matching a
-	 * cert that we have (most likely a duplicate that we already trust) -
-	 * in which case it will be marked trusted.
-	 */
-	if (cert->unsupported_sig || cert->self_signed) {
+	if (cert->unsupported_sig) {
 		public_key_free(NULL, cert->sig);
 		cert->sig = NULL;
 	} else {
 		pr_devel("Cert Signature: %s + %s\n",
 			 pkey_algo_name[cert->sig->pkey_algo],
 			 hash_algo_name[cert->sig->pkey_hash_algo]);
-
-		ret = x509_validate_trust(cert, get_system_trusted_keyring());
-		if (ret)
-			ret = x509_validate_trust(cert, get_ima_mok_keyring());
-		if (ret == -EKEYREJECTED)
-			goto error_free_cert;
-		if (!ret)
-			prep->trusted = true;
 	}
 
 	/* Don't permit addition of blacklisted keys */
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index eaaf261d398a..c2250f2c1450 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -98,6 +98,13 @@ extern void public_key_free(struct public_key *key,
 			    struct public_key_signature *sig);
 
 struct key;
+struct key_type;
+union key_payload;
+
+extern int public_key_restrict_link(struct key *trust_keyring,
+				    const struct key_type *type,
+				    const union key_payload *payload);
+
 extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
 
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 707229245c8f..28ca2d824554 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -15,19 +15,11 @@
 #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
 
 #include <linux/key.h>
-#include <linux/verification.h>
-#include <crypto/public_key.h>
 
-extern struct key *system_trusted_keyring;
-static inline struct key *get_system_trusted_keyring(void)
-{
-	return system_trusted_keyring;
-}
-#else
-static inline struct key *get_system_trusted_keyring(void)
-{
-	return NULL;
-}
+extern int restrict_link_by_system_trusted(struct key *keyring,
+					   const struct key_type *type,
+					   unsigned long flags,
+					   const union key_payload *payload);
 #endif
 
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index b3dafe4fd320..50eab38e0e34 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -11,7 +11,7 @@
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <keys/system_keyring.h>
+#include <linux/verification.h>
 #include <crypto/public_key.h>
 #include "module-internal.h"
 
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 659566c2200b..fee9b5b08b01 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -18,6 +18,8 @@
 #include <linux/cred.h>
 #include <linux/key-type.h>
 #include <linux/digsig.h>
+#include <crypto/public_key.h>
+#include <keys/system_keyring.h>
 
 #include "integrity.h"
 
@@ -40,6 +42,26 @@ static bool init_keyring __initdata = true;
 static bool init_keyring __initdata;
 #endif
 
+/*
+ * Restrict the addition of keys into the IMA keyring.
+ *
+ * Any key that needs to go in .ima keyring must be signed by CA in
+ * either .system or .ima_mok keyrings.
+ */
+static int restrict_link_by_ima_mok(struct key *keyring,
+				    const struct key_type *type,
+				    unsigned long flags,
+				    const union key_payload *payload)
+{
+	int ret;
+
+	ret = restrict_link_by_system_trusted(keyring, type, flags, payload);
+	if (ret != -ENOKEY)
+		return ret;
+
+	return public_key_restrict_link(get_ima_mok_keyring(), type, payload);
+}
+
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 			    const char *digest, int digestlen)
 {
@@ -72,19 +94,26 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 
 int __init integrity_init_keyring(const unsigned int id)
 {
+	int (*restrict_link)(struct key *,
+			     const struct key_type *,
+			     unsigned long,
+			     const union key_payload *) = NULL;
 	const struct cred *cred = current_cred();
 	int err = 0;
 
 	if (!init_keyring)
 		return 0;
 
+	if (id == 1)
+		restrict_link = restrict_link_by_ima_mok;
+
 	keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
 				    KGIDT_INIT(0), cred,
 				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				     KEY_USR_VIEW | KEY_USR_READ |
 				     KEY_USR_WRITE | KEY_USR_SEARCH),
 				    KEY_ALLOC_NOT_IN_QUOTA,
-				    NULL, NULL);
+				    restrict_link, NULL);
 	if (IS_ERR(keyring[id])) {
 		err = PTR_ERR(keyring[id]);
 		pr_info("Can't allocate %s keyring (%d)\n",
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index ef91248cb934..be0da013622c 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -17,7 +17,7 @@
 #include <linux/cred.h>
 #include <linux/err.h>
 #include <linux/init.h>
-#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
 
 
 struct key *ima_mok_keyring;
@@ -36,7 +36,7 @@ __init int ima_mok_init(void)
 			      KEY_USR_VIEW | KEY_USR_READ |
 			      KEY_USR_WRITE | KEY_USR_SEARCH,
 			      KEY_ALLOC_NOT_IN_QUOTA,
-			      keyring_restrict_trusted_only, NULL);
+			      restrict_link_by_system_trusted, NULL);
 
 	ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
 				KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
@@ -44,7 +44,7 @@ __init int ima_mok_init(void)
 				KEY_USR_VIEW | KEY_USR_READ |
 				KEY_USR_WRITE | KEY_USR_SEARCH,
 				KEY_ALLOC_NOT_IN_QUOTA,
-				keyring_restrict_trusted_only, NULL);
+				restrict_link_by_system_trusted, NULL);
 
 	if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
 		panic("Can't allocate IMA MOK or blacklist keyrings.");

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 16/20] KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (14 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 15/20] KEYS: Move the point of trust determination to __key_link() " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-01-19 11:32 ` [RFC PATCH 17/20] PKCS#7: Handle blacklisted certificates " David Howells
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED as they're no longer
meaningful.  Also we can drop the trusted flag from the preparse structure.

Given this, we no longer need to pass the key flags through to
restrict_link().

Further, we can now get rid of keyring_restrict_trusted_only() also.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/system_keyring.c        |    2 --
 include/keys/system_keyring.h |    1 -
 include/linux/key-type.h      |    1 -
 include/linux/key.h           |   20 +++++---------------
 security/integrity/digsig.c   |    4 +---
 security/keys/key.c           |   11 ++---------
 security/keys/keyring.c       |   28 +---------------------------
 7 files changed, 9 insertions(+), 58 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 6e069246c168..5e76121d4cc2 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -31,7 +31,6 @@ extern __initconst const unsigned long system_certificate_list_size;
  */
 int restrict_link_by_system_trusted(struct key *keyring,
 				    const struct key_type *type,
-				    unsigned long flags,
 				    const union key_payload *payload)
 {
 	return public_key_restrict_link(system_trusted_keyring, type, payload);
@@ -96,7 +95,6 @@ static __init int load_system_certificate_list(void)
 					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 					   KEY_USR_VIEW | KEY_USR_READ),
 					   KEY_ALLOC_NOT_IN_QUOTA |
-					   KEY_ALLOC_TRUSTED |
 					   KEY_ALLOC_BUILT_IN |
 					   KEY_ALLOC_BYPASS_RESTRICTION);
 		if (IS_ERR(key)) {
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 28ca2d824554..615244b1e276 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -18,7 +18,6 @@
 
 extern int restrict_link_by_system_trusted(struct key *keyring,
 					   const struct key_type *type,
-					   unsigned long flags,
 					   const union key_payload *payload);
 #endif
 
diff --git a/include/linux/key-type.h b/include/linux/key-type.h
index 7463355a198b..eaee981c5558 100644
--- a/include/linux/key-type.h
+++ b/include/linux/key-type.h
@@ -45,7 +45,6 @@ struct key_preparsed_payload {
 	size_t		datalen;	/* Raw datalen */
 	size_t		quotalen;	/* Quota length for proposed payload */
 	time_t		expiry;		/* Expiry time of key */
-	bool		trusted;	/* True if key is trusted */
 };
 
 typedef int (*request_key_actor_t)(struct key_construction *key,
diff --git a/include/linux/key.h b/include/linux/key.h
index c331b8bed035..9b885ba3ba63 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -173,10 +173,9 @@ struct key {
 #define KEY_FLAG_NEGATIVE	5	/* set if key is negative */
 #define KEY_FLAG_ROOT_CAN_CLEAR	6	/* set if key can be cleared by root without permission */
 #define KEY_FLAG_INVALIDATED	7	/* set if key has been invalidated */
-#define KEY_FLAG_TRUSTED	8	/* set if key is trusted */
-#define KEY_FLAG_BUILTIN	9	/* set if key is built in to the kernel */
-#define KEY_FLAG_ROOT_CAN_INVAL	10	/* set if key can be invalidated by root without permission */
-#define KEY_FLAG_KEEP		11	/* set if key should not be removed */
+#define KEY_FLAG_BUILTIN	8	/* set if key is built in to the kernel */
+#define KEY_FLAG_ROOT_CAN_INVAL	9	/* set if key can be invalidated by root without permission */
+#define KEY_FLAG_KEEP		10	/* set if key should not be removed */
 
 	/* the key type and key description string
 	 * - the desc is used to match a key against search criteria
@@ -217,7 +216,6 @@ struct key {
 	 */
 	int (*restrict_link)(struct key *keyring,
 			     const struct key_type *type,
-			     unsigned long flags,
 			     const union key_payload *payload);
 };
 
@@ -229,16 +227,14 @@ extern struct key *key_alloc(struct key_type *type,
 			     unsigned long flags,
 			     int (*restrict_link)(struct key *,
 						  const struct key_type *,
-						  unsigned long,
 						  const union key_payload *));
 
 
 #define KEY_ALLOC_IN_QUOTA		0x0000	/* add to quota, reject if would overrun */
 #define KEY_ALLOC_QUOTA_OVERRUN		0x0001	/* add to quota, permit even if overrun */
 #define KEY_ALLOC_NOT_IN_QUOTA		0x0002	/* not in quota */
-#define KEY_ALLOC_TRUSTED		0x0004	/* Key should be flagged as trusted */
-#define KEY_ALLOC_BUILT_IN		0x0008	/* Key is built into kernel */
-#define KEY_ALLOC_BYPASS_RESTRICTION	0x0010	/* Override the check on restricted keyrings */
+#define KEY_ALLOC_BUILT_IN		0x0004	/* Key is built into kernel */
+#define KEY_ALLOC_BYPASS_RESTRICTION	0x0008	/* Override the check on restricted keyrings */
 
 extern void key_revoke(struct key *key);
 extern void key_invalidate(struct key *key);
@@ -309,15 +305,9 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid
 				 unsigned long flags,
 				 int (*restrict_link)(struct key *,
 						      const struct key_type *,
-						      unsigned long,
 						      const union key_payload *),
 				 struct key *dest);
 
-extern int keyring_restrict_trusted_only(struct key *keyring,
-					 const struct key_type *type,
-					 unsigned long,
-					 const union key_payload *payload);
-
 extern int keyring_clear(struct key *keyring);
 
 extern key_ref_t keyring_search(key_ref_t keyring,
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index fee9b5b08b01..464d25e698ec 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -50,12 +50,11 @@ static bool init_keyring __initdata;
  */
 static int restrict_link_by_ima_mok(struct key *keyring,
 				    const struct key_type *type,
-				    unsigned long flags,
 				    const union key_payload *payload)
 {
 	int ret;
 
-	ret = restrict_link_by_system_trusted(keyring, type, flags, payload);
+	ret = restrict_link_by_system_trusted(keyring, type, payload);
 	if (ret != -ENOKEY)
 		return ret;
 
@@ -96,7 +95,6 @@ int __init integrity_init_keyring(const unsigned int id)
 {
 	int (*restrict_link)(struct key *,
 			     const struct key_type *,
-			     unsigned long,
 			     const union key_payload *) = NULL;
 	const struct cred *cred = current_cred();
 	int err = 0;
diff --git a/security/keys/key.c b/security/keys/key.c
index 23b271b1834d..f61e2fd5c0c5 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -227,7 +227,6 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 		      key_perm_t perm, unsigned long flags,
 		      int (*restrict_link)(struct key *,
 					   const struct key_type *,
-					   unsigned long,
 					   const union key_payload *))
 {
 	struct key_user *user = NULL;
@@ -300,8 +299,6 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 
 	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
 		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
-	if (flags & KEY_ALLOC_TRUSTED)
-		key->flags |= 1 << KEY_FLAG_TRUSTED;
 	if (flags & KEY_ALLOC_BUILT_IN)
 		key->flags |= 1 << KEY_FLAG_BUILTIN;
 
@@ -503,7 +500,7 @@ int key_instantiate_and_link(struct key *key,
 	if (keyring) {
 		if (keyring->restrict_link) {
 			ret = keyring->restrict_link(keyring, key->type,
-						     key->flags, &prep.payload);
+						     &prep.payload);
 			if (ret < 0)
 				goto error;
 		}
@@ -810,7 +807,6 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	int ret;
 	int (*restrict_link)(struct key *,
 			     const struct key_type *,
-			     unsigned long,
 			     const union key_payload *) = NULL;
 
 	/* look up the key type to see if it's one of the registered kernel
@@ -842,7 +838,6 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	prep.data = payload;
 	prep.datalen = plen;
 	prep.quotalen = index_key.type->def_datalen;
-	prep.trusted = flags & KEY_ALLOC_TRUSTED;
 	prep.expiry = TIME_T_MAX;
 	if (index_key.type->preparse) {
 		ret = index_key.type->preparse(&prep);
@@ -859,9 +854,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	index_key.desc_len = strlen(index_key.description);
 
 	if (restrict_link) {
-		unsigned long kflags = prep.trusted ? KEY_FLAG_TRUSTED : 0;
-		ret = restrict_link(keyring,
-				    index_key.type, kflags, &prep.payload);
+		ret = restrict_link(keyring, index_key.type, &prep.payload);
 		if (ret < 0) {
 			key_ref = ERR_PTR(ret);
 			goto error_free_prep;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index ea023ca6d217..68f02cd4e921 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -494,7 +494,6 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 			  unsigned long flags,
 			  int (*restrict_link)(struct key *,
 					       const struct key_type *,
-					       unsigned long,
 					       const union key_payload *),
 			  struct key *dest)
 {
@@ -515,30 +514,6 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 }
 EXPORT_SYMBOL(keyring_alloc);
 
-/**
- * keyring_restrict_trusted_only - Restrict additions to a keyring to trusted keys only
- * @keyring: The keyring being added to.
- * @type: The type of key being added.
- * @flags: The key flags.
- * @payload: The payload of the key intended to be added.
- *
- * Reject the addition of any links to a keyring that point to keys that aren't
- * marked as being trusted.  It can be overridden by passing
- * KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when adding a key
- * to a keyring.
- *
- * This is meant to be passed as the restrict_link parameter to
- * keyring_alloc().
- */
-int keyring_restrict_trusted_only(struct key *keyring,
-				  const struct key_type *type,
-				  unsigned long flags,
-				  const union key_payload *payload)
-{
-	
-	return flags & KEY_FLAG_TRUSTED ? 0 : -EPERM;
-}
-
 /*
  * By default, we keys found by getting an exact match on their descriptions.
  */
@@ -1227,8 +1202,7 @@ static int __key_link_check_restriction(struct key *keyring, struct key *key)
 {
 	if (!keyring->restrict_link)
 		return 0;
-	return keyring->restrict_link(keyring,
-				      key->type, key->flags, &key->payload);
+	return keyring->restrict_link(keyring, key->type, &key->payload);
 }
 
 /**

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 17/20] PKCS#7: Handle blacklisted certificates [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (15 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 16/20] KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-01-19 11:32 ` [RFC PATCH 18/20] IMA: Use the system blacklist keyring " David Howells
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

PKCS#7: Handle certificates that are blacklisted when verifying the chain
of trust on the signatures on a PKCS#7 message.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/pkcs7_parser.h |    1 +
 crypto/asymmetric_keys/pkcs7_verify.c |   32 ++++++++++++++++++++++++--------
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index f4e81074f5e0..ac341e19e530 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -23,6 +23,7 @@ struct pkcs7_signed_info {
 	struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
 	unsigned	index;
 	bool		unsupported_crypto;	/* T if not usable due to missing crypto */
+	bool		blacklisted;
 
 	/* Message digest - the digest of the Content Data (or NULL) */
 	const void	*msgdigest;
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 3b8124c2cd91..2f8df3533c08 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -192,6 +192,18 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 			 x509->subject,
 			 x509->raw_serial_size, x509->raw_serial);
 		x509->seen = true;
+
+		if (x509->blacklisted) {
+			/* If this cert is blacklisted, then mark everything
+			 * that depends on this as blacklisted too.
+			 */
+			sinfo->blacklisted = true;
+			for (p = sinfo->signer; p != x509; p = p->signer)
+				p->blacklisted = true;
+			pr_debug("- blacklisted\n");
+			return 0;
+		}
+
 		if (x509->unsupported_key)
 			goto unsupported_crypto_in_x509;
 
@@ -359,17 +371,19 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
  *
  *  (*) -EBADMSG if some part of the message was invalid, or:
  *
- *  (*) -ENOPKG if none of the signature chains are verifiable because suitable
- *	crypto modules couldn't be found, or:
+ *  (*) 0 if no signature chains were found to be blacklisted or to contain
+ *	unsupported crypto, or:
  *
- *  (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
- *	(note that a signature chain may be of zero length), or:
+ *  (*) -EKEYREJECTED if a blacklisted key was encountered, or:
+ *
+ *  (*) -ENOPKG if none of the signature chains are verifiable because suitable
+ *	crypto modules couldn't be found.
  */
 int pkcs7_verify(struct pkcs7_message *pkcs7,
 		 enum key_being_used_for usage)
 {
 	struct pkcs7_signed_info *sinfo;
-	int enopkg = -ENOPKG;
+	int actual_ret = -ENOPKG;
 	int ret;
 
 	kenter("");
@@ -414,6 +428,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
 
 	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
 		ret = pkcs7_verify_one(pkcs7, sinfo);
+		if (sinfo->blacklisted && actual_ret == -ENOPKG)
+			actual_ret = -EKEYREJECTED;
 		if (ret < 0) {
 			if (ret == -ENOPKG) {
 				sinfo->unsupported_crypto = true;
@@ -422,11 +438,11 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
 			kleave(" = %d", ret);
 			return ret;
 		}
-		enopkg = 0;
+		actual_ret = 0;
 	}
 
-	kleave(" = %d", enopkg);
-	return enopkg;
+	kleave(" = %d", actual_ret);
+	return actual_ret;
 }
 EXPORT_SYMBOL_GPL(pkcs7_verify);
 

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 18/20] IMA: Use the system blacklist keyring [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (16 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 17/20] PKCS#7: Handle blacklisted certificates " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-02-10 19:12   ` Mimi Zohar
  2016-02-19 11:58   ` David Howells
  2016-01-19 11:32 ` [RFC PATCH 19/20] certs: Add a secondary system keyring that can be added to dynamically " David Howells
                   ` (5 subsequent siblings)
  23 siblings, 2 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Use the system blacklist keyring instead of having an IMA-specific keyring.
This requires that the system blacklist be made writable.  To control what
goes into it, additions to the system blacklist is restricted to
certificates that can be validated by CA certificates in the system
keyring.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/blacklist.c                      |   26 +++++++++++++++++++++++---
 include/keys/system_keyring.h          |   14 +++++---------
 security/integrity/digsig_asymmetric.c |   13 +++----------
 security/integrity/ima/ima_mok.c       |   15 ++-------------
 4 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/certs/blacklist.c b/certs/blacklist.c
index 7f769479c17b..5648504768b2 100644
--- a/certs/blacklist.c
+++ b/certs/blacklist.c
@@ -18,6 +18,7 @@
 #include <linux/ctype.h>
 #include <linux/err.h>
 #include <keys/system_keyring.h>
+#include <keys/asymmetric-type.h>
 #include "blacklist.h"
 
 static struct key *blacklist_keyring;
@@ -80,7 +81,8 @@ int mark_hash_blacklisted(const char *hash)
 				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				    KEY_USR_VIEW),
 				   KEY_ALLOC_NOT_IN_QUOTA |
-				   KEY_ALLOC_BUILT_IN);
+				   KEY_ALLOC_BUILT_IN |
+				   KEY_ALLOC_BYPASS_RESTRICTION);
 	if (IS_ERR(key)) {
 		pr_err("Problem blacklisting hash (%ld)\n",
 		       PTR_ERR(key));
@@ -129,6 +131,24 @@ int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len)
 }
 EXPORT_SYMBOL_GPL(is_bin_hash_blacklisted);
 
+/**
+ * is_key_blacklisted - Determine if a key is blacklisted
+ * @name: The name or ID of the key to check.
+ */
+int is_key_blacklisted(const char *name)
+{
+	key_ref_t kref;
+
+	kref = keyring_search(make_key_ref(blacklist_keyring, true),
+			      &key_type_asymmetric, name);
+	if (!IS_ERR(kref)) {
+		key_ref_put(kref);
+		return -EKEYREJECTED;
+	}
+
+	return 0;
+}
+
 /*
  * Intialise the blacklist
  */
@@ -145,10 +165,10 @@ static int __init blacklist_init(void)
 			      current_cred(),
 			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
 			      KEY_USR_VIEW | KEY_USR_READ |
-			      KEY_USR_SEARCH,
+			      KEY_USR_SEARCH | KEY_USR_WRITE,
 			      KEY_ALLOC_NOT_IN_QUOTA |
 			      KEY_FLAG_KEEP,
-			      NULL, NULL);
+			      restrict_link_by_system_trusted, NULL);
 	if (IS_ERR(blacklist_keyring))
 		panic("Can't allocate system blacklist keyring\n");
 
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 615244b1e276..15107dcc2ec4 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -25,6 +25,7 @@ extern int restrict_link_by_system_trusted(struct key *keyring,
 extern int mark_hash_blacklisted(const char *hash);
 extern int is_hash_blacklisted(const char *hash);
 extern int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len);
+extern int is_key_blacklisted(const char *name);
 #else
 static inline int is_hash_blacklisted(const char *hash)
 {
@@ -34,29 +35,24 @@ static inline int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len)
 {
 	return 0;
 }
+static inline int is_key_blacklisted(const char *name)
+{
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_IMA_MOK_KEYRING
 extern struct key *ima_mok_keyring;
-extern struct key *ima_blacklist_keyring;
 
 static inline struct key *get_ima_mok_keyring(void)
 {
 	return ima_mok_keyring;
 }
-static inline struct key *get_ima_blacklist_keyring(void)
-{
-	return ima_blacklist_keyring;
-}
 #else
 static inline struct key *get_ima_mok_keyring(void)
 {
 	return NULL;
 }
-static inline struct key *get_ima_blacklist_keyring(void)
-{
-	return NULL;
-}
 #endif /* CONFIG_IMA_MOK_KEYRING */
 
 
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index be1af41b5c2a..bd854dff36e0 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -34,16 +34,9 @@ static struct key *ds_request_asymmetric_key(struct key *keyring,
 
 	pr_debug("key search: \"%s\"\n", name);
 
-	key = get_ima_blacklist_keyring();
-	if (key) {
-		key_ref_t kref;
-
-		kref = keyring_search(make_key_ref(key, 1),
-				     &key_type_asymmetric, name);
-		if (!IS_ERR(kref)) {
-			pr_err("Key '%s' is in ima_blacklist_keyring\n", name);
-			return ERR_PTR(-EKEYREJECTED);
-		}
+	if (is_key_blacklisted(name) == -EKEYREJECTED) {
+		pr_err("Key '%s' is blacklisted\n", name);
+		return ERR_PTR(-EKEYREJECTED);
 	}
 
 	if (keyring) {
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index be0da013622c..6b34770a6c9f 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -21,7 +21,6 @@
 
 
 struct key *ima_mok_keyring;
-struct key *ima_blacklist_keyring;
 
 /*
  * Allocate the IMA MOK and blacklist keyrings
@@ -38,18 +37,8 @@ __init int ima_mok_init(void)
 			      KEY_ALLOC_NOT_IN_QUOTA,
 			      restrict_link_by_system_trusted, NULL);
 
-	ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
-				KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
-				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
-				KEY_USR_VIEW | KEY_USR_READ |
-				KEY_USR_WRITE | KEY_USR_SEARCH,
-				KEY_ALLOC_NOT_IN_QUOTA,
-				restrict_link_by_system_trusted, NULL);
-
-	if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
-		panic("Can't allocate IMA MOK or blacklist keyrings.");
-
-	set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
+	if (IS_ERR(ima_mok_keyring))
+		panic("Can't allocate IMA MOK keyring.");
 	return 0;
 }
 device_initcall(ima_mok_init);

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 19/20] certs: Add a secondary system keyring that can be added to dynamically [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (17 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 18/20] IMA: Use the system blacklist keyring " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-01-19 11:32 ` [RFC PATCH 20/20] IMA: Replace the .ima_mok keyring with the secondary system keyring " David Howells
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Add a secondary system keyring that can be added to by root whilst the
system is running - provided the key being added is vouched for by a key
built into the kernel or already added to the secondary keyring.

Rename .system_keyring to .builtin_trusted_keys to distinguish it more
obviously from the new keyring (called .secondary_trusted_keys).

The new keyring needs to be enabled with CONFIG_SECONDARY_TRUSTED_KEYRING.

If the secondary keyring is enabled, a link is created from that to
.builtin_trusted_keys so that the the latter will automatically be searched
too if the secondary keyring is searched.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/Kconfig                 |    8 ++++
 certs/system_keyring.c        |   82 +++++++++++++++++++++++++++++++++++------
 include/keys/system_keyring.h |    4 ++
 3 files changed, 82 insertions(+), 12 deletions(-)

diff --git a/certs/Kconfig b/certs/Kconfig
index 7ce41d4b541d..d78354bb5dfc 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -57,4 +57,12 @@ config SYSTEM_BLACKLIST_HASH_LIST
 	  wrapper to incorporate the list into the kernel.  Each <hash> should
 	  be a string of hex digits.
 
+config SECONDARY_TRUSTED_KEYRING
+	bool "Provide a keyring to which extra trustable keys may be added"
+	depends on SYSTEM_TRUSTED_KEYRING
+	help
+	  If set, provide a keyring to which extra keys may be added, provided
+	  those keys are not blacklisted and are vouched for by a key built
+	  into the kernel or already in the secondary trusted keyring.
+
 endmenu
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 5e76121d4cc2..4d930895f9ac 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -18,7 +18,10 @@
 #include <keys/system_keyring.h>
 #include <crypto/pkcs7.h>
 
-static struct key *system_trusted_keyring;
+static struct key *builtin_trusted_keys;
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+static struct key *secondary_trusted_keys;
+#endif
 
 extern __initconst const u8 system_certificate_list[];
 extern __initconst const unsigned long system_certificate_list_size;
@@ -33,25 +36,72 @@ int restrict_link_by_system_trusted(struct key *keyring,
 				    const struct key_type *type,
 				    const union key_payload *payload)
 {
-	return public_key_restrict_link(system_trusted_keyring, type, payload);
+	int ret;
+
+	/* If we have a secondary trusted keyring, then that contains a link
+	 * through to the builtin keyring and the search will follow that link.
+	 */
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+	if (type == &key_type_keyring &&
+	    keyring == secondary_trusted_keys &&
+	    payload == &builtin_trusted_keys->payload)
+		return 0;
+
+	ret = public_key_restrict_link(secondary_trusted_keys, type, payload);
+#else
+	ret = public_key_restrict_link(builtin_trusted_keys, type, payload);
+#endif
+	if (ret == 0 || ret == -EKEYREJECTED)
+		return ret;
+	return ret;
+}
+
+/**
+ * restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA
+ *
+ * Restrict the addition of keys into a keyring based on the key-to-be-added
+ * being vouched for by a key in the built in system keyring.
+ */
+int restrict_link_by_builtin_trusted(struct key *keyring,
+				     const struct key_type *type,
+				     const union key_payload *payload)
+{
+	return public_key_restrict_link(secondary_trusted_keys, type, payload);
 }
 
 /*
- * Load the compiled-in keys
+ * Create the trusted keyrings
  */
 static __init int system_trusted_keyring_init(void)
 {
-	pr_notice("Initialise system trusted keyring\n");
+	pr_notice("Initialise system trusted keyrings\n");
 
-	system_trusted_keyring =
-		keyring_alloc(".system_keyring",
+	builtin_trusted_keys =
+		keyring_alloc(".builtin_trusted_keys",
 			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
 			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
 			      KEY_ALLOC_NOT_IN_QUOTA,
+			      NULL, NULL);
+	if (IS_ERR(builtin_trusted_keys))
+		panic("Can't allocate builtin trusted keyring\n");
+
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+	secondary_trusted_keys =
+		keyring_alloc(".secondary_trusted_keys",
+			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
+			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+			       KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH |
+			       KEY_USR_WRITE),
+			      KEY_ALLOC_NOT_IN_QUOTA,
 			      restrict_link_by_system_trusted, NULL);
-	if (IS_ERR(system_trusted_keyring))
-		panic("Can't allocate system trusted keyring\n");
+	if (IS_ERR(secondary_trusted_keys))
+		panic("Can't allocate secondary trusted keyring\n");
+#endif
+
+	if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0)
+		panic("Can't link trusted keyrings\n");
+
 	return 0;
 }
 
@@ -87,7 +137,7 @@ static __init int load_system_certificate_list(void)
 		if (plen > end - p)
 			goto dodgy_cert;
 
-		key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
+		key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1),
 					   "asymmetric",
 					   NULL,
 					   p,
@@ -124,7 +174,8 @@ late_initcall(load_system_certificate_list);
  * @len: Size of @data.
  * @raw_pkcs7: The PKCS#7 message that is the signature.
  * @pkcs7_len: The size of @raw_pkcs7.
- * @trusted_keys: Trusted keys to use (NULL for system_trusted_keyring).
+ * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
+ *					(void *)1UL for all trusted keys).
  * @usage: The use to which the key is being put.
  * @view_content: Callback to gain access to content.
  * @ctx: Context for callback.
@@ -156,8 +207,15 @@ int verify_pkcs7_signature(const void *data, size_t len,
 	if (ret < 0)
 		goto error;
 
-	if (!trusted_keys)
-		trusted_keys = system_trusted_keyring;
+	if (!trusted_keys) {
+		trusted_keys = builtin_trusted_keys;
+	} else if (trusted_keys == (void *)1UL) {
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+		trusted_keys = secondary_trusted_keys;
+#else
+		trusted_keys = builtin_trusted_keys;
+#endif
+	}
 	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
 	if (ret < 0) {
 		if (ret == -ENOKEY)
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 15107dcc2ec4..b261362c8b2d 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -19,6 +19,10 @@
 extern int restrict_link_by_system_trusted(struct key *keyring,
 					   const struct key_type *type,
 					   const union key_payload *payload);
+
+extern int restrict_link_by_builtin_trusted(struct key *keyring,
+					    const struct key_type *type,
+					    const union key_payload *payload);
 #endif
 
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [RFC PATCH 20/20] IMA: Replace the .ima_mok keyring with the secondary system keyring [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (18 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 19/20] certs: Add a secondary system keyring that can be added to dynamically " David Howells
@ 2016-01-19 11:32 ` David Howells
  2016-01-20 17:24 ` [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings " Petko Manolov
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-01-19 11:32 UTC (permalink / raw)
  To: zohar; +Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Use the secondary system keyring instead of the .ima_mok keyring and remove
the latter.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/keys/system_keyring.h    |   15 -------------
 security/integrity/digsig.c      |   28 ++----------------------
 security/integrity/ima/Kconfig   |   18 ----------------
 security/integrity/ima/Makefile  |    1 -
 security/integrity/ima/ima_mok.c |   44 --------------------------------------
 5 files changed, 2 insertions(+), 104 deletions(-)
 delete mode 100644 security/integrity/ima/ima_mok.c

diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index b261362c8b2d..622c1760ecc9 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -45,19 +45,4 @@ static inline int is_key_blacklisted(const char *name)
 }
 #endif
 
-#ifdef CONFIG_IMA_MOK_KEYRING
-extern struct key *ima_mok_keyring;
-
-static inline struct key *get_ima_mok_keyring(void)
-{
-	return ima_mok_keyring;
-}
-#else
-static inline struct key *get_ima_mok_keyring(void)
-{
-	return NULL;
-}
-#endif /* CONFIG_IMA_MOK_KEYRING */
-
-
 #endif /* _KEYS_SYSTEM_KEYRING_H */
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 464d25e698ec..70fa199731f1 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -42,25 +42,6 @@ static bool init_keyring __initdata = true;
 static bool init_keyring __initdata;
 #endif
 
-/*
- * Restrict the addition of keys into the IMA keyring.
- *
- * Any key that needs to go in .ima keyring must be signed by CA in
- * either .system or .ima_mok keyrings.
- */
-static int restrict_link_by_ima_mok(struct key *keyring,
-				    const struct key_type *type,
-				    const union key_payload *payload)
-{
-	int ret;
-
-	ret = restrict_link_by_system_trusted(keyring, type, payload);
-	if (ret != -ENOKEY)
-		return ret;
-
-	return public_key_restrict_link(get_ima_mok_keyring(), type, payload);
-}
-
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 			    const char *digest, int digestlen)
 {
@@ -93,25 +74,20 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 
 int __init integrity_init_keyring(const unsigned int id)
 {
-	int (*restrict_link)(struct key *,
-			     const struct key_type *,
-			     const union key_payload *) = NULL;
 	const struct cred *cred = current_cred();
 	int err = 0;
 
 	if (!init_keyring)
 		return 0;
 
-	if (id == 1)
-		restrict_link = restrict_link_by_ima_mok;
-
 	keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
 				    KGIDT_INIT(0), cred,
 				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				     KEY_USR_VIEW | KEY_USR_READ |
 				     KEY_USR_WRITE | KEY_USR_SEARCH),
 				    KEY_ALLOC_NOT_IN_QUOTA,
-				    restrict_link, NULL);
+				    restrict_link_by_system_trusted,
+				    NULL);
 	if (IS_ERR(keyring[id])) {
 		err = PTR_ERR(keyring[id]);
 		pr_info("Can't allocate %s keyring (%d)\n",
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index e54a8a8dae94..5466cfe0305f 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -155,24 +155,6 @@ config IMA_TRUSTED_KEYRING
 
 	   This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING
 
-config IMA_MOK_KEYRING
-	bool "Create IMA machine owner keys (MOK) and blacklist keyrings"
-	depends on SYSTEM_TRUSTED_KEYRING
-	depends on IMA_TRUSTED_KEYRING
-	default n
-	help
-	   This option creates IMA MOK and blacklist keyrings.  IMA MOK is an
-	   intermediate keyring that sits between .system and .ima keyrings,
-	   effectively forming a simple CA hierarchy.  To successfully import a
-	   key into .ima_mok it must be signed by a key which CA is in .system
-	   keyring.  On turn any key that needs to go in .ima keyring must be
-	   signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty
-	   at kernel boot.
-
-	   IMA blacklist keyring contains all revoked IMA keys.  It is consulted
-	   before any other keyring.  If the search is successful the requested
-	   operation is rejected and error is returned to the caller.
-
 config IMA_LOAD_X509
 	bool "Load X509 certificate onto the '.ima' trusted keyring"
 	depends on IMA_TRUSTED_KEYRING
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index a8539f9e060f..d79263d2fdbf 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -8,4 +8,3 @@ obj-$(CONFIG_IMA) += ima.o
 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
 	 ima_policy.o ima_template.o ima_template_lib.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
-obj-$(CONFIG_IMA_MOK_KEYRING) += ima_mok.o
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
deleted file mode 100644
index 6b34770a6c9f..000000000000
--- a/security/integrity/ima/ima_mok.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2015 Juniper Networks, Inc.
- *
- * Author:
- * Petko Manolov <petko.manolov@konsulko.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- */
-
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/cred.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <keys/system_keyring.h>
-
-
-struct key *ima_mok_keyring;
-
-/*
- * Allocate the IMA MOK and blacklist keyrings
- */
-__init int ima_mok_init(void)
-{
-	pr_notice("Allocating IMA MOK and blacklist keyrings.\n");
-
-	ima_mok_keyring = keyring_alloc(".ima_mok",
-			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
-			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
-			      KEY_USR_VIEW | KEY_USR_READ |
-			      KEY_USR_WRITE | KEY_USR_SEARCH,
-			      KEY_ALLOC_NOT_IN_QUOTA,
-			      restrict_link_by_system_trusted, NULL);
-
-	if (IS_ERR(ima_mok_keyring))
-		panic("Can't allocate IMA MOK keyring.");
-	return 0;
-}
-device_initcall(ima_mok_init);

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (19 preceding siblings ...)
  2016-01-19 11:32 ` [RFC PATCH 20/20] IMA: Replace the .ima_mok keyring with the secondary system keyring " David Howells
@ 2016-01-20 17:24 ` Petko Manolov
  2016-01-20 18:57 ` Mimi Zohar
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 56+ messages in thread
From: Petko Manolov @ 2016-01-20 17:24 UTC (permalink / raw)
  To: David Howells; +Cc: zohar, linux-security-module, keyrings, linux-kernel

I assume this is intended for 4.6 or later, correct?


		Petko


On 16-01-19 11:30:26, David Howells wrote:
> 
> Here's a set of patches that changes how certificates/keys are determined
> to be trusted.  That's currently a two-step process:
> 
>  (1) Up until recently, when an X.509 certificate was parsed - no matter
>      the source - it was judged against the keys in .system_keyring,
>      assuming those keys to be trusted if they have KEY_FLAG_TRUSTED set
>      upon them.
> 
>      This has just been changed such that any key in the .ima_mok keyring
>      may also be used to judge the trustwortiness of a new certificate,
>      whether or not the .ima_mok keyring is meant to be consulted for
>      whatever process is being undertaken.
> 
>      If a certificate is determined to be trustworthy, KEY_FLAG_TRUSTED
>      will be set upon a key it is loaded into (if it is loaded into one),
>      no matter what the key is going to be loaded for.
> 
>  (2) If an X.509 certificate is loaded into a key, then that key - if
>      KEY_FLAG_TRUSTED gets set upon it - can be linked into any keyring
>      with KEY_FLAG_TRUSTED_ONLY set upon it.  This was meant to be the
>      system keyring only, but has been extended to various IMA keyrings.
> 
>      A user can at will link any key marked KEY_FLAG_TRUSTED into any
>      keyring marked KEY_FLAG_TRUSTED_ONLY if the relevant permissions masks
>      permit it.
> 
> These patches change that:
> 
>  (1) Trust becomes a matter of consulting the ring of trusted keys supplied
>      when the trust is evaluated only.
> 
>  (2) Asymmetric keys retain the source certificate signature information
>      for future evaluation rather than discarding it.
> 
>  (3) Every keyring can be supplied with its own manager function to
>      restrict what may be added to that keyring.  This is called whenever a
>      key is to be linked into the keyring to guard against a key being
>      created in one keyring and then linked across.
> 
>      This function is supplied with the keyring and the key type and
>      payload[*] of the key being linked in for use in its evaluation.  It
>      is permitted to use other data also, such as the contents of other
>      keyrings such as the system keyrings.
> 
>      [*] The type and payload are supplied instead of a key because as an
>      	 optimisation this function may be called whilst creating a key and
>      	 so may reject the proposed key between preparse and allocation.
> 
>  (4) A default manager function is provided that permits keys to be
>      restricted to only asymmetric keys that are vouched for by the
>      contents of the system keyring.
> 
>  (5) A key allocation flag, KEY_ALLOC_BYPASS_RESTRICTION, is made available
>      so that the kernel can initialise keyrings with keys that form the
>      root of the trust relationship.
> 
>  (6) KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed, along with
>      key_preparsed_payload::trusted.
> 
> This change also makes it possible for userspace to create a private set of
> trusted keys and then to seal it by setting a manager function where the
> private set is wholly independent of the kernel's trust relationships.
> 
> Further changes in the set involve extracting certain IMA special keyrings
> and making them generally global:
> 
>  (*) .system_keyring is renamed to .builtin_trusted_keys and remains read
>      only.  It carries only keys built in to the kernel.  It may be where
>      UEFI keys should be loaded - though that could better be the new
>      secondary keyring (see below).
> 
>  (*) An optional system blacklist keyring is created to replace the IMA
>      keyring.
> 
>      (*) A 'blacklist' key type is created that may contain a hex string in
>          its description (it carries no payload).  When an X.509
>          certificate is parsed, the system blacklist is searched for a
>          blacklist key that matches the TBS hash of the X.509 certificate
>          and if one is found, the certificate is considered blacklisted.
> 
>      (*) A list of blacklisted hashes can be added to the system blacklist
>          keyring at compile time.  In the future it should also be possible
>          to load this up from such as the UEFI blacklist.
> 
>      (*) Keys can be added to the blacklist keyring by root if the keys are
>      	 signed by a key in the builtin system keyring.  These can then be
>      	 searched for by asymmetric key ID.  This allows the functionality
>      	 of the IMA blacklist keyring to be replicated.
> 
>  	 It might be worth making an asymmetric key subtype that carries no
>  	 data to be used here as the cryptographic material is then just
>  	 dead weight since the IDs are what matter.
> 
>  (*) An optional secondary system keyring (called .secondary_trusted_keys)
>      is added to replace the IMA MOK keyring.
> 
>      (*) Keys can be added to the secondary keyring by root if the keys can
>      	 be vouched for by either ring of system keys.
> 
>  (*) Module signing and kexec only use .builtin_trusted_keys and do not use
>      the new secondary keyring, but they do consult the system blacklist.
> 
>  (*) If the kernel sees a PKCS#7 message with more than one signature, at
>      least one of which is blacklisted, it will permit the message if at
>      least one of the non-blacklisted signature chains is vouched for.  If
>      none are, then EKEYREJECTED will be given.  This error takes priority
>      over giving ENOPKG for unsupported encryption.
> 
> The patches can be found here also:
> 
> 	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust
> 
> David
> ---
> David Howells (20):
>       KEYS: Add an alloc flag to convey the builtinness of a key
>       KEYS: Add a system blacklist keyring
>       X.509: Allow X.509 certs to be blacklisted
>       X.509: Don't treat self-signed keys specially
>       KEYS: Generalise system_verify_data() to provide access to internal content
>       PKCS#7: Make trust determination dependent on contents of trust keyring
>       KEYS: Add a facility to restrict new links into a keyring
>       KEYS: Allow authentication data to be stored in an asymmetric key
>       KEYS: Add identifier pointers to public_key_signature struct
>       X.509: Retain the key verification data
>       X.509: Extract signature digest and make self-signed cert checks earlier
>       PKCS#7: Make the signature a pointer rather than embedding it
>       X.509: Move the trust validation code out to its own file
>       KEYS: Generalise x509_request_asymmetric_key()
>       KEYS: Move the point of trust determination to __key_link()
>       KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED
>       PKCS#7: Handle blacklisted certificates
>       IMA: Use the system blacklist keyring
>       certs: Add a secondary system keyring that can be added to dynamically
>       IMA: Replace the .ima_mok keyring with the secondary system keyring
> 
> 
>  Documentation/security/keys.txt           |   14 +
>  arch/x86/kernel/kexec-bzimage64.c         |   18 --
>  certs/Kconfig                             |   26 ++
>  certs/Makefile                            |    6 +
>  certs/blacklist.c                         |  184 +++++++++++++++++
>  certs/blacklist.h                         |    3 
>  certs/blacklist_hashes.c                  |    6 +
>  certs/blacklist_nohashes.c                |    5 
>  certs/system_keyring.c                    |  141 ++++++++++---
>  crypto/asymmetric_keys/Kconfig            |    1 
>  crypto/asymmetric_keys/Makefile           |    2 
>  crypto/asymmetric_keys/asymmetric_keys.h  |    2 
>  crypto/asymmetric_keys/asymmetric_type.c  |    7 -
>  crypto/asymmetric_keys/mscode_parser.c    |   21 +-
>  crypto/asymmetric_keys/pkcs7_key_type.c   |   66 +++---
>  crypto/asymmetric_keys/pkcs7_parser.c     |   59 +++--
>  crypto/asymmetric_keys/pkcs7_parser.h     |   12 -
>  crypto/asymmetric_keys/pkcs7_trust.c      |   44 ++--
>  crypto/asymmetric_keys/pkcs7_verify.c     |  141 ++++++-------
>  crypto/asymmetric_keys/public_key.c       |   24 ++
>  crypto/asymmetric_keys/public_key.h       |    6 +
>  crypto/asymmetric_keys/public_key_trust.c |  209 +++++++++++++++++++
>  crypto/asymmetric_keys/verify_pefile.c    |   40 +---
>  crypto/asymmetric_keys/verify_pefile.h    |    5 
>  crypto/asymmetric_keys/x509_cert_parser.c |   51 +++--
>  crypto/asymmetric_keys/x509_parser.h      |   13 +
>  crypto/asymmetric_keys/x509_public_key.c  |  318 +++++++++--------------------
>  fs/cifs/cifsacl.c                         |    2 
>  fs/nfs/nfs4idmap.c                        |    2 
>  include/crypto/pkcs7.h                    |    6 -
>  include/crypto/public_key.h               |   35 +--
>  include/keys/asymmetric-subtype.h         |    2 
>  include/keys/asymmetric-type.h            |    8 -
>  include/keys/system_keyring.h             |   52 ++---
>  include/linux/key-type.h                  |    1 
>  include/linux/key.h                       |   39 +++-
>  include/linux/verification.h              |   49 ++++
>  include/linux/verify_pefile.h             |   22 --
>  kernel/module_signing.c                   |    7 -
>  net/dns_resolver/dns_key.c                |    2 
>  net/rxrpc/ar-key.c                        |    4 
>  security/integrity/digsig.c               |   10 +
>  security/integrity/digsig_asymmetric.c    |   18 +-
>  security/integrity/ima/Kconfig            |   18 --
>  security/integrity/ima/Makefile           |    1 
>  security/integrity/ima/ima_mok.c          |   55 -----
>  security/keys/key.c                       |   44 +++-
>  security/keys/keyring.c                   |   26 ++
>  security/keys/persistent.c                |    4 
>  security/keys/process_keys.c              |   16 +
>  security/keys/request_key.c               |    4 
>  security/keys/request_key_auth.c          |    2 
>  52 files changed, 1131 insertions(+), 722 deletions(-)
>  create mode 100644 certs/blacklist.c
>  create mode 100644 certs/blacklist.h
>  create mode 100644 certs/blacklist_hashes.c
>  create mode 100644 certs/blacklist_nohashes.c
>  create mode 100644 crypto/asymmetric_keys/public_key_trust.c
>  create mode 100644 include/linux/verification.h
>  delete mode 100644 include/linux/verify_pefile.h
>  delete mode 100644 security/integrity/ima/ima_mok.c
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (20 preceding siblings ...)
  2016-01-20 17:24 ` [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings " Petko Manolov
@ 2016-01-20 18:57 ` Mimi Zohar
  2016-02-03 15:47 ` David Howells
  2016-02-03 15:56 ` David Howells
  23 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-01-20 18:57 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Here's a set of patches that changes how certificates/keys are determined
> to be trusted.  That's currently a two-step process:
> 
>  (1) Up until recently, when an X.509 certificate was parsed - no matter
>      the source - it was judged against the keys in .system_keyring,
>      assuming those keys to be trusted if they have KEY_FLAG_TRUSTED set
>      upon them.
> 
>      This has just been changed such that any key in the .ima_mok keyring

, if configured,

>      may also be used to judge the trustwortiness of a new certificate,
>      whether or not the .ima_mok keyring is meant to be consulted for
>      whatever process is being undertaken.
> 
>      If a certificate is determined to be trustworthy, KEY_FLAG_TRUSTED
>      will be set upon a key it is loaded into (if it is loaded into one),
>      no matter what the key is going to be loaded for.
> 
>  (2) If an X.509 certificate is loaded into a key, then that key - if
>      KEY_FLAG_TRUSTED gets set upon it - can be linked into any keyring
>      with KEY_FLAG_TRUSTED_ONLY set upon it.  This was meant to be the
>      system keyring only, but has been extended to various IMA keyrings.
> 
>      A user can at will link any key marked KEY_FLAG_TRUSTED into any
>      keyring marked KEY_FLAG_TRUSTED_ONLY if the relevant permissions masks
>      permit it.
> 
> These patches change that:
> 
>  (1) Trust becomes a matter of consulting the ring of trusted keys supplied
>      when the trust is evaluated only.
> 
>  (2) Asymmetric keys retain the source certificate signature information
>      for future evaluation rather than discarding it.
> 
>  (3) Every keyring can be supplied with its own manager function to
>      restrict what may be added to that keyring.  This is called whenever a
>      key is to be linked into the keyring to guard against a key being
>      created in one keyring and then linked across.
> 
>      This function is supplied with the keyring and the key type and
>      payload[*] of the key being linked in for use in its evaluation.  It
>      is permitted to use other data also, such as the contents of other
>      keyrings such as the system keyrings.
> 
>      [*] The type and payload are supplied instead of a key because as an
>      	 optimisation this function may be called whilst creating a key and
>      	 so may reject the proposed key between preparse and allocation.
> 
>  (4) A default manager function is provided that permits keys to be
>      restricted to only asymmetric keys that are vouched for by the
>      contents of the system keyring.
> 
>  (5) A key allocation flag, KEY_ALLOC_BYPASS_RESTRICTION, is made available
>      so that the kernel can initialise keyrings with keys that form the
>      root of the trust relationship.
> 
>  (6) KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed, along with
>      key_preparsed_payload::trusted.
> 
> This change also makes it possible for userspace to create a private set of
> trusted keys and then to seal it by setting a manager function where the
> private set is wholly independent of the kernel's trust relationships.
> 
> Further changes in the set involve extracting certain IMA special keyrings
> and making them generally global:
> 
>  (*) .system_keyring is renamed to .builtin_trusted_keys and remains read
>      only.  It carries only keys built in to the kernel.  It may be where
>      UEFI keys should be loaded - though that could better be the new
>      secondary keyring (see below).

or even better a UEFI specific keyring.

>  (*) An optional system blacklist keyring is created to replace the IMA
>      keyring.

to replace the IMA blacklist keyring.

>      (*) A 'blacklist' key type is created that may contain a hex string in
>          its description (it carries no payload).  When an X.509
>          certificate is parsed, the system blacklist is searched for a
>          blacklist key that matches the TBS hash of the X.509 certificate
>          and if one is found, the certificate is considered blacklisted.
> 
>      (*) A list of blacklisted hashes can be added to the system blacklist
>          keyring at compile time.  In the future it should also be possible
>          to load this up from such as the UEFI blacklist.
> 
>      (*) Keys can be added to the blacklist keyring by root if the keys are
>      	 signed by a key in the builtin system keyring.  These can then be
>      	 searched for by asymmetric key ID.  This allows the functionality
>      	 of the IMA blacklist keyring to be replicated.
> 
>  	 It might be worth making an asymmetric key subtype that carries no
>  	 data to be used here as the cryptographic material is then just
>  	 dead weight since the IDs are what matter.

I would go one step farther and say that only this new asymmetric key
subtype, that carries no data, be permitted.  Otherwise the same
certificate, that was used for loading the key in the first place, could
be inadvertently added to the blacklist.

Mimi

>  (*) An optional secondary system keyring (called .secondary_trusted_keys)
>      is added to replace the IMA MOK keyring.
> 
>      (*) Keys can be added to the secondary keyring by root if the keys can
>      	 be vouched for by either ring of system keys.
> 
>  (*) Module signing and kexec only use .builtin_trusted_keys and do not use
>      the new secondary keyring, but they do consult the system blacklist.
> 
>  (*) If the kernel sees a PKCS#7 message with more than one signature, at
>      least one of which is blacklisted, it will permit the message if at
>      least one of the non-blacklisted signature chains is vouched for.  If
>      none are, then EKEYREJECTED will be given.  This error takes priority
>      over giving ENOPKG for unsupported encryption.
> 
> The patches can be found here also:
> 
> 	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust
> 
> David
> ---
> David Howells (20):
>       KEYS: Add an alloc flag to convey the builtinness of a key
>       KEYS: Add a system blacklist keyring
>       X.509: Allow X.509 certs to be blacklisted
>       X.509: Don't treat self-signed keys specially
>       KEYS: Generalise system_verify_data() to provide access to internal content
>       PKCS#7: Make trust determination dependent on contents of trust keyring
>       KEYS: Add a facility to restrict new links into a keyring
>       KEYS: Allow authentication data to be stored in an asymmetric key
>       KEYS: Add identifier pointers to public_key_signature struct
>       X.509: Retain the key verification data
>       X.509: Extract signature digest and make self-signed cert checks earlier
>       PKCS#7: Make the signature a pointer rather than embedding it
>       X.509: Move the trust validation code out to its own file
>       KEYS: Generalise x509_request_asymmetric_key()
>       KEYS: Move the point of trust determination to __key_link()
>       KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED
>       PKCS#7: Handle blacklisted certificates
>       IMA: Use the system blacklist keyring
>       certs: Add a secondary system keyring that can be added to dynamically
>       IMA: Replace the .ima_mok keyring with the secondary system keyring
> 
> 
>  Documentation/security/keys.txt           |   14 +
>  arch/x86/kernel/kexec-bzimage64.c         |   18 --
>  certs/Kconfig                             |   26 ++
>  certs/Makefile                            |    6 +
>  certs/blacklist.c                         |  184 +++++++++++++++++
>  certs/blacklist.h                         |    3 
>  certs/blacklist_hashes.c                  |    6 +
>  certs/blacklist_nohashes.c                |    5 
>  certs/system_keyring.c                    |  141 ++++++++++---
>  crypto/asymmetric_keys/Kconfig            |    1 
>  crypto/asymmetric_keys/Makefile           |    2 
>  crypto/asymmetric_keys/asymmetric_keys.h  |    2 
>  crypto/asymmetric_keys/asymmetric_type.c  |    7 -
>  crypto/asymmetric_keys/mscode_parser.c    |   21 +-
>  crypto/asymmetric_keys/pkcs7_key_type.c   |   66 +++---
>  crypto/asymmetric_keys/pkcs7_parser.c     |   59 +++--
>  crypto/asymmetric_keys/pkcs7_parser.h     |   12 -
>  crypto/asymmetric_keys/pkcs7_trust.c      |   44 ++--
>  crypto/asymmetric_keys/pkcs7_verify.c     |  141 ++++++-------
>  crypto/asymmetric_keys/public_key.c       |   24 ++
>  crypto/asymmetric_keys/public_key.h       |    6 +
>  crypto/asymmetric_keys/public_key_trust.c |  209 +++++++++++++++++++
>  crypto/asymmetric_keys/verify_pefile.c    |   40 +---
>  crypto/asymmetric_keys/verify_pefile.h    |    5 
>  crypto/asymmetric_keys/x509_cert_parser.c |   51 +++--
>  crypto/asymmetric_keys/x509_parser.h      |   13 +
>  crypto/asymmetric_keys/x509_public_key.c  |  318 +++++++++--------------------
>  fs/cifs/cifsacl.c                         |    2 
>  fs/nfs/nfs4idmap.c                        |    2 
>  include/crypto/pkcs7.h                    |    6 -
>  include/crypto/public_key.h               |   35 +--
>  include/keys/asymmetric-subtype.h         |    2 
>  include/keys/asymmetric-type.h            |    8 -
>  include/keys/system_keyring.h             |   52 ++---
>  include/linux/key-type.h                  |    1 
>  include/linux/key.h                       |   39 +++-
>  include/linux/verification.h              |   49 ++++
>  include/linux/verify_pefile.h             |   22 --
>  kernel/module_signing.c                   |    7 -
>  net/dns_resolver/dns_key.c                |    2 
>  net/rxrpc/ar-key.c                        |    4 
>  security/integrity/digsig.c               |   10 +
>  security/integrity/digsig_asymmetric.c    |   18 +-
>  security/integrity/ima/Kconfig            |   18 --
>  security/integrity/ima/Makefile           |    1 
>  security/integrity/ima/ima_mok.c          |   55 -----
>  security/keys/key.c                       |   44 +++-
>  security/keys/keyring.c                   |   26 ++
>  security/keys/persistent.c                |    4 
>  security/keys/process_keys.c              |   16 +
>  security/keys/request_key.c               |    4 
>  security/keys/request_key_auth.c          |    2 
>  52 files changed, 1131 insertions(+), 722 deletions(-)
>  create mode 100644 certs/blacklist.c
>  create mode 100644 certs/blacklist.h
>  create mode 100644 certs/blacklist_hashes.c
>  create mode 100644 certs/blacklist_nohashes.c
>  create mode 100644 crypto/asymmetric_keys/public_key_trust.c
>  create mode 100644 include/linux/verification.h
>  delete mode 100644 include/linux/verify_pefile.h
>  delete mode 100644 security/integrity/ima/ima_mok.c
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key " David Howells
@ 2016-01-20 18:58   ` Mimi Zohar
  2016-02-03 15:30   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-01-20 18:58 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Add KEY_ALLOC_BUILT_IN to convey that a key should have KEY_FLAG_BUILTIN
> set rather than setting it after the fact.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>

Acked-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

> ---
> 
>  certs/system_keyring.c |    4 ++--
>  include/linux/key.h    |    1 +
>  security/keys/key.c    |    2 ++
>  3 files changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/certs/system_keyring.c b/certs/system_keyring.c
> index 2570598b784d..f4180326c2e1 100644
> --- a/certs/system_keyring.c
> +++ b/certs/system_keyring.c
> @@ -84,12 +84,12 @@ static __init int load_system_certificate_list(void)
>  					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  					   KEY_USR_VIEW | KEY_USR_READ),
>  					   KEY_ALLOC_NOT_IN_QUOTA |
> -					   KEY_ALLOC_TRUSTED);
> +					   KEY_ALLOC_TRUSTED |
> +					   KEY_ALLOC_BUILT_IN);
>  		if (IS_ERR(key)) {
>  			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
>  			       PTR_ERR(key));
>  		} else {
> -			set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
>  			pr_notice("Loaded X.509 cert '%s'\n",
>  				  key_ref_to_ptr(key)->description);
>  			key_ref_put(key);
> diff --git a/include/linux/key.h b/include/linux/key.h
> index 7321ab8ef949..5f5b1129dc92 100644
> --- a/include/linux/key.h
> +++ b/include/linux/key.h
> @@ -219,6 +219,7 @@ extern struct key *key_alloc(struct key_type *type,
>  #define KEY_ALLOC_QUOTA_OVERRUN	0x0001	/* add to quota, permit even if overrun */
>  #define KEY_ALLOC_NOT_IN_QUOTA	0x0002	/* not in quota */
>  #define KEY_ALLOC_TRUSTED	0x0004	/* Key should be flagged as trusted */
> +#define KEY_ALLOC_BUILT_IN	0x0008	/* Key is built into kernel */
> 
>  extern void key_revoke(struct key *key);
>  extern void key_invalidate(struct key *key);
> diff --git a/security/keys/key.c b/security/keys/key.c
> index 07a87311055c..48dbfa543bcb 100644
> --- a/security/keys/key.c
> +++ b/security/keys/key.c
> @@ -296,6 +296,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
>  		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
>  	if (flags & KEY_ALLOC_TRUSTED)
>  		key->flags |= 1 << KEY_FLAG_TRUSTED;
> +	if (flags & KEY_ALLOC_BUILT_IN)
> +		key->flags |= 1 << KEY_FLAG_BUILTIN;
> 
>  #ifdef KEY_DEBUGGING
>  	key->magic = KEY_DEBUG_MAGIC;

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
@ 2016-01-20 19:31   ` Mimi Zohar
  2016-01-20 20:26   ` Mimi Zohar
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-01-20 19:31 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Add the following:
> 
>  (1) A new system keyring that is used to store information about
>      blacklisted certificates and signatures.
> 
>  (2) A new key type (called 'blacklist') that is used to store a
>      blacklisted hash in its description as a hex string.  The key accepts
>      no payload.

>  (3) The ability to configure a list of blacklisted hashes into the kernel
>      at build time.  This is done by setting
>      CONFIG_SYSTEM_BLACKLIST_HASH_LIST to the filename of a list of hashes
>      that are in the form:
> 
> 	"<hash>", "<hash>", ..., "<hash>"
> 
>      where each <hash> is a hex string representation of the hash and must
>      include all necessary leading zeros to pad the hash to the right size.

Is the output of "keyctl print" the hex string representation?  Update
keys documentation?

> The above are enabled with CONFIG_SYSTEM_BLACKLIST_KEYRING.
> 
> Once the kernel is booted, the blacklist keyring can be listed:
> 
> 	root@andromeda ~]# keyctl show %:.blacklist
> 	Keyring
> 	 723359729 ---lswrv      0     0  keyring: .blacklist
> 	 676257228 ---lswrv      0     0   \_ blacklist: 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46
> 
> The blacklist cannot currently be modified by userspace, but it will be
> possible to load it, for example, from the UEFI blacklist database.

When loading the UEFI blacklist database is enabled, it should be
configurable.

> In the future, it should also be made possible to load blacklisted
> asymmetric keys in here too.

Please update to reflect patch 3/20 "X.509: Allow X.509 certs to be
blacklisted" adds this support.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
  2016-01-20 19:31   ` Mimi Zohar
@ 2016-01-20 20:26   ` Mimi Zohar
  2016-02-03 15:27   ` David Howells
  2016-02-03 15:29   ` David Howells
  3 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-01-20 20:26 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:

> diff --git a/certs/blacklist_hashes.c b/certs/blacklist_hashes.c
> new file mode 100644
> index 000000000000..5bd449f7db17
> --- /dev/null
> +++ b/certs/blacklist_hashes.c
> @@ -0,0 +1,6 @@
> +#include "blacklist.h"
> +
> +const char __initdata *const blacklist_hashes[] = {
> +#include CONFIG_SYSTEM_BLACKLIST_HASH_LIST
> +	, NULL
> +};

It seems CONFIG_SYSTEM_BLACKLIST_HASH_LIST path is expected to be
relative to
the certs directory, not the build root directory.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted " David Howells
@ 2016-01-20 20:33   ` Mimi Zohar
  2016-02-03 15:46   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-01-20 20:33 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Allow X.509 certs to be blacklisted based on their TBS hash. 

What is the TBS hash?  This doesn't seem to be the key identifier.  The
cert associated with this key identifier is loaded onto the .ima
keyring.

eg:  openssl x509 -in <pathname> -inform DER -notext -out

<snip>

        X509v3 extensions:
            X509v3 Subject Key Identifier: 

71:12:39:B3:AB:E6:8D:BF:70:E7:26:DE:C8:4A:3F:5F:17:EF:00:6C

# keyctl show %keyring:.blacklist
Keyring
 466574863 ---lswrv      0     0  keyring: .blacklist
 433453563 ---lswrv      0     0   \_ blacklist:
711239b3abe68dbf70e726dec84a3f5f17ef006c

Mimi

>  This is
> convenient since we have to determine this anyway to be able to check the
> signature on an X.509 certificate.
> 
> If a certificate built into the kernel is blacklisted, something like the
> following might then be seen during boot:
> 
> 	X.509: Cert 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46 is blacklisted
> 	Problem loading in-kernel X.509 certificate (-129)
> 
> where the hex string shown is the blacklisted hash.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 04/20] X.509: Don't treat self-signed keys specially [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 04/20] X.509: Don't treat self-signed keys specially " David Howells
@ 2016-01-20 20:40   ` Mimi Zohar
  0 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-01-20 20:40 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Trust for a self-signed certificate can normally only be determined by
> whether we obtained it from a trusted location (ie. it was built into the
> kernel at compile time), so there's not really any point in checking it -
> we could verify that the signature is valid, but it doesn't really tell us
> anything if the signature checks out.
> 
> However, there's a bug in the code determining whether a certificate is
> self-signed or not - if they have neither AKID nor SKID then we just assume
> that the cert is self-signed, which may not be true.
> 
> Given this, remove the code that treats self-signed certs specially when it
> comes to evaluating trustability and attempt to evaluate them as ordinary
> signed certificates.  We then expect self-signed certificates to fail the
> trustability check and be marked as untrustworthy in x509_key_preparse().
> 
> Note that there is the possibility of the trustability check on a
> self-signed cert then succeeding.  This is most likely to happen when a
> duplicate of the certificate is already on the trust keyring - in which
> case it shouldn't be a problem.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: David Woodhouse <David.Woodhouse@intel.com>
> cc: Mimi Zohar <zohar@linux.vnet.ibm.com>

Acked-by:  Mimi Zohar <zohar@linux.vnet.ibm.com

> ---
> 
>  crypto/asymmetric_keys/x509_public_key.c |   25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
> index c4f3c40a4ab9..630c1c331fe1 100644
> --- a/crypto/asymmetric_keys/x509_public_key.c
> +++ b/crypto/asymmetric_keys/x509_public_key.c
> @@ -265,6 +265,9 @@ static int x509_validate_trust(struct x509_certificate *cert,
>  	struct key *key;
>  	int ret = 1;
> 
> +	if (!cert->akid_id && !cert->akid_skid)
> +		return 1;
> +
>  	if (!trust_keyring)
>  		return -EOPNOTSUPP;
> 
> @@ -322,19 +325,23 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
>  	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
>  	cert->pub->id_type = PKEY_ID_X509;
> 
> -	/* Check the signature on the key if it appears to be self-signed */
> -	if ((!cert->akid_skid && !cert->akid_id) ||
> -	    asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
> -	    asymmetric_key_id_same(cert->id, cert->akid_id)) {
> -		ret = x509_check_signature(cert->pub, cert); /* self-signed */
> -		if (ret < 0)
> -			goto error_free_cert;
> -	} else if (!prep->trusted) {
> +	/* See if we can derive the trustability of this certificate.
> +	 *
> +	 * When it comes to self-signed certificates, we cannot evaluate
> +	 * trustedness except by the fact that we obtained it from a trusted
> +	 * location.  So we just rely on x509_validate_trust() failing in this
> +	 * case.
> +	 *
> +	 * Note that there's a possibility of a self-signed cert matching a
> +	 * cert that we have (most likely a duplicate that we already trust) -
> +	 * in which case it will be marked trusted.
> +	 */
> +	if (!prep->trusted) {
>  		ret = x509_validate_trust(cert, get_system_trusted_keyring());
>  		if (ret)
>  			ret = x509_validate_trust(cert, get_ima_mok_keyring());
>  		if (!ret)
> -			prep->trusted = 1;
> +			prep->trusted = true;
>  	}
> 
>  	/* Don't permit addition of blacklisted keys */
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
  2016-01-20 19:31   ` Mimi Zohar
  2016-01-20 20:26   ` Mimi Zohar
@ 2016-02-03 15:27   ` David Howells
  2016-02-08 13:34     ` Mimi Zohar
                       ` (2 more replies)
  2016-02-03 15:29   ` David Howells
  3 siblings, 3 replies; 56+ messages in thread
From: David Howells @ 2016-02-03 15:27 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> >  (3) The ability to configure a list of blacklisted hashes into the kernel
> >      at build time.  This is done by setting
> >      CONFIG_SYSTEM_BLACKLIST_HASH_LIST to the filename of a list of hashes
> >      that are in the form:
> > 
> > 	"<hash>", "<hash>", ..., "<hash>"
> > 
> >      where each <hash> is a hex string representation of the hash and must
> >      include all necessary leading zeros to pad the hash to the right size.
> 
> Is the output of "keyctl print" the hex string representation?

No, there is no payload and no read method.  "keyctl desc" will return the hex
string representation.

>  Update keys documentation?

Not a bad idea, but it should probably go in a separate document, along with
info about asymmetric keys.

> > The blacklist cannot currently be modified by userspace, but it will be
> > possible to load it, for example, from the UEFI blacklist database.
> 
> When loading the UEFI blacklist database is enabled, it should be
> configurable.

Probably.  That patch isn't added yet though.

> > In the future, it should also be made possible to load blacklisted
> > asymmetric keys in here too.
> 
> Please update to reflect patch 3/20 "X.509: Allow X.509 certs to be
> blacklisted" adds this support.

Changed to:

	A later commit will make it possible to load blacklisted asymmetric
	keys in here too.
 
David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
                     ` (2 preceding siblings ...)
  2016-02-03 15:27   ` David Howells
@ 2016-02-03 15:29   ` David Howells
  3 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-02-03 15:29 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> It seems CONFIG_SYSTEM_BLACKLIST_HASH_LIST path is expected to be relative
> to the certs directory, not the build root directory.

There's not a lot I can do about that without fabricating the blacklist C file
with a script rather than using a #include.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key " David Howells
  2016-01-20 18:58   ` Mimi Zohar
@ 2016-02-03 15:30   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: David Howells @ 2016-02-03 15:30 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> > Add KEY_ALLOC_BUILT_IN to convey that a key should have KEY_FLAG_BUILTIN
> > set rather than setting it after the fact.
> > 
> > Signed-off-by: David Howells <dhowells@redhat.com>
> 
> Acked-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

Thanks.  I'm moving this onto my keys-next branch.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]
  2016-01-19 11:30 ` [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted " David Howells
  2016-01-20 20:33   ` Mimi Zohar
@ 2016-02-03 15:46   ` David Howells
  2016-02-05 16:16     ` Mimi Zohar
  1 sibling, 1 reply; 56+ messages in thread
From: David Howells @ 2016-02-03 15:46 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> > Allow X.509 certs to be blacklisted based on their TBS hash. 
> 
> What is the TBS hash?  This doesn't seem to be the key identifier.

It's the TBSCertificate hash (I'll change to calling it that in the patch
description).  "TBS" stands for "To Be Signed".  This is what is hashed for
the signature to be generated upon - so it's something we have to expend
resources calculating anyway.

The reason I'm using this is this is what UEFI puts into its blacklist.  See:

	http://uefi.blogspot.co.uk/2013/09/uefi-24-review-part-13-hash-of.html

To quote:

	Now, in the UEFI 2.4 specification, three new types of signatures for
	the black list were added. Specifically, the various recommended forms
	of the To-Be-Signed hash value (160, 256 and 512-bits) which are
	created during the creation of a certificate could be added to the
	black list instead of the certificate itself.

> The cert associated with this key identifier is loaded onto the .ima
> keyring.

We could also check that.  There's no requirement that we only check the TBS -
but the TBS hash is something we must check.

I wonder if I should mark the blacklist key as to what the value it holds
should be checked against.  There's a number of different things we could put
in there:

 (1) TBSCertificate hash.

 (2) Subject Key Identifier content.

 (3) Authenticode Binary hash (for PE files).

 (4) PKCS#7 component digest.

> eg:  openssl x509 -in <pathname> -inform DER -notext -out
> 
> <snip>
> 
>         X509v3 extensions:
>             X509v3 Subject Key Identifier: 
> 
> 71:12:39:B3:AB:E6:8D:BF:70:E7:26:DE:C8:4A:3F:5F:17:EF:00:6C

Note that this isn't a mandatory field and if it's not present, we have no way
to calculate it as there's no one standard-defined method.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (21 preceding siblings ...)
  2016-01-20 18:57 ` Mimi Zohar
@ 2016-02-03 15:47 ` David Howells
  2016-02-03 15:56 ` David Howells
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-02-03 15:47 UTC (permalink / raw)
  To: Petko Manolov
  Cc: dhowells, zohar, linux-security-module, keyrings, linux-kernel

Petko Manolov <petkan@mip-labs.com> wrote:

> I assume this is intended for 4.6 or later, correct?

At this point, yes.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]
  2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
                   ` (22 preceding siblings ...)
  2016-02-03 15:47 ` David Howells
@ 2016-02-03 15:56 ` David Howells
  23 siblings, 0 replies; 56+ messages in thread
From: David Howells @ 2016-02-03 15:56 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> >      (*) Keys can be added to the blacklist keyring by root if the keys are
> >      	 signed by a key in the builtin system keyring.  These can then be
> >      	 searched for by asymmetric key ID.  This allows the functionality
> >      	 of the IMA blacklist keyring to be replicated.
> > 
> >  	 It might be worth making an asymmetric key subtype that carries no
> >  	 data to be used here as the cryptographic material is then just
> >  	 dead weight since the IDs are what matter.
> 
> I would go one step farther and say that only this new asymmetric key
> subtype, that carries no data, be permitted.  Otherwise the same
> certificate, that was used for loading the key in the first place, could
> be inadvertently added to the blacklist.

Sounds reasonable.  The question then is how to select the subtype to be
added.  The preparse has no concept of where the key is going to end up.

Maybe I need the following system call:

	blacklist_key(const char *type, const char *description,
                      const void *payload, size_t plen,
                      key_serial_t keyring);

to tell the parser what we intend.

If I can drop the destination keyring argument, I can make it a keyctl()
instead.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]
  2016-02-03 15:46   ` David Howells
@ 2016-02-05 16:16     ` Mimi Zohar
  0 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-05 16:16 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

Hi David,

On Wed, 2016-02-03 at 15:46 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 
> > > Allow X.509 certs to be blacklisted based on their TBS hash. 
> > 
> > What is the TBS hash?  This doesn't seem to be the key identifier.
> 
> It's the TBSCertificate hash (I'll change to calling it that in the patch
> description).  "TBS" stands for "To Be Signed".  This is what is hashed for
> the signature to be generated upon - so it's something we have to expend
> resources calculating anyway.
> 
> The reason I'm using this is this is what UEFI puts into its blacklist.  See:
> 
> 	http://uefi.blogspot.co.uk/2013/09/uefi-24-review-part-13-hash-of.html
> 
> To quote:
> 
> 	Now, in the UEFI 2.4 specification, three new types of signatures for
> 	the black list were added. Specifically, the various recommended forms
> 	of the To-Be-Signed hash value (160, 256 and 512-bits) which are
> 	created during the creation of a certificate could be added to the
> 	black list instead of the certificate itself.
> 
> > The cert associated with this key identifier is loaded onto the .ima
> > keyring.
> 
> We could also check that.  There's no requirement that we only check the TBS -
> but the TBS hash is something we must check.

Ok, but before "IMA: Use the system blacklist keyring" patch, this needs
to be addressed.

> I wonder if I should mark the blacklist key as to what the value it holds
> should be checked against.  There's a number of different things we could put
> in there:
> 
>  (1) TBSCertificate hash.
> 
>  (2) Subject Key Identifier content.
> 
>  (3) Authenticode Binary hash (for PE files).
> 
>  (4) PKCS#7 component digest.

Ok

> > eg:  openssl x509 -in <pathname> -inform DER -notext -out
> > 
> > <snip>
> > 
> >         X509v3 extensions:
> >             X509v3 Subject Key Identifier: 
> > 
> > 71:12:39:B3:AB:E6:8D:BF:70:E7:26:DE:C8:4A:3F:5F:17:EF:00:6C
> 
> Note that this isn't a mandatoryy field and if it's not present, we have no way
> to calculate it as there's no one standard-defined method.

The hex string appears when displaying the keys.  For example, 
 keyctl show %keyring:.ima shows:

734429129 --als--v      0     0   \_ asymmetric: : local: signing key:
711239b3abe68dbf70e726dec84a3f5f17ef006c

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a keyring [ver #2]
  2016-01-19 11:31 ` [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a " David Howells
@ 2016-02-08 11:59   ` Mimi Zohar
  2016-02-29 15:49   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 11:59 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:31 +0000, David Howells wrote:
> Add a facility whereby proposed new links to be added to a keyring can be
> vetted, permitting them to be rejected if necessary.  This can be used to
> block public keys from which the signature cannot be verified or for which
> the signature verification fails.  It could also be used to provide
> blacklisting.
> 
> This affects operations like add_key(), KEYCTL_LINK and KEYCTL_INSTANTIATE.
> 
> To this end:
> 
>  (1) A function pointer is added to the key struct that, if set, points to
>      the vetting function.  This is called as:
> 
> 	int (*restrict_link)(struct key *keyring,
> 			     const struct key_type *key_type,
> 			     unsigned long key_flags,
> 			     const union key_payload *key_payload),
> 
>      where 'keyring' will be the keyring being added to, key_type and
>      key_payload will describe the key being added and key_flags[*] can be
>      AND'ed with KEY_FLAG_TRUSTED.
> 
>      [*] This parameter will be removed in a later patch when
>      	 KEY_FLAG_TRUSTED is removed.
> 
>      The function should return 0 to allow the link to take place or an
>      error (typically -ENOKEY, -ENOPKG or -EKEYREJECTED) to reject the
>      link.
> 
>      The pointer should not be set directly, but rather should be set
>      through keyring_alloc().
> 
>      Note that if called during add_key(), preparse is called before this
>      method, but a key isn't actually allocated until after this function
>      is called.
> 
>  (2) KEY_ALLOC_BYPASS_RESTRICTION is added.  This can be passed to
>      key_create_or_update() or key_instantiate_and_link() to bypass the
>      restriction check.
> 
>  (3) KEY_FLAG_TRUSTED_ONLY is removed.  The entire contents of a keyring
>      with this restriction emplaced can be considered 'trustworthy' by
>      virtue of being in the keyring when that keyring is consulted.
> 
>  (4) key_alloc() and keyring_alloc() take an extra argument that will be
>      used to set restrict_link in the new key.  This ensures that the
>      pointer is set before the key is published, thus preventing a window
>      of unrestrictedness.  Normally this argument will be NULL.
> 
>  (5) As a temporary affair, keyring_restrict_trusted_only() is added.  It
>      should be passed to keyring_alloc() as the extra argument instead of
>      setting KEY_FLAG_TRUSTED_ONLY on a keyring.  This will be replaced in
>      a later patch with functions that look in the appropriate places for
>      authoritative keys.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>

Rephrase restrict_link documentation comment inline below.

Reviewed-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

> ---
> 
>  Documentation/security/keys.txt  |   14 ++++++++++
>  certs/blacklist.c                |    2 +
>  certs/system_keyring.c           |    8 +++---
>  fs/cifs/cifsacl.c                |    2 +
>  fs/nfs/nfs4idmap.c               |    2 +
>  include/linux/key.h              |   48 ++++++++++++++++++++++++++++-------
>  net/dns_resolver/dns_key.c       |    2 +
>  net/rxrpc/ar-key.c               |    4 +--
>  security/integrity/digsig.c      |    7 ++---
>  security/integrity/ima/ima_mok.c |    8 +++---
>  security/keys/key.c              |   43 ++++++++++++++++++++++++++-----
>  security/keys/keyring.c          |   52 +++++++++++++++++++++++++++++++++-----
>  security/keys/persistent.c       |    4 +--
>  security/keys/process_keys.c     |   16 +++++++-----
>  security/keys/request_key.c      |    4 +--
>  security/keys/request_key_auth.c |    2 +
>  16 files changed, 165 insertions(+), 53 deletions(-)
> 
> diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
> index 8c183873b2b7..3e2e958f2091 100644
> --- a/Documentation/security/keys.txt
> +++ b/Documentation/security/keys.txt
> @@ -999,6 +999,10 @@ payload contents" for more information.
>  	struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
>  				  const struct cred *cred,
>  				  key_perm_t perm,
> +				  int (*restrict_link)(struct key *,
> +						       const struct key_type *,
> +						       unsigned long,
> +						       const union key_payload *),
>  				  unsigned long flags,
>  				  struct key *dest);
> 
> @@ -1010,6 +1014,16 @@ payload contents" for more information.
>      KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
>      towards the user's quota).  Error ENOMEM can also be returned.
> 
> +    If restrict_link not NULL, it should point to a function will be called to
> +    vet all attempts to link keys into the keyring, though this can be
> +    overridden by passing KEY_ALLOC_BYPASS_RESTRICTION to
> +    key_create_or_update().

Please fix the first part of the sentence.   Maybe add an example of
when it is appropriate to bypass the restriction - (eg. loading the
builtin keys).

> +
> +    When called, the restriction function will be passed the keyring being
> +    added to, the key flags value and the type and payload of the key being
> +    added.  Note that when a new key is being created, this is called between
> +    payload preparsing and actual key creation.
> +
> 
>  (*) To check the validity of a key, this function can be called:
> 
> diff --git a/certs/blacklist.c b/certs/blacklist.c
> index 5f54baae3a32..7f769479c17b 100644
> --- a/certs/blacklist.c
> +++ b/certs/blacklist.c
> @@ -148,7 +148,7 @@ static int __init blacklist_init(void)
>  			      KEY_USR_SEARCH,
>  			      KEY_ALLOC_NOT_IN_QUOTA |
>  			      KEY_FLAG_KEEP,
> -			      NULL);
> +			      NULL, NULL);
>  	if (IS_ERR(blacklist_keyring))
>  		panic("Can't allocate system blacklist keyring\n");
> 
> diff --git a/certs/system_keyring.c b/certs/system_keyring.c
> index dc18869ff680..417d65882870 100644
> --- a/certs/system_keyring.c
> +++ b/certs/system_keyring.c
> @@ -36,11 +36,10 @@ static __init int system_trusted_keyring_init(void)
>  			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
>  			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
> -			      KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +			      KEY_ALLOC_NOT_IN_QUOTA,
> +			      keyring_restrict_trusted_only, NULL);
>  	if (IS_ERR(system_trusted_keyring))
>  		panic("Can't allocate system trusted keyring\n");
> -
> -	set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
>  	return 0;
>  }
> 
> @@ -85,7 +84,8 @@ static __init int load_system_certificate_list(void)
>  					   KEY_USR_VIEW | KEY_USR_READ),
>  					   KEY_ALLOC_NOT_IN_QUOTA |
>  					   KEY_ALLOC_TRUSTED |
> -					   KEY_ALLOC_BUILT_IN);
> +					   KEY_ALLOC_BUILT_IN |
> +					   KEY_ALLOC_BYPASS_RESTRICTION);
>  		if (IS_ERR(key)) {
>  			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
>  			       PTR_ERR(key));
> diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
> index 3f93125916bf..71e8a56e9479 100644
> --- a/fs/cifs/cifsacl.c
> +++ b/fs/cifs/cifsacl.c
> @@ -360,7 +360,7 @@ init_cifs_idmap(void)
>  				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
>  		goto failed_put_cred;
> diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
> index 5ba22c6b0ffa..c444285bb1b1 100644
> --- a/fs/nfs/nfs4idmap.c
> +++ b/fs/nfs/nfs4idmap.c
> @@ -201,7 +201,7 @@ int nfs_idmap_init(void)
>  				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
>  		goto failed_put_cred;
> diff --git a/include/linux/key.h b/include/linux/key.h
> index 5f5b1129dc92..c331b8bed035 100644
> --- a/include/linux/key.h
> +++ b/include/linux/key.h
> @@ -174,10 +174,9 @@ struct key {
>  #define KEY_FLAG_ROOT_CAN_CLEAR	6	/* set if key can be cleared by root without permission */
>  #define KEY_FLAG_INVALIDATED	7	/* set if key has been invalidated */
>  #define KEY_FLAG_TRUSTED	8	/* set if key is trusted */
> -#define KEY_FLAG_TRUSTED_ONLY	9	/* set if keyring only accepts links to trusted keys */
> -#define KEY_FLAG_BUILTIN	10	/* set if key is builtin */
> -#define KEY_FLAG_ROOT_CAN_INVAL	11	/* set if key can be invalidated by root without permission */
> -#define KEY_FLAG_KEEP		12	/* set if key should not be removed */
> +#define KEY_FLAG_BUILTIN	9	/* set if key is built in to the kernel */
> +#define KEY_FLAG_ROOT_CAN_INVAL	10	/* set if key can be invalidated by root without permission */
> +#define KEY_FLAG_KEEP		11	/* set if key should not be removed */
> 
>  	/* the key type and key description string
>  	 * - the desc is used to match a key against search criteria
> @@ -205,6 +204,21 @@ struct key {
>  		};
>  		int reject_error;
>  	};
> +
> +	/* This is set on a keyring to restrict the addition of a link to a key
> +	 * to it.  If this method isn't provided then it is assumed that the
> +	 * keyring is open to any addition.  It is ignored for non-keyring
> +	 * keys.
> +	 *
> +	 * This is intended for use with rings of trusted keys whereby addition
> +	 * to the keyring needs to be controlled.  KEY_ALLOC_BYPASS_RESTRICTION
> +	 * overrides this, allowing the kernel to add extra keys without
> +	 * restriction.
> +	 */
> +	int (*restrict_link)(struct key *keyring,
> +			     const struct key_type *type,
> +			     unsigned long flags,
> +			     const union key_payload *payload);
>  };
> 
>  extern struct key *key_alloc(struct key_type *type,
> @@ -212,14 +226,19 @@ extern struct key *key_alloc(struct key_type *type,
>  			     kuid_t uid, kgid_t gid,
>  			     const struct cred *cred,
>  			     key_perm_t perm,
> -			     unsigned long flags);
> +			     unsigned long flags,
> +			     int (*restrict_link)(struct key *,
> +						  const struct key_type *,
> +						  unsigned long,
> +						  const union key_payload *));
> 
> 
> -#define KEY_ALLOC_IN_QUOTA	0x0000	/* add to quota, reject if would overrun */
> -#define KEY_ALLOC_QUOTA_OVERRUN	0x0001	/* add to quota, permit even if overrun */
> -#define KEY_ALLOC_NOT_IN_QUOTA	0x0002	/* not in quota */
> -#define KEY_ALLOC_TRUSTED	0x0004	/* Key should be flagged as trusted */
> -#define KEY_ALLOC_BUILT_IN	0x0008	/* Key is built into kernel */
> +#define KEY_ALLOC_IN_QUOTA		0x0000	/* add to quota, reject if would overrun */
> +#define KEY_ALLOC_QUOTA_OVERRUN		0x0001	/* add to quota, permit even if overrun */
> +#define KEY_ALLOC_NOT_IN_QUOTA		0x0002	/* not in quota */
> +#define KEY_ALLOC_TRUSTED		0x0004	/* Key should be flagged as trusted */
> +#define KEY_ALLOC_BUILT_IN		0x0008	/* Key is built into kernel */
> +#define KEY_ALLOC_BYPASS_RESTRICTION	0x0010	/* Override the check on restricted keyrings */
> 
>  extern void key_revoke(struct key *key);
>  extern void key_invalidate(struct key *key);
> @@ -288,8 +307,17 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid
>  				 const struct cred *cred,
>  				 key_perm_t perm,
>  				 unsigned long flags,
> +				 int (*restrict_link)(struct key *,
> +						      const struct key_type *,
> +						      unsigned long,
> +						      const union key_payload *),
>  				 struct key *dest);
> 
> +extern int keyring_restrict_trusted_only(struct key *keyring,
> +					 const struct key_type *type,
> +					 unsigned long,
> +					 const union key_payload *payload);
> +
>  extern int keyring_clear(struct key *keyring);
> 
>  extern key_ref_t keyring_search(key_ref_t keyring,
> diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
> index c79b85eb4d4c..8737412c7b27 100644
> --- a/net/dns_resolver/dns_key.c
> +++ b/net/dns_resolver/dns_key.c
> @@ -281,7 +281,7 @@ static int __init init_dns_resolver(void)
>  				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
>  		goto failed_put_cred;
> diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
> index 3f6571651d32..b8e87a16c544 100644
> --- a/net/rxrpc/ar-key.c
> +++ b/net/rxrpc/ar-key.c
> @@ -965,7 +965,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
> 
>  	key = key_alloc(&key_type_rxrpc, "x",
>  			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
> -			KEY_ALLOC_NOT_IN_QUOTA);
> +			KEY_ALLOC_NOT_IN_QUOTA, NULL);
>  	if (IS_ERR(key)) {
>  		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
>  		return -ENOMEM;
> @@ -1012,7 +1012,7 @@ struct key *rxrpc_get_null_key(const char *keyname)
> 
>  	key = key_alloc(&key_type_rxrpc, keyname,
>  			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
> -			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
> +			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
>  	if (IS_ERR(key))
>  		return key;
> 
> diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
> index 8ef15118cc78..659566c2200b 100644
> --- a/security/integrity/digsig.c
> +++ b/security/integrity/digsig.c
> @@ -83,10 +83,9 @@ int __init integrity_init_keyring(const unsigned int id)
>  				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				     KEY_USR_VIEW | KEY_USR_READ |
>  				     KEY_USR_WRITE | KEY_USR_SEARCH),
> -				    KEY_ALLOC_NOT_IN_QUOTA, NULL);
> -	if (!IS_ERR(keyring[id]))
> -		set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
> -	else {
> +				    KEY_ALLOC_NOT_IN_QUOTA,
> +				    NULL, NULL);
> +	if (IS_ERR(keyring[id])) {
>  		err = PTR_ERR(keyring[id]);
>  		pr_info("Can't allocate %s keyring (%d)\n",
>  			keyring_name[id], err);
> diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
> index 676885e4320e..ef91248cb934 100644
> --- a/security/integrity/ima/ima_mok.c
> +++ b/security/integrity/ima/ima_mok.c
> @@ -35,20 +35,20 @@ __init int ima_mok_init(void)
>  			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  			      KEY_USR_VIEW | KEY_USR_READ |
>  			      KEY_USR_WRITE | KEY_USR_SEARCH,
> -			      KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +			      KEY_ALLOC_NOT_IN_QUOTA,
> +			      keyring_restrict_trusted_only, NULL);
> 
>  	ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
>  				KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ |
>  				KEY_USR_WRITE | KEY_USR_SEARCH,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA,
> +				keyring_restrict_trusted_only, NULL);
> 
>  	if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
>  		panic("Can't allocate IMA MOK or blacklist keyrings.");
> -	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags);
> 
> -	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags);
>  	set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
>  	return 0;
>  }
> diff --git a/security/keys/key.c b/security/keys/key.c
> index 48dbfa543bcb..23b271b1834d 100644
> --- a/security/keys/key.c
> +++ b/security/keys/key.c
> @@ -201,6 +201,7 @@ serial_exists:
>   * @cred: The credentials specifying UID namespace.
>   * @perm: The permissions mask of the new key.
>   * @flags: Flags specifying quota properties.
> + * @restrict_link: Optional link restriction method for new keyrings.
>   *
>   * Allocate a key of the specified type with the attributes given.  The key is
>   * returned in an uninstantiated state and the caller needs to instantiate the
> @@ -223,7 +224,11 @@ serial_exists:
>   */
>  struct key *key_alloc(struct key_type *type, const char *desc,
>  		      kuid_t uid, kgid_t gid, const struct cred *cred,
> -		      key_perm_t perm, unsigned long flags)
> +		      key_perm_t perm, unsigned long flags,
> +		      int (*restrict_link)(struct key *,
> +					   const struct key_type *,
> +					   unsigned long,
> +					   const union key_payload *))
>  {
>  	struct key_user *user = NULL;
>  	struct key *key;
> @@ -291,6 +296,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
>  	key->uid = uid;
>  	key->gid = gid;
>  	key->perm = perm;
> +	key->restrict_link = restrict_link;
> 
>  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
>  		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
> @@ -495,6 +501,12 @@ int key_instantiate_and_link(struct key *key,
>  	}
> 
>  	if (keyring) {
> +		if (keyring->restrict_link) {
> +			ret = keyring->restrict_link(keyring, key->type,
> +						     key->flags, &prep.payload);
> +			if (ret < 0)
> +				goto error;
> +		}
>  		ret = __key_link_begin(keyring, &key->index_key, &edit);
>  		if (ret < 0)
>  			goto error;
> @@ -550,8 +562,12 @@ int key_reject_and_link(struct key *key,
>  	awaken = 0;
>  	ret = -EBUSY;
> 
> -	if (keyring)
> +	if (keyring) {
> +		if (keyring->restrict_link)
> +			return -EPERM;
> +
>  		link_ret = __key_link_begin(keyring, &key->index_key, &edit);
> +	}
> 
>  	mutex_lock(&key_construction_mutex);
> 
> @@ -792,6 +808,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
>  	struct key *keyring, *key = NULL;
>  	key_ref_t key_ref;
>  	int ret;
> +	int (*restrict_link)(struct key *,
> +			     const struct key_type *,
> +			     unsigned long,
> +			     const union key_payload *) = NULL;
> 
>  	/* look up the key type to see if it's one of the registered kernel
>  	 * types */
> @@ -810,6 +830,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
> 
>  	key_check(keyring);
> 
> +	key_ref = ERR_PTR(-EPERM);
> +	if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION))
> +		restrict_link = keyring->restrict_link;
> +
>  	key_ref = ERR_PTR(-ENOTDIR);
>  	if (keyring->type != &key_type_keyring)
>  		goto error_put_type;
> @@ -834,10 +858,15 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
>  	}
>  	index_key.desc_len = strlen(index_key.description);
> 
> -	key_ref = ERR_PTR(-EPERM);
> -	if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags))
> -		goto error_free_prep;
> -	flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0;
> +	if (restrict_link) {
> +		unsigned long kflags = prep.trusted ? KEY_FLAG_TRUSTED : 0;
> +		ret = restrict_link(keyring,
> +				    index_key.type, kflags, &prep.payload);
> +		if (ret < 0) {
> +			key_ref = ERR_PTR(ret);
> +			goto error_free_prep;
> +		}
> +	}
> 
>  	ret = __key_link_begin(keyring, &index_key, &edit);
>  	if (ret < 0) {
> @@ -878,7 +907,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
> 
>  	/* allocate a new key */
>  	key = key_alloc(index_key.type, index_key.description,
> -			cred->fsuid, cred->fsgid, cred, perm, flags);
> +			cred->fsuid, cred->fsgid, cred, perm, flags, NULL);
>  	if (IS_ERR(key)) {
>  		key_ref = ERR_CAST(key);
>  		goto error_link_end;
> diff --git a/security/keys/keyring.c b/security/keys/keyring.c
> index f931ccfeefb0..ea023ca6d217 100644
> --- a/security/keys/keyring.c
> +++ b/security/keys/keyring.c
> @@ -491,13 +491,18 @@ static long keyring_read(const struct key *keyring,
>   */
>  struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
>  			  const struct cred *cred, key_perm_t perm,
> -			  unsigned long flags, struct key *dest)
> +			  unsigned long flags,
> +			  int (*restrict_link)(struct key *,
> +					       const struct key_type *,
> +					       unsigned long,
> +					       const union key_payload *),
> +			  struct key *dest)
>  {
>  	struct key *keyring;
>  	int ret;
> 
>  	keyring = key_alloc(&key_type_keyring, description,
> -			    uid, gid, cred, perm, flags);
> +			    uid, gid, cred, perm, flags, restrict_link);
>  	if (!IS_ERR(keyring)) {
>  		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
>  		if (ret < 0) {
> @@ -510,6 +515,30 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
>  }
>  EXPORT_SYMBOL(keyring_alloc);
> 
> +/**
> + * keyring_restrict_trusted_only - Restrict additions to a keyring to trusted keys only
> + * @keyring: The keyring being added to.
> + * @type: The type of key being added.
> + * @flags: The key flags.
> + * @payload: The payload of the key intended to be added.
> + *
> + * Reject the addition of any links to a keyring that point to keys that aren't
> + * marked as being trusted.  It can be overridden by passing
> + * KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when adding a key
> + * to a keyring.
> + *
> + * This is meant to be passed as the restrict_link parameter to
> + * keyring_alloc().
> + */
> +int keyring_restrict_trusted_only(struct key *keyring,
> +				  const struct key_type *type,
> +				  unsigned long flags,
> +				  const union key_payload *payload)
> +{
> +	
> +	return flags & KEY_FLAG_TRUSTED ? 0 : -EPERM;
> +}
> +
>  /*
>   * By default, we keys found by getting an exact match on their descriptions.
>   */
> @@ -1191,6 +1220,17 @@ void __key_link_end(struct key *keyring,
>  	up_write(&keyring->sem);
>  }
> 
> +/*
> + * Check addition of keys to restricted keyrings.
> + */
> +static int __key_link_check_restriction(struct key *keyring, struct key *key)
> +{
> +	if (!keyring->restrict_link)
> +		return 0;
> +	return keyring->restrict_link(keyring,
> +				      key->type, key->flags, &key->payload);
> +}
> +
>  /**
>   * key_link - Link a key to a keyring
>   * @keyring: The keyring to make the link in.
> @@ -1221,14 +1261,12 @@ int key_link(struct key *keyring, struct key *key)
>  	key_check(keyring);
>  	key_check(key);
> 
> -	if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) &&
> -	    !test_bit(KEY_FLAG_TRUSTED, &key->flags))
> -		return -EPERM;
> -
>  	ret = __key_link_begin(keyring, &key->index_key, &edit);
>  	if (ret == 0) {
>  		kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage));
> -		ret = __key_link_check_live_key(keyring, key);
> +		ret = __key_link_check_restriction(keyring, key);
> +		if (ret == 0)
> +			ret = __key_link_check_live_key(keyring, key);
>  		if (ret == 0)
>  			__key_link(key, &edit);
>  		__key_link_end(keyring, &key->index_key, edit);
> diff --git a/security/keys/persistent.c b/security/keys/persistent.c
> index c9fae5ea89fe..2ef45b319dd9 100644
> --- a/security/keys/persistent.c
> +++ b/security/keys/persistent.c
> @@ -26,7 +26,7 @@ static int key_create_persistent_register(struct user_namespace *ns)
>  					current_cred(),
>  					((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  					 KEY_USR_VIEW | KEY_USR_READ),
> -					KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +					KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(reg))
>  		return PTR_ERR(reg);
> 
> @@ -60,7 +60,7 @@ static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid,
>  				   uid, INVALID_GID, current_cred(),
>  				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				    KEY_USR_VIEW | KEY_USR_READ),
> -				   KEY_ALLOC_NOT_IN_QUOTA,
> +				   KEY_ALLOC_NOT_IN_QUOTA, NULL,
>  				   ns->persistent_keyring_register);
>  	if (IS_ERR(persistent))
>  		return ERR_CAST(persistent);
> diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
> index a3f85d2a00bb..9bb6bb5fd845 100644
> --- a/security/keys/process_keys.c
> +++ b/security/keys/process_keys.c
> @@ -76,7 +76,8 @@ int install_user_keyrings(void)
>  		if (IS_ERR(uid_keyring)) {
>  			uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
>  						    cred, user_keyring_perm,
> -						    KEY_ALLOC_IN_QUOTA, NULL);
> +						    KEY_ALLOC_IN_QUOTA,
> +						    NULL, NULL);
>  			if (IS_ERR(uid_keyring)) {
>  				ret = PTR_ERR(uid_keyring);
>  				goto error;
> @@ -92,7 +93,8 @@ int install_user_keyrings(void)
>  			session_keyring =
>  				keyring_alloc(buf, user->uid, INVALID_GID,
>  					      cred, user_keyring_perm,
> -					      KEY_ALLOC_IN_QUOTA, NULL);
> +					      KEY_ALLOC_IN_QUOTA,
> +					      NULL, NULL);
>  			if (IS_ERR(session_keyring)) {
>  				ret = PTR_ERR(session_keyring);
>  				goto error_release;
> @@ -134,7 +136,8 @@ int install_thread_keyring_to_cred(struct cred *new)
> 
>  	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
>  				KEY_POS_ALL | KEY_USR_VIEW,
> -				KEY_ALLOC_QUOTA_OVERRUN, NULL);
> +				KEY_ALLOC_QUOTA_OVERRUN,
> +				NULL, NULL);
>  	if (IS_ERR(keyring))
>  		return PTR_ERR(keyring);
> 
> @@ -180,7 +183,8 @@ int install_process_keyring_to_cred(struct cred *new)
> 
>  	keyring = keyring_alloc("_pid", new->uid, new->gid, new,
>  				KEY_POS_ALL | KEY_USR_VIEW,
> -				KEY_ALLOC_QUOTA_OVERRUN, NULL);
> +				KEY_ALLOC_QUOTA_OVERRUN,
> +				NULL, NULL);
>  	if (IS_ERR(keyring))
>  		return PTR_ERR(keyring);
> 
> @@ -231,7 +235,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
> 
>  		keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
>  					KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
> -					flags, NULL);
> +					flags, NULL, NULL);
>  		if (IS_ERR(keyring))
>  			return PTR_ERR(keyring);
>  	} else {
> @@ -785,7 +789,7 @@ long join_session_keyring(const char *name)
>  		keyring = keyring_alloc(
>  			name, old->uid, old->gid, old,
>  			KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK,
> -			KEY_ALLOC_IN_QUOTA, NULL);
> +			KEY_ALLOC_IN_QUOTA, NULL, NULL);
>  		if (IS_ERR(keyring)) {
>  			ret = PTR_ERR(keyring);
>  			goto error2;
> diff --git a/security/keys/request_key.c b/security/keys/request_key.c
> index c7a117c9a8f3..a29e3554751e 100644
> --- a/security/keys/request_key.c
> +++ b/security/keys/request_key.c
> @@ -116,7 +116,7 @@ static int call_sbin_request_key(struct key_construction *cons,
>  	cred = get_current_cred();
>  	keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
>  				KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_QUOTA_OVERRUN, NULL);
> +				KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL);
>  	put_cred(cred);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
> @@ -355,7 +355,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
> 
>  	key = key_alloc(ctx->index_key.type, ctx->index_key.description,
>  			ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
> -			perm, flags);
> +			perm, flags, NULL);
>  	if (IS_ERR(key))
>  		goto alloc_failed;
> 
> diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
> index 4f0f112fe276..9db8b4a82787 100644
> --- a/security/keys/request_key_auth.c
> +++ b/security/keys/request_key_auth.c
> @@ -202,7 +202,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
>  	authkey = key_alloc(&key_type_request_key_auth, desc,
>  			    cred->fsuid, cred->fsgid, cred,
>  			    KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
> -			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
> +			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL);
>  	if (IS_ERR(authkey)) {
>  		ret = PTR_ERR(authkey);
>  		goto error_alloc;
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file [ver #2]
  2016-01-19 11:32 ` [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file " David Howells
@ 2016-02-08 11:59   ` Mimi Zohar
  0 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 11:59 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Tue, 2016-01-19 at 11:32 +0000, David Howells wrote:
> Move the X.509 trust validation code out to its own file so that it can be
> generalised.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>

Reviewed-by:  Mimi Zohar <zohar@linux.vnet.ibm.com>

> ---
> 
>  crypto/asymmetric_keys/Makefile           |    2 
>  crypto/asymmetric_keys/public_key_trust.c |  195 +++++++++++++++++++++++++++++
>  crypto/asymmetric_keys/x509_parser.h      |    6 +
>  crypto/asymmetric_keys/x509_public_key.c  |  170 -------------------------
>  4 files changed, 202 insertions(+), 171 deletions(-)
>  create mode 100644 crypto/asymmetric_keys/public_key_trust.c
> 
> diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
> index cd1406f9b14a..3f291bbf7b74 100644
> --- a/crypto/asymmetric_keys/Makefile
> +++ b/crypto/asymmetric_keys/Makefile
> @@ -6,7 +6,7 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
> 
>  asymmetric_keys-y := asymmetric_type.o signature.o
> 
> -obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
> +obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o public_key_trust.o
>  obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
> 
>  #
> diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
> new file mode 100644
> index 000000000000..9febe612e659
> --- /dev/null
> +++ b/crypto/asymmetric_keys/public_key_trust.c
> @@ -0,0 +1,195 @@
> +/* Instantiate a public key crypto key from an X.509 Certificate
> + *
> + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
> + * Written by David Howells (dhowells@redhat.com)
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public Licence
> + * as published by the Free Software Foundation; either version
> + * 2 of the Licence, or (at your option) any later version.
> + */
> +
> +#define pr_fmt(fmt) "X.509: "fmt
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/mpi.h>
> +#include <linux/asn1_decoder.h>
> +#include <keys/asymmetric-subtype.h>
> +#include <keys/asymmetric-parser.h>
> +#include <keys/system_keyring.h>
> +#include <crypto/hash.h>
> +#include "asymmetric_keys.h"
> +#include "public_key.h"
> +#include "x509_parser.h"
> +
> +static bool use_builtin_keys;
> +static struct asymmetric_key_id *ca_keyid;
> +
> +#ifndef MODULE
> +static struct {
> +	struct asymmetric_key_id id;
> +	unsigned char data[10];
> +} cakey;
> +
> +static int __init ca_keys_setup(char *str)
> +{
> +	if (!str)		/* default system keyring */
> +		return 1;
> +
> +	if (strncmp(str, "id:", 3) == 0) {
> +		struct asymmetric_key_id *p = &cakey.id;
> +		size_t hexlen = (strlen(str) - 3) / 2;
> +		int ret;
> +
> +		if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
> +			pr_err("Missing or invalid ca_keys id\n");
> +			return 1;
> +		}
> +
> +		ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
> +		if (ret < 0)
> +			pr_err("Unparsable ca_keys id hex string\n");
> +		else
> +			ca_keyid = p;	/* owner key 'id:xxxxxx' */
> +	} else if (strcmp(str, "builtin") == 0) {
> +		use_builtin_keys = true;
> +	}
> +
> +	return 1;
> +}
> +__setup("ca_keys=", ca_keys_setup);
> +#endif
> +
> +/**
> + * x509_request_asymmetric_key - Request a key by X.509 certificate params.
> + * @keyring: The keys to search.
> + * @id: The issuer & serialNumber to look for or NULL.
> + * @skid: The subjectKeyIdentifier to look for or NULL.
> + * @partial: Use partial match if true, exact if false.
> + *
> + * Find a key in the given keyring by identifier.  The preferred identifier is
> + * the issuer + serialNumber and the fallback identifier is the
> + * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
> + * the latter must also match.
> + */
> +struct key *x509_request_asymmetric_key(struct key *keyring,
> +					const struct asymmetric_key_id *id,
> +					const struct asymmetric_key_id *skid,
> +					bool partial)
> +{
> +	struct key *key;
> +	key_ref_t ref;
> +	const char *lookup;
> +	char *req, *p;
> +	int len;
> +
> +	if (id) {
> +		lookup = id->data;
> +		len = id->len;
> +	} else {
> +		lookup = skid->data;
> +		len = skid->len;
> +	}
> +
> +	/* Construct an identifier "id:<keyid>". */
> +	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
> +	if (!req)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (partial) {
> +		*p++ = 'i';
> +		*p++ = 'd';
> +	} else {
> +		*p++ = 'e';
> +		*p++ = 'x';
> +	}
> +	*p++ = ':';
> +	p = bin2hex(p, lookup, len);
> +	*p = 0;
> +
> +	pr_debug("Look up: \"%s\"\n", req);
> +
> +	ref = keyring_search(make_key_ref(keyring, 1),
> +			     &key_type_asymmetric, req);
> +	if (IS_ERR(ref))
> +		pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
> +	kfree(req);
> +
> +	if (IS_ERR(ref)) {
> +		switch (PTR_ERR(ref)) {
> +			/* Hide some search errors */
> +		case -EACCES:
> +		case -ENOTDIR:
> +		case -EAGAIN:
> +			return ERR_PTR(-ENOKEY);
> +		default:
> +			return ERR_CAST(ref);
> +		}
> +	}
> +
> +	key = key_ref_to_ptr(ref);
> +	if (id && skid) {
> +		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
> +		if (!kids->id[1]) {
> +			pr_debug("issuer+serial match, but expected SKID missing\n");
> +			goto reject;
> +		}
> +		if (!asymmetric_key_id_same(skid, kids->id[1])) {
> +			pr_debug("issuer+serial match, but SKID does not\n");
> +			goto reject;
> +		}
> +	}
> +
> +	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
> +	return key;
> +
> +reject:
> +	key_put(key);
> +	return ERR_PTR(-EKEYREJECTED);
> +}
> +EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
> +
> +/*
> + * Check the new certificate against the ones in the trust keyring.  If one of
> + * those is the signing key and validates the new certificate, then mark the
> + * new certificate as being trusted.
> + *
> + * Return 0 if the new certificate was successfully validated, 1 if we couldn't
> + * find a matching parent certificate in the trusted list and an error if there
> + * is a matching certificate but the signature check fails.
> + */
> +int x509_validate_trust(struct x509_certificate *cert,
> +			struct key *trust_keyring)
> +{
> +	struct public_key_signature *sig = cert->sig;
> +	struct key *key;
> +	int ret = 1;
> +
> +	if (!sig->auth_ids[0] && !sig->auth_ids[1])
> +		return 1;
> +
> +	if (!trust_keyring)
> +		return -EOPNOTSUPP;
> +	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
> +		return -EPERM;
> +	if (cert->unsupported_sig)
> +		return -ENOPKG;
> +
> +	key = x509_request_asymmetric_key(trust_keyring,
> +					  sig->auth_ids[0], sig->auth_ids[1],
> +					  false);
> +	if (IS_ERR(key))
> +		return PTR_ERR(key);
> +
> +	if (!use_builtin_keys ||
> +	    test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
> +		ret = public_key_verify_signature(
> +			key->payload.data[asym_crypto], cert->sig);
> +		if (ret == -ENOPKG)
> +			cert->unsupported_sig = true;
> +	}
> +	key_put(key);
> +	return ret;
> +}
> diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
> index e373e7483812..0cf670b196c8 100644
> --- a/crypto/asymmetric_keys/x509_parser.h
> +++ b/crypto/asymmetric_keys/x509_parser.h
> @@ -59,3 +59,9 @@ extern int x509_decode_time(time64_t *_t,  size_t hdrlen,
>   */
>  extern int x509_get_sig_params(struct x509_certificate *cert);
>  extern int x509_check_for_self_signed(struct x509_certificate *cert);
> +
> +/*
> + * public_key_trust.c
> + */
> +extern int x509_validate_trust(struct x509_certificate *cert,
> +			       struct key *trust_keyring);
> diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
> index 00aef0d121b2..7397edb6cefb 100644
> --- a/crypto/asymmetric_keys/x509_public_key.c
> +++ b/crypto/asymmetric_keys/x509_public_key.c
> @@ -24,133 +24,6 @@
>  #include "public_key.h"
>  #include "x509_parser.h"
> 
> -static bool use_builtin_keys;
> -static struct asymmetric_key_id *ca_keyid;
> -
> -#ifndef MODULE
> -static struct {
> -	struct asymmetric_key_id id;
> -	unsigned char data[10];
> -} cakey;
> -
> -static int __init ca_keys_setup(char *str)
> -{
> -	if (!str)		/* default system keyring */
> -		return 1;
> -
> -	if (strncmp(str, "id:", 3) == 0) {
> -		struct asymmetric_key_id *p = &cakey.id;
> -		size_t hexlen = (strlen(str) - 3) / 2;
> -		int ret;
> -
> -		if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
> -			pr_err("Missing or invalid ca_keys id\n");
> -			return 1;
> -		}
> -
> -		ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
> -		if (ret < 0)
> -			pr_err("Unparsable ca_keys id hex string\n");
> -		else
> -			ca_keyid = p;	/* owner key 'id:xxxxxx' */
> -	} else if (strcmp(str, "builtin") == 0) {
> -		use_builtin_keys = true;
> -	}
> -
> -	return 1;
> -}
> -__setup("ca_keys=", ca_keys_setup);
> -#endif
> -
> -/**
> - * x509_request_asymmetric_key - Request a key by X.509 certificate params.
> - * @keyring: The keys to search.
> - * @id: The issuer & serialNumber to look for or NULL.
> - * @skid: The subjectKeyIdentifier to look for or NULL.
> - * @partial: Use partial match if true, exact if false.
> - *
> - * Find a key in the given keyring by identifier.  The preferred identifier is
> - * the issuer + serialNumber and the fallback identifier is the
> - * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
> - * the latter must also match.
> - */
> -struct key *x509_request_asymmetric_key(struct key *keyring,
> -					const struct asymmetric_key_id *id,
> -					const struct asymmetric_key_id *skid,
> -					bool partial)
> -{
> -	struct key *key;
> -	key_ref_t ref;
> -	const char *lookup;
> -	char *req, *p;
> -	int len;
> -
> -	if (id) {
> -		lookup = id->data;
> -		len = id->len;
> -	} else {
> -		lookup = skid->data;
> -		len = skid->len;
> -	}
> -
> -	/* Construct an identifier "id:<keyid>". */
> -	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
> -	if (!req)
> -		return ERR_PTR(-ENOMEM);
> -
> -	if (partial) {
> -		*p++ = 'i';
> -		*p++ = 'd';
> -	} else {
> -		*p++ = 'e';
> -		*p++ = 'x';
> -	}
> -	*p++ = ':';
> -	p = bin2hex(p, lookup, len);
> -	*p = 0;
> -
> -	pr_debug("Look up: \"%s\"\n", req);
> -
> -	ref = keyring_search(make_key_ref(keyring, 1),
> -			     &key_type_asymmetric, req);
> -	if (IS_ERR(ref))
> -		pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
> -	kfree(req);
> -
> -	if (IS_ERR(ref)) {
> -		switch (PTR_ERR(ref)) {
> -			/* Hide some search errors */
> -		case -EACCES:
> -		case -ENOTDIR:
> -		case -EAGAIN:
> -			return ERR_PTR(-ENOKEY);
> -		default:
> -			return ERR_CAST(ref);
> -		}
> -	}
> -
> -	key = key_ref_to_ptr(ref);
> -	if (id && skid) {
> -		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
> -		if (!kids->id[1]) {
> -			pr_debug("issuer+serial match, but expected SKID missing\n");
> -			goto reject;
> -		}
> -		if (!asymmetric_key_id_same(skid, kids->id[1])) {
> -			pr_debug("issuer+serial match, but SKID does not\n");
> -			goto reject;
> -		}
> -	}
> -
> -	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
> -	return key;
> -
> -reject:
> -	key_put(key);
> -	return ERR_PTR(-EKEYREJECTED);
> -}
> -EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
> -
>  /*
>   * Set up the signature parameters in an X.509 certificate.  This involves
>   * digesting the signed data and extracting the signature.
> @@ -294,49 +167,6 @@ not_self_signed:
>  }
> 
>  /*
> - * Check the new certificate against the ones in the trust keyring.  If one of
> - * those is the signing key and validates the new certificate, then mark the
> - * new certificate as being trusted.
> - *
> - * Return 0 if the new certificate was successfully validated, 1 if we couldn't
> - * find a matching parent certificate in the trusted list and an error if there
> - * is a matching certificate but the signature check fails.
> - */
> -static int x509_validate_trust(struct x509_certificate *cert,
> -			       struct key *trust_keyring)
> -{
> -	struct public_key_signature *sig = cert->sig;
> -	struct key *key;
> -	int ret = 1;
> -
> -	if (!sig->auth_ids[0] && !sig->auth_ids[1])
> -		return 1;
> -
> -	if (!trust_keyring)
> -		return -EOPNOTSUPP;
> -	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
> -		return -EPERM;
> -	if (cert->unsupported_sig)
> -		return -ENOPKG;
> -
> -	key = x509_request_asymmetric_key(trust_keyring,
> -					  sig->auth_ids[0], sig->auth_ids[1],
> -					  false);
> -	if (IS_ERR(key))
> -		return PTR_ERR(key);
> -
> -	if (!use_builtin_keys ||
> -	    test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
> -		ret = public_key_verify_signature(
> -			key->payload.data[asym_crypto], cert->sig);
> -		if (ret == -ENOPKG)
> -			cert->unsupported_sig = true;
> -	}
> -	key_put(key);
> -	return ret;
> -}
> -
> -/*
>   * Attempt to parse a data blob for a key as an X509 certificate.
>   */
>  static int x509_key_preparse(struct key_preparsed_payload *prep)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() [ver #2]
  2016-01-19 11:32 ` [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() " David Howells
@ 2016-02-08 11:59   ` Mimi Zohar
  0 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 11:59 UTC (permalink / raw)
  To: David Howells
  Cc: linux-security-module, keyrings, petkan, linux-kernel, Dmitry Kasatkin

On Tue, 2016-01-19 at 11:32 +0000, David Howells wrote:
> Generalise x509_request_asymmetric_key().  It doesn't really have any
> dependencies on X.509 features as it uses generalised IDs and the
> public_key structs that contain data extracted from X.509.

CC'ing Dmitry Kasatkin.

This patch also renames the digsig version of request_asymmetric_keys().

Mimi

> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
> 
>  crypto/asymmetric_keys/asymmetric_keys.h  |    2 +
>  crypto/asymmetric_keys/pkcs7_trust.c      |   22 +++++------
>  crypto/asymmetric_keys/public_key_trust.c |   60 +++++++++++++----------------
>  include/crypto/public_key.h               |    8 ++--
>  security/integrity/digsig_asymmetric.c    |    5 +-
>  5 files changed, 46 insertions(+), 51 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h
> index 1d450b580245..ca8e9ac34ce6 100644
> --- a/crypto/asymmetric_keys/asymmetric_keys.h
> +++ b/crypto/asymmetric_keys/asymmetric_keys.h
> @@ -9,6 +9,8 @@
>   * 2 of the Licence, or (at your option) any later version.
>   */
> 
> +#include <keys/asymmetric-type.h>
> +
>  extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
> 
>  extern int __asymmetric_key_hex_to_key_id(const char *id,
> diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
> index 400ef359448a..8760bc566902 100644
> --- a/crypto/asymmetric_keys/pkcs7_trust.c
> +++ b/crypto/asymmetric_keys/pkcs7_trust.c
> @@ -51,9 +51,9 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
>  		/* Look to see if this certificate is present in the trusted
>  		 * keys.
>  		 */
> -		key = x509_request_asymmetric_key(trust_keyring,
> -						  x509->id, x509->skid,
> -						  false);
> +		key = request_asymmetric_key(trust_keyring,
> +					     x509->id, x509->skid,
> +					     false);
>  		if (!IS_ERR(key)) {
>  			/* One of the X.509 certificates in the PKCS#7 message
>  			 * is apparently the same as one we already trust.
> @@ -84,10 +84,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
>  	 * trusted keys.
>  	 */
>  	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
> -		key = x509_request_asymmetric_key(trust_keyring,
> -						  last->sig->auth_ids[0],
> -						  last->sig->auth_ids[1],
> -						  false);
> +		key = request_asymmetric_key(trust_keyring,
> +					     last->sig->auth_ids[0],
> +					     last->sig->auth_ids[1],
> +					     false);
>  		if (!IS_ERR(key)) {
>  			x509 = last;
>  			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
> @@ -101,10 +101,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
>  	/* As a last resort, see if we have a trusted public key that matches
>  	 * the signed info directly.
>  	 */
> -	key = x509_request_asymmetric_key(trust_keyring,
> -					  sinfo->sig->auth_ids[0],
> -					  NULL,
> -					  false);
> +	key = request_asymmetric_key(trust_keyring,
> +				     sinfo->sig->auth_ids[0],
> +				     NULL,
> +				     false);
>  	if (!IS_ERR(key)) {
>  		pr_devel("sinfo %u: Direct signer is key %x\n",
>  			 sinfo->index, key_serial(key));
> diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
> index 9febe612e659..afb2a3eb583a 100644
> --- a/crypto/asymmetric_keys/public_key_trust.c
> +++ b/crypto/asymmetric_keys/public_key_trust.c
> @@ -1,6 +1,6 @@
> -/* Instantiate a public key crypto key from an X.509 Certificate
> +/* Validate one public key against another to determine trust chaining.
>   *
> - * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
> + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
>   * Written by David Howells (dhowells@redhat.com)
>   *
>   * This program is free software; you can redistribute it and/or
> @@ -9,17 +9,10 @@
>   * 2 of the Licence, or (at your option) any later version.
>   */
> 
> -#define pr_fmt(fmt) "X.509: "fmt
> -#include <linux/module.h>
> +#define pr_fmt(fmt) "PKEY: "fmt
>  #include <linux/kernel.h>
>  #include <linux/slab.h>
>  #include <linux/err.h>
> -#include <linux/mpi.h>
> -#include <linux/asn1_decoder.h>
> -#include <keys/asymmetric-subtype.h>
> -#include <keys/asymmetric-parser.h>
> -#include <keys/system_keyring.h>
> -#include <crypto/hash.h>
>  #include "asymmetric_keys.h"
>  #include "public_key.h"
>  #include "x509_parser.h"
> @@ -63,21 +56,20 @@ __setup("ca_keys=", ca_keys_setup);
>  #endif
> 
>  /**
> - * x509_request_asymmetric_key - Request a key by X.509 certificate params.
> + * request_asymmetric_key - Request a key by ID.
>   * @keyring: The keys to search.
> - * @id: The issuer & serialNumber to look for or NULL.
> - * @skid: The subjectKeyIdentifier to look for or NULL.
> + * @id_0: The first ID to look for or NULL.
> + * @id_1: The second ID to look for or NULL.
>   * @partial: Use partial match if true, exact if false.
>   *
>   * Find a key in the given keyring by identifier.  The preferred identifier is
> - * the issuer + serialNumber and the fallback identifier is the
> - * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
> - * the latter must also match.
> + * the id_0 and the fallback identifier is the id_1.  If both are given, the
> + * lookup is by the former, but the latter must also match.
>   */
> -struct key *x509_request_asymmetric_key(struct key *keyring,
> -					const struct asymmetric_key_id *id,
> -					const struct asymmetric_key_id *skid,
> -					bool partial)
> +struct key *request_asymmetric_key(struct key *keyring,
> +				   const struct asymmetric_key_id *id_0,
> +				   const struct asymmetric_key_id *id_1,
> +				   bool partial)
>  {
>  	struct key *key;
>  	key_ref_t ref;
> @@ -85,12 +77,12 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
>  	char *req, *p;
>  	int len;
> 
> -	if (id) {
> -		lookup = id->data;
> -		len = id->len;
> +	if (id_0) {
> +		lookup = id_0->data;
> +		len = id_0->len;
>  	} else {
> -		lookup = skid->data;
> -		len = skid->len;
> +		lookup = id_1->data;
> +		len = id_1->len;
>  	}
> 
>  	/* Construct an identifier "id:<keyid>". */
> @@ -130,14 +122,15 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
>  	}
> 
>  	key = key_ref_to_ptr(ref);
> -	if (id && skid) {
> +	if (id_0 && id_1) {
>  		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
> -		if (!kids->id[1]) {
> -			pr_debug("issuer+serial match, but expected SKID missing\n");
> +
> +		if (!kids->id[0]) {
> +			pr_debug("First ID matches, but second is missing\n");
>  			goto reject;
>  		}
> -		if (!asymmetric_key_id_same(skid, kids->id[1])) {
> -			pr_debug("issuer+serial match, but SKID does not\n");
> +		if (!asymmetric_key_id_same(id_1, kids->id[1])) {
> +			pr_debug("First ID matches, but second does not\n");
>  			goto reject;
>  		}
>  	}
> @@ -149,7 +142,7 @@ reject:
>  	key_put(key);
>  	return ERR_PTR(-EKEYREJECTED);
>  }
> -EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
> +EXPORT_SYMBOL_GPL(request_asymmetric_key);
> 
>  /*
>   * Check the new certificate against the ones in the trust keyring.  If one of
> @@ -177,9 +170,8 @@ int x509_validate_trust(struct x509_certificate *cert,
>  	if (cert->unsupported_sig)
>  		return -ENOPKG;
> 
> -	key = x509_request_asymmetric_key(trust_keyring,
> -					  sig->auth_ids[0], sig->auth_ids[1],
> -					  false);
> +	key = request_asymmetric_key(trust_keyring,
> +				     sig->auth_ids[0], sig->auth_ids[1], false);
>  	if (IS_ERR(key))
>  		return PTR_ERR(key);
> 
> diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
> index ed86bfb23e89..eaaf261d398a 100644
> --- a/include/crypto/public_key.h
> +++ b/include/crypto/public_key.h
> @@ -102,9 +102,9 @@ extern int verify_signature(const struct key *key,
>  			    const struct public_key_signature *sig);
> 
>  struct asymmetric_key_id;
> -extern struct key *x509_request_asymmetric_key(struct key *keyring,
> -					       const struct asymmetric_key_id *id,
> -					       const struct asymmetric_key_id *skid,
> -					       bool partial);
> +extern struct key *request_asymmetric_key(struct key *keyring,
> +					  const struct asymmetric_key_id *id_0,
> +					  const struct asymmetric_key_id *id_1,
> +					  bool partial);
> 
>  #endif /* _LINUX_PUBLIC_KEY_H */
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index 5ade2a7517a6..be1af41b5c2a 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -24,7 +24,8 @@
>  /*
>   * Request an asymmetric key.
>   */
> -static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
> +static struct key *ds_request_asymmetric_key(struct key *keyring,
> +					     uint32_t keyid)
>  {
>  	struct key *key;
>  	char name[12];
> @@ -97,7 +98,7 @@ int asymmetric_verify(struct key *keyring, const char *sig,
>  	if (hdr->hash_algo >= PKEY_HASH__LAST)
>  		return -ENOPKG;
> 
> -	key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
> +	key = ds_request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
>  	if (IS_ERR(key))
>  		return PTR_ERR(key);
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it [ver #2]
  2016-01-19 11:31 ` [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it " David Howells
@ 2016-02-08 12:00   ` Mimi Zohar
  2016-02-19 11:56   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 12:00 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

Hi David,

On Tue, 2016-01-19 at 11:31 +0000, David Howells wrote:
> Point to the public_key_signature struct from the pkcs7_signed_info struct
> rather than embedding it.  This makes it easier to have it take an
> arbitrary number of MPIs in future.

Just a reminder ...

Reviewing patches isn't easy no matter how well written and documented,
especially large patch sets.   For this reason, patch sets should be
limited to the patches that are required to accomplish the patch set
goal.  In this case, that goal is to change  "how certificates/keys are
determined to be trusted."

Although this patch is straight forward, the patch description should
include a reason for including this patch in this patch set.   Is having
an arbitrary number of MPIs included in this patch set?  Could this
patch be deferred?

> We also save a copy of the digest in the signature without sharing the
> memory with the crypto layer metadata.  This means we can use
> public_key_free() to get rid of the signature record.

Again, is this needed to accomplish the patch set goals?

> Signed-off-by: David Howells <dhowells@redhat.com>

Reviewed-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

> ---
> 
>  crypto/asymmetric_keys/pkcs7_parser.c |   38 ++++++++++++++----------
>  crypto/asymmetric_keys/pkcs7_parser.h |   10 ++----
>  crypto/asymmetric_keys/pkcs7_trust.c  |    4 +-
>  crypto/asymmetric_keys/pkcs7_verify.c |   53 +++++++++++++++++----------------
>  4 files changed, 56 insertions(+), 49 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
> index 7b69783cff99..8454ae5b5aa8 100644
> --- a/crypto/asymmetric_keys/pkcs7_parser.c
> +++ b/crypto/asymmetric_keys/pkcs7_parser.c
> @@ -44,9 +44,7 @@ struct pkcs7_parse_context {
>  static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
>  {
>  	if (sinfo) {
> -		mpi_free(sinfo->sig.mpi[0]);
> -		kfree(sinfo->sig.digest);
> -		kfree(sinfo->signing_cert_id);
> +		public_key_free(NULL, sinfo->sig);
>  		kfree(sinfo);
>  	}
>  }
> @@ -125,6 +123,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
>  	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
>  	if (!ctx->sinfo)
>  		goto out_no_sinfo;
> +	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
> +				  GFP_KERNEL);
> +	if (!ctx->sinfo->sig)
> +		goto out_no_sig;
> 
>  	ctx->data = (unsigned long)data;
>  	ctx->ppcerts = &ctx->certs;
> @@ -150,6 +152,7 @@ out:
>  		ctx->certs = cert->next;
>  		x509_free_certificate(cert);
>  	}
> +out_no_sig:
>  	pkcs7_free_signed_info(ctx->sinfo);
>  out_no_sinfo:
>  	pkcs7_free_message(ctx->msg);
> @@ -219,25 +222,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
> 
>  	switch (ctx->last_oid) {
>  	case OID_md4:
> -		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4;
> +		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_MD4;
>  		break;
>  	case OID_md5:
> -		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5;
> +		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_MD5;
>  		break;
>  	case OID_sha1:
> -		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1;
> +		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA1;
>  		break;
>  	case OID_sha256:
> -		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
> +		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA256;
>  		break;
>  	case OID_sha384:
> -		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384;
> +		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA384;
>  		break;
>  	case OID_sha512:
> -		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512;
> +		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA512;
>  		break;
>  	case OID_sha224:
> -		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224;
> +		ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA224;
>  	default:
>  		printk("Unsupported digest algo: %u\n", ctx->last_oid);
>  		return -ENOPKG;
> @@ -256,7 +259,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
> 
>  	switch (ctx->last_oid) {
>  	case OID_rsaEncryption:
> -		ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA;
> +		ctx->sinfo->sig->pkey_algo = PKEY_ALGO_RSA;
>  		break;
>  	default:
>  		printk("Unsupported pkey algo: %u\n", ctx->last_oid);
> @@ -617,16 +620,17 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen,
>  			     const void *value, size_t vlen)
>  {
>  	struct pkcs7_parse_context *ctx = context;
> +	struct public_key_signature *sig = ctx->sinfo->sig;
>  	MPI mpi;
> 
> -	BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
> +	BUG_ON(sig->pkey_algo != PKEY_ALGO_RSA);
> 
>  	mpi = mpi_read_raw_data(value, vlen);
>  	if (!mpi)
>  		return -ENOMEM;
> 
> -	ctx->sinfo->sig.mpi[0] = mpi;
> -	ctx->sinfo->sig.nr_mpi = 1;
> +	sig->mpi[0] = mpi;
> +	sig->nr_mpi = 1;
>  	return 0;
>  }
> 
> @@ -662,12 +666,16 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
> 
>  	pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
> 
> -	sinfo->signing_cert_id = kid;
> +	sinfo->sig->auth_ids[0] = kid;
>  	sinfo->index = ++ctx->sinfo_index;
>  	*ctx->ppsinfo = sinfo;
>  	ctx->ppsinfo = &sinfo->next;
>  	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
>  	if (!ctx->sinfo)
>  		return -ENOMEM;
> +	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
> +				  GFP_KERNEL);
> +	if (!ctx->sinfo->sig)
> +		return -ENOMEM;
>  	return 0;
>  }
> diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
> index c8159983ed8f..f4e81074f5e0 100644
> --- a/crypto/asymmetric_keys/pkcs7_parser.h
> +++ b/crypto/asymmetric_keys/pkcs7_parser.h
> @@ -40,19 +40,17 @@ struct pkcs7_signed_info {
>  #define	sinfo_has_ms_statement_type	5
>  	time64_t	signing_time;
> 
> -	/* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
> -	 * or issuing cert's SKID [CMS ver 3].
> -	 */
> -	struct asymmetric_key_id *signing_cert_id;
> -
>  	/* Message signature.
>  	 *
>  	 * This contains the generated digest of _either_ the Content Data or
>  	 * the Authenticated Attributes [RFC2315 9.3].  If the latter, one of
>  	 * the attributes contains the digest of the the Content Data within
>  	 * it.
> +	 *
> +	 * THis also contains the issuing cert serial number and issuer's name
> +	 * [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3].
>  	 */
> -	struct public_key_signature sig;
> +	struct public_key_signature *sig;
>  };
> 
>  struct pkcs7_message {
> diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
> index 7bb9389fd644..400ef359448a 100644
> --- a/crypto/asymmetric_keys/pkcs7_trust.c
> +++ b/crypto/asymmetric_keys/pkcs7_trust.c
> @@ -27,7 +27,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
>  				    struct pkcs7_signed_info *sinfo,
>  				    struct key *trust_keyring)
>  {
> -	struct public_key_signature *sig = &sinfo->sig;
> +	struct public_key_signature *sig = sinfo->sig;
>  	struct x509_certificate *x509, *last = NULL, *p;
>  	struct key *key;
>  	int ret;
> @@ -102,7 +102,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
>  	 * the signed info directly.
>  	 */
>  	key = x509_request_asymmetric_key(trust_keyring,
> -					  sinfo->signing_cert_id,
> +					  sinfo->sig->auth_ids[0],
>  					  NULL,
>  					  false);
>  	if (!IS_ERR(key)) {
> diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
> index 0d1173081b5c..3b8124c2cd91 100644
> --- a/crypto/asymmetric_keys/pkcs7_verify.c
> +++ b/crypto/asymmetric_keys/pkcs7_verify.c
> @@ -25,36 +25,38 @@
>  static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  			struct pkcs7_signed_info *sinfo)
>  {
> +	struct public_key_signature *sig = sinfo->sig;
>  	struct crypto_shash *tfm;
>  	struct shash_desc *desc;
> -	size_t digest_size, desc_size;
> -	void *digest;
> +	size_t desc_size;
>  	int ret;
> 
> -	kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
> +	kenter(",%u,%u", sinfo->index, sig->pkey_hash_algo);
> 
> -	if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
> -	    !hash_algo_name[sinfo->sig.pkey_hash_algo])
> +	if (sig->pkey_hash_algo >= PKEY_HASH__LAST ||
> +	    !hash_algo_name[sig->pkey_hash_algo])
>  		return -ENOPKG;
> 
>  	/* Allocate the hashing algorithm we're going to need and find out how
>  	 * big the hash operational data will be.
>  	 */
> -	tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo],
> +	tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig->pkey_hash_algo],
>  				 0, 0);
>  	if (IS_ERR(tfm))
>  		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
> 
>  	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
> -	sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
> +	sig->digest_size = crypto_shash_digestsize(tfm);
> 
>  	ret = -ENOMEM;
> -	digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
> -			 GFP_KERNEL);
> -	if (!digest)
> +	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
> +	if (!sig->digest)
> +		goto error_no_desc;
> +
> +	desc = kzalloc(desc_size, GFP_KERNEL);
> +	if (!desc)
>  		goto error_no_desc;
> 
> -	desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
>  	desc->tfm   = tfm;
>  	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
> 
> @@ -62,10 +64,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  	ret = crypto_shash_init(desc);
>  	if (ret < 0)
>  		goto error;
> -	ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
> +	ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len,
> +				 sig->digest);
>  	if (ret < 0)
>  		goto error;
> -	pr_devel("MsgDigest = [%*ph]\n", 8, digest);
> +	pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
> 
>  	/* However, if there are authenticated attributes, there must be a
>  	 * message digest attribute amongst them which corresponds to the
> @@ -80,14 +83,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  			goto error;
>  		}
> 
> -		if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
> +		if (sinfo->msgdigest_len != sig->digest_size) {
>  			pr_debug("Sig %u: Invalid digest size (%u)\n",
>  				 sinfo->index, sinfo->msgdigest_len);
>  			ret = -EBADMSG;
>  			goto error;
>  		}
> 
> -		if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
> +		if (memcmp(sig->digest, sinfo->msgdigest,
> +			   sinfo->msgdigest_len) != 0) {
>  			pr_debug("Sig %u: Message digest doesn't match\n",
>  				 sinfo->index);
>  			ret = -EKEYREJECTED;
> @@ -99,7 +103,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  		 * convert the attributes from a CONT.0 into a SET before we
>  		 * hash it.
>  		 */
> -		memset(digest, 0, sinfo->sig.digest_size);
> +		memset(sig->digest, 0, sig->digest_size);
> 
>  		ret = crypto_shash_init(desc);
>  		if (ret < 0)
> @@ -109,17 +113,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  		if (ret < 0)
>  			goto error;
>  		ret = crypto_shash_finup(desc, sinfo->authattrs,
> -					 sinfo->authattrs_len, digest);
> +					 sinfo->authattrs_len, sig->digest);
>  		if (ret < 0)
>  			goto error;
> -		pr_devel("AADigest = [%*ph]\n", 8, digest);
> +		pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
>  	}
> 
> -	sinfo->sig.digest = digest;
> -	digest = NULL;
> -
>  error:
> -	kfree(digest);
> +	kfree(desc);
>  error_no_desc:
>  	crypto_free_shash(tfm);
>  	kleave(" = %d", ret);
> @@ -146,12 +147,12 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
>  		 * PKCS#7 message - but I can't be 100% sure of that.  It's
>  		 * possible this will need element-by-element comparison.
>  		 */
> -		if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
> +		if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0]))
>  			continue;
>  		pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
>  			 sinfo->index, certix);
> 
> -		if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
> +		if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) {
>  			pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
>  				sinfo->index);
>  			continue;
> @@ -166,7 +167,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
>  	 */
>  	pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
>  		 sinfo->index,
> -		 sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
> +		 sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data);
>  	return 0;
>  }
> 
> @@ -325,7 +326,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
>  	}
> 
>  	/* Verify the PKCS#7 binary against the key */
> -	ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
> +	ret = public_key_verify_signature(sinfo->signer->pub, sinfo->sig);
>  	if (ret < 0)
>  		return ret;
> 
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-02-03 15:27   ` David Howells
@ 2016-02-08 13:34     ` Mimi Zohar
  2016-02-08 13:55     ` David Howells
  2016-02-08 14:55     ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] David Howells
  2 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 13:34 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Wed, 2016-02-03 at 15:27 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 
> > >  (3) The ability to configure a list of blacklisted hashes into the kernel
> > >      at build time.  This is done by setting
> > >      CONFIG_SYSTEM_BLACKLIST_HASH_LIST to the filename of a list of hashes
> > >      that are in the form:
> > > 
> > > 	"<hash>", "<hash>", ..., "<hash>"
> > > 
> > >      where each <hash> is a hex string representation of the hash and must
> > >      include all necessary leading zeros to pad the hash to the right size.
> > 
> > Is the output of "keyctl print" the hex string representation?
> 
> No, there is no payload and no read method.  "keyctl desc" will return the hex
> string representation.
> 
> >  Update keys documentation?
> 
> Not a bad idea, but it should probably go in a separate document, along with
> info about asymmetric keys.
> 
> > > The blacklist cannot currently be modified by userspace, but it will be
> > > possible to load it, for example, from the UEFI blacklist database.
> > 
> > When loading the UEFI blacklist database is enabled, it should be
> > configurable.
> 
> Probably.  That patch isn't added yet though.
> 
> > > In the future, it should also be made possible to load blacklisted
> > > asymmetric keys in here too.
> > 
> > Please update to reflect patch 3/20 "X.509: Allow X.509 certs to be
> > blacklisted" adds this support.
> 
> Changed to:
> 
> 	A later commit will make it possible to load blacklisted asymmetric
> 	keys in here too.

As you said, only the kernel can load keys on the blacklist, not
userspace, and the patch for loading the UEFI blacklist keys on the
system blacklist keyring is not included in this patch set, wouldn't it
be better to separate the concept of a general blacklist keyring from
the concept of trust?   In addition, this patch set removes the IMA
blacklist without any method for adding blacklisted IMA keys to the
system blacklist keyring.   I suggest a separate blacklist patch set
that adds support: for a system blacklist keyring, different types of
keys being black listed, allow userspace to load blacklisted keys on the
system blacklist keyring,  convert the ima_blacklist to use the general
system blacklist keyring and, optionally, include the UEFI blacklist
keys on the blacklist keyring.

This patch set would then be limited to "how certificates/keys are
determined to be trusted."  By separating out the blacklist keyring from
the issue of trust, you'll have smaller patch sets that can more easily
be reviewed. (Reviewing anything having to do with certificates is
difficult enough.)  It would also allow you to upstream the two patch
sets independently of each other.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-02-03 15:27   ` David Howells
  2016-02-08 13:34     ` Mimi Zohar
@ 2016-02-08 13:55     ` David Howells
  2016-02-08 15:03       ` Mimi Zohar
  2016-02-08 15:53       ` How to add additional blacklist entries? David Howells
  2016-02-08 14:55     ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] David Howells
  2 siblings, 2 replies; 56+ messages in thread
From: David Howells @ 2016-02-08 13:55 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> In addition, this patch set removes the IMA blacklist without any method for
> adding blacklisted IMA keys to the system blacklist keyring.

That's not true.

Patch 18 enables userspace to add keys to the system blacklist keyring,
provided those keys are validly signed:

-			      KEY_USR_SEARCH,
+			      KEY_USR_SEARCH | KEY_USR_WRITE,
 			      KEY_ALLOC_NOT_IN_QUOTA |
 			      KEY_FLAG_KEEP,
-			      NULL, NULL);
+			      restrict_link_by_system_trusted, NULL);

After this commit, you can do everything with the system blacklist keyring
that you can currently do with the IMA blacklist keyring.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-02-03 15:27   ` David Howells
  2016-02-08 13:34     ` Mimi Zohar
  2016-02-08 13:55     ` David Howells
@ 2016-02-08 14:55     ` David Howells
  2016-02-08 16:39       ` Mimi Zohar
  2016-02-19 11:48       ` David Howells
  2 siblings, 2 replies; 56+ messages in thread
From: David Howells @ 2016-02-08 14:55 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> By separating out the blacklist keyring from the issue of trust, you'll have
> smaller patch sets that can more easily be reviewed. (Reviewing anything
> having to do with certificates is difficult enough.)  It would also allow
> you to upstream the two patch sets independently of each other.

Unfortunately, there's a dependency between the subsets you're talking about
in the form of the restriction function passed to keyring_alloc() - an
argument that's only made available in the other subset, so they cannot be
completely independent.

That said, the trust changes don't require the blacklist changes.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-02-08 13:55     ` David Howells
@ 2016-02-08 15:03       ` Mimi Zohar
  2016-02-08 15:53       ` How to add additional blacklist entries? David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 15:03 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Mon, 2016-02-08 at 13:55 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 
> > In addition, this patch set removes the IMA blacklist without any method for
> > adding blacklisted IMA keys to the system blacklist keyring.
> 
> That's not true.
> 
> Patch 18 enables userspace to add keys to the system blacklist keyring,
> provided those keys are validly signed:
> 
> -			      KEY_USR_SEARCH,
> +			      KEY_USR_SEARCH | KEY_USR_WRITE,
>  			      KEY_ALLOC_NOT_IN_QUOTA |
>  			      KEY_FLAG_KEEP,
> -			      NULL, NULL);
> +			      restrict_link_by_system_trusted, NULL);
> 
> After this commit, you can do everything with the system blacklist keyring
> that you can currently do with the IMA blacklist keyring.

Right, this patch makes the system blacklist keyring writable by
userspace and removes the IMA blacklist.  What I don't understand is how
to add a key that is currently on the IMA keyring to the system
blacklist? 

With the IMA blacklist, the same certificate that was added to the IMA
keyring could be added to the blacklist. (Probably not the best idea.)

The system black list currently only supports the  TBSCertificate hash,
not the key-id.   I have the signed certificate being added to the IMA
keyring.  I'm missing the step of getting the TBSCertificate hash based
on the certificate.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* How to add additional blacklist entries?
  2016-02-08 13:55     ` David Howells
  2016-02-08 15:03       ` Mimi Zohar
@ 2016-02-08 15:53       ` David Howells
  2016-02-08 16:32         ` Mimi Zohar
  2016-02-08 16:43         ` David Howells
  1 sibling, 2 replies; 56+ messages in thread
From: David Howells @ 2016-02-08 15:53 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> Right, this patch makes the system blacklist keyring writable by
> userspace and removes the IMA blacklist.  What I don't understand is how
> to add a key that is currently on the IMA keyring to the system
> blacklist? 

You can do this from userspace with "keyctl link".  Admittedly, this attaches
the entire key to the blacklist keyring, not just the ID.  But that's
basically what you're doing at the moment, right.

To simply list the SKID of the key you want to blacklist, another patch will
be required, but the question is as to what the interface should look like.

Let's start at the beginning.  First of all, let me ask the following:

 (1) How is the key-to-be-blacklisted specified?  A copy of the X.509 cert to
     be blocked?  A signed list of SKIDs to be blocked?  A CRL?

 (2) How is the blacklist addition to be verified?

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: How to add additional blacklist entries?
  2016-02-08 15:53       ` How to add additional blacklist entries? David Howells
@ 2016-02-08 16:32         ` Mimi Zohar
  2016-02-08 16:43         ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 16:32 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Mon, 2016-02-08 at 15:53 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 
> > Right, this patch makes the system blacklist keyring writable by
> > userspace and removes the IMA blacklist.  What I don't understand is how
> > to add a key that is currently on the IMA keyring to the system
> > blacklist? 
> 
> You can do this from userspace with "keyctl link".  Admittedly, this attaches
> the entire key to the blacklist keyring, not just the ID.  But that's
> basically what you're doing at the moment, right.

Does this imply that the key already has to be loaded onto a keyring in
order to link it to the blacklist?   Currently the key doesn't need to
be on the IMA keyring in order for it to be black listed.  The cert can
be verified, that it is signed by a key on the system trusted (or
ima_mok) keyring(s), before directly being added to the IMA blacklist
keyring.

> To simply list the SKID of the key you want to blacklist, another patch will
> be required, but the question is as to what the interface should look like.
> 
> Let's start at the beginning.  First of all, let me ask the following:
> 
>  (1) How is the key-to-be-blacklisted specified?  A copy of the X.509 cert to
>      be blocked?  A signed list of SKIDs to be blocked?  A CRL?

Similar to the TBScertificate hash list, there should be support for a
SKIDs list, either in the same file or separately.

>  (2) How is the blacklist addition to be verified?

As I recall without going back and looking at the patches, you've
defined a new key type for just the TBScertficate hash without a
payload.  Is it possible to do the equivalent for SKIDs?  In both cases,
these new key type(s) would need to be signed by a key on the system
keyring (now called the builtin keyring) for it to be added to the
blacklist.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-02-08 14:55     ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] David Howells
@ 2016-02-08 16:39       ` Mimi Zohar
  2016-02-19 11:48       ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 16:39 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Mon, 2016-02-08 at 14:55 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 
> > By separating out the blacklist keyring from the issue of trust, you'll have
> > smaller patch sets that can more easily be reviewed. (Reviewing anything
> > having to do with certificates is difficult enough.)  It would also allow
> > you to upstream the two patch sets independently of each other.
> 
> Unfortunately, there's a dependency between the subsets you're talking about
> in the form of the restriction function passed to keyring_alloc() - an
> argument that's only made available in the other subset, so they cannot be
> completely independent.
> 
> That said, the trust changes don't require the blacklist changes.

Right, I should have said the blacklist changes are dependent on the
trusted keyring changes.

In the "trust" patch set, could you please include Mehmet's patch?

Thanks!

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: How to add additional blacklist entries?
  2016-02-08 15:53       ` How to add additional blacklist entries? David Howells
  2016-02-08 16:32         ` Mimi Zohar
@ 2016-02-08 16:43         ` David Howells
  2016-02-08 19:28           ` Mimi Zohar
  2016-02-09 10:42           ` David Howells
  1 sibling, 2 replies; 56+ messages in thread
From: David Howells @ 2016-02-08 16:43 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> > > Right, this patch makes the system blacklist keyring writable by
> > > userspace and removes the IMA blacklist.  What I don't understand is how
> > > to add a key that is currently on the IMA keyring to the system
> > > blacklist? 
> > 
> > You can do this from userspace with "keyctl link".  Admittedly, this
> > attaches the entire key to the blacklist keyring, not just the ID.  But
> > that's basically what you're doing at the moment, right.
> 
> Does this imply that the key already has to be loaded onto a keyring in
> order to link it to the blacklist?   Currently the key doesn't need to
> be on the IMA keyring in order for it to be black listed.  The cert can
> be verified, that it is signed by a key on the system trusted (or
> ima_mok) keyring(s), before directly being added to the IMA blacklist
> keyring.

You can link from any key you have LINK permission on.  Further, add_key() can
add directly.

> > To simply list the SKID of the key you want to blacklist, another patch
> > will be required, but the question is as to what the interface should look
> > like.
> > 
> > Let's start at the beginning.  First of all, let me ask the following:
> > 
> >  (1) How is the key-to-be-blacklisted specified?  A copy of the X.509 cert
> >      to be blocked?  A signed list of SKIDs to be blocked?  A CRL?
> 
> Similar to the TBScertificate hash list, there should be support for a
> SKIDs list, either in the same file or separately.

Separately probably makes sense - and marking the blacklist keys with
something that says what is to be checked.

> >  (2) How is the blacklist addition to be verified?
> 
> As I recall without going back and looking at the patches, you've
> defined a new key type for just the TBScertficate hash without a
> payload.

Sort of.  It carries a hash string as a description.  One of the patches
matches this with the X.509 TBScertficate hash.  I should look at adding
another patch to check the PE file content hash for kexec also.

> Is it possible to do the equivalent for SKIDs?

Yes.

> In both cases, these new key type(s) would need to be signed by a key on the
> system keyring (now called the builtin keyring) for it to be added to the
> blacklist.

I think you may have misunderstood the point of the question.  Assuming we're
loading a SKID list from userspace, how do we validate the list?  Is it
wrapped in an X.509 cert, a PKCS#7 message or is it a binary blob with an
associated signature?

Or are you proposing the SKID list be built into the kernel at compile time
and not modifiable at runtime?

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: How to add additional blacklist entries?
  2016-02-08 16:43         ` David Howells
@ 2016-02-08 19:28           ` Mimi Zohar
  2016-02-09 10:42           ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-08 19:28 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Mon, 2016-02-08 at 16:43 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 
> > > > Right, this patch makes the system blacklist keyring writable by
> > > > userspace and removes the IMA blacklist.  What I don't understand is how
> > > > to add a key that is currently on the IMA keyring to the system
> > > > blacklist? 
> > > 
> > > You can do this from userspace with "keyctl link".  Admittedly, this
> > > attaches the entire key to the blacklist keyring, not just the ID.  But
> > > that's basically what you're doing at the moment, right.
> > 
> > Does this imply that the key already has to be loaded onto a keyring in
> > order to link it to the blacklist?   Currently the key doesn't need to
> > be on the IMA keyring in order for it to be black listed.  The cert can
> > be verified, that it is signed by a key on the system trusted (or
> > ima_mok) keyring(s), before directly being added to the IMA blacklist
> > keyring.
> 
> You can link from any key you have LINK permission on.  Further, add_key() can
> add directly.

Oh, for some reason I thought the system blacklist keyring was limited
to the new key type with just a description.   I was able to add, but
also remove a key from the system blacklist.   I guess the KEY_FLAG_KEEP
is not set on the system blacklist.

> > > To simply list the SKID of the key you want to blacklist, another patch
> > > will be required, but the question is as to what the interface should look
> > > like.
> > > 
> > > Let's start at the beginning.  First of all, let me ask the following:
> > > 
> > >  (1) How is the key-to-be-blacklisted specified?  A copy of the X.509 cert
> > >      to be blocked?  A signed list of SKIDs to be blocked?  A CRL?
> > 
> > Similar to the TBScertificate hash list, there should be support for a
> > SKIDs list, either in the same file or separately.
> 
> Separately probably makes sense - and marking the blacklist keys with
> something that says what is to be checked.
> 
> > >  (2) How is the blacklist addition to be verified?
> > 
> > As I recall without going back and looking at the patches, you've
> > defined a new key type for just the TBScertficate hash without a
> > payload.
> 
> Sort of.  It carries a hash string as a description.  One of the patches
> matches this with the X.509 TBScertficate hash.  I should look at adding
> another patch to check the PE file content hash for kexec also.
> 
> > Is it possible to do the equivalent for SKIDs?
> 
> Yes.
> 
> > In both cases, these new key type(s) would need to be signed by a key on the
> > system keyring (now called the builtin keyring) for it to be added to the
> > blacklist.
> 
> I think you may have misunderstood the point of the question.  Assuming we're
> loading a SKID list from userspace, how do we validate the list?  Is it
> wrapped in an X.509 cert, a PKCS#7 message or is it a binary blob with an
> associated signature?

The keys being added to the IMA keyring are signed x509 certs (eg.
openssl ca -ss_cert).  It would be nice to be able to include the skid
in the description, without a payload, and sign that.  I have no idea if
that Is possible or if it makes sense.  I'm open to suggestions.

> Or are you proposing the SKID list be built into the kernel at compile time
> and not modifiable at runtime?

No, we definitely want to be able to blacklist keys at run time.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: How to add additional blacklist entries?
  2016-02-08 16:43         ` David Howells
  2016-02-08 19:28           ` Mimi Zohar
@ 2016-02-09 10:42           ` David Howells
  2016-02-10 14:07             ` Mimi Zohar
  1 sibling, 1 reply; 56+ messages in thread
From: David Howells @ 2016-02-09 10:42 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> > You can link from any key you have LINK permission on.  Further, add_key()
> > can add directly.
> 
> Oh, for some reason I thought the system blacklist keyring was limited
> to the new key type with just a description.   I was able to add, but
> also remove a key from the system blacklist.   I guess the KEY_FLAG_KEEP
> is not set on the system blacklist.

With patch 18 you can.  Prior to that it's not possible to modify it from
userspace at all.

> The keys being added to the IMA keyring are signed x509 certs (eg.
> openssl ca -ss_cert).  It would be nice to be able to include the skid
> in the description, without a payload, and sign that.  I have no idea if
> that Is possible or if it makes sense.  I'm open to suggestions.

I think we need a new keyctl or syscall for this.

We need to run through the X.509 parser, but we don't actually want to keep
any of the payload - and, in fact, we don't even necessarily want to create an
asymmetric-type key, though it's not a complete loss if we do that and create
one with a blacklist subtype.  The blacklist subtype would just return an
error from all operation points, but would otherwise be handled as normal.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: How to add additional blacklist entries?
  2016-02-09 10:42           ` David Howells
@ 2016-02-10 14:07             ` Mimi Zohar
  0 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-10 14:07 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

Hi David,

Sorry, for the delay in responding...

On Tue, 2016-02-09 at 10:42 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> > The keys being added to the IMA keyring are signed x509 certs (eg.
> > openssl ca -ss_cert).  It would be nice to be able to include the skid
> > in the description, without a payload, and sign that.  I have no idea if
> > that Is possible or if it makes sense.  I'm open to suggestions.

I'm back tracking here a bit.  Problem statement: we need a safe method
for revoking an x509 certificate. The RFCs describe x509 certificate
revocation lists(CRL).  Perhaps in addition to the x509 cert, require a
CRL, containing the revoked x509 certificate, to load the cert on the
blacklist?  That way having just a cert, already signed by a trusted
key, would not be enough for it to be added to the blacklist.  The CRL
itself could be verified against a key on the trusted keyring.

> I think we need a new keyctl or syscall for this.
> 
> We need to run through the X.509 parser, but we don't actually want to keep
> any of the payload - and, in fact, we don't even necessarily want to create an
> asymmetric-type key, though it's not a complete loss if we do that and create
> one with a blacklist subtype.  The blacklist subtype would just return an
> error from all operation points, but would otherwise be handled as normal.

Having back tracked,  a new version of the "key add" syscall might be
needed to include the CRL.  The kernel could extract what it needs from
the revoked certificates (and CRL) to be stored on the blacklist
keyring.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 18/20] IMA: Use the system blacklist keyring [ver #2]
  2016-01-19 11:32 ` [RFC PATCH 18/20] IMA: Use the system blacklist keyring " David Howells
@ 2016-02-10 19:12   ` Mimi Zohar
  2016-02-19 11:58   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-10 19:12 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

Hi David,

On Tue, 2016-01-19 at 11:32 +0000, David Howells wrote:

> @@ -145,10 +165,10 @@ static int __init blacklist_init(void)
>  			      current_cred(),
>  			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  			      KEY_USR_VIEW | KEY_USR_READ |
> -			      KEY_USR_SEARCH,
> +			      KEY_USR_SEARCH | KEY_USR_WRITE,
>  			      KEY_ALLOC_NOT_IN_QUOTA |
>  			      KEY_FLAG_KEEP,
> -			      NULL, NULL);
> +			      restrict_link_by_system_trusted, NULL);

As discussed, "restrict_link_by_system_trusted" is not enough.  The
certificate being added should be in a revoked list as well.  We should
defer this patch until that is possible or at least add a Kconfig option
to permit black listing x509 certificates.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
  2016-02-08 14:55     ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] David Howells
  2016-02-08 16:39       ` Mimi Zohar
@ 2016-02-19 11:48       ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: David Howells @ 2016-02-19 11:48 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> In the "trust" patch set, could you please include Mehmet's patch?

Okay, I've just looked at those (there are two) - something I should've done a
while ago - but there are a couple of issues, particularly with his first
patch.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it [ver #2]
  2016-01-19 11:31 ` [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it " David Howells
  2016-02-08 12:00   ` Mimi Zohar
@ 2016-02-19 11:56   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: David Howells @ 2016-02-19 11:56 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> > Point to the public_key_signature struct from the pkcs7_signed_info struct
> > rather than embedding it.  This makes it easier to have it take an
> > arbitrary number of MPIs in future.
> 
> Just a reminder ...
> 
> Reviewing patches isn't easy no matter how well written and documented,
> especially large patch sets.   For this reason, patch sets should be
> limited to the patches that are required to accomplish the patch set
> goal.  In this case, that goal is to change  "how certificates/keys are
> determined to be trusted."
> 
> Although this patch is straight forward, the patch description should
> include a reason for including this patch in this patch set.   Is having
> an arbitrary number of MPIs included in this patch set?  Could this
> patch be deferred?

Actually, this may be changed with the advent of Tadeusz's patches.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 18/20] IMA: Use the system blacklist keyring [ver #2]
  2016-01-19 11:32 ` [RFC PATCH 18/20] IMA: Use the system blacklist keyring " David Howells
  2016-02-10 19:12   ` Mimi Zohar
@ 2016-02-19 11:58   ` David Howells
  2016-02-19 12:16     ` Mimi Zohar
  1 sibling, 1 reply; 56+ messages in thread
From: David Howells @ 2016-02-19 11:58 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> As discussed, "restrict_link_by_system_trusted" is not enough.  The
> certificate being added should be in a revoked list as well.

What do you mean be a "revoked list"?  There currently isn't such a beast in
IMA.  The patches I've proposed should make the functionality available
approximately the same as exists now.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 18/20] IMA: Use the system blacklist keyring [ver #2]
  2016-02-19 11:58   ` David Howells
@ 2016-02-19 12:16     ` Mimi Zohar
  0 siblings, 0 replies; 56+ messages in thread
From: Mimi Zohar @ 2016-02-19 12:16 UTC (permalink / raw)
  To: David Howells; +Cc: linux-security-module, keyrings, petkan, linux-kernel

On Fri, 2016-02-19 at 11:58 +0000, David Howells wrote:
> Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> 
> > As discussed, "restrict_link_by_system_trusted" is not enough.  The
> > certificate being added should be in a revoked list as well.
> 
> What do you mean be a "revoked list"?  There currently isn't such a beast in
> IMA.  The patches I've proposed should make the functionality available
> approximately the same as exists now.

Support for the IMA mok and blacklist keyrings are disabled by default.
Please don't make this the default, at least until we add the equivalent
of revoked certificates.  Refer to the "Re: How to add additional
blacklist entries?"  thread.

Mimi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a keyring [ver #2]
  2016-01-19 11:31 ` [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a " David Howells
  2016-02-08 11:59   ` Mimi Zohar
@ 2016-02-29 15:49   ` David Howells
  1 sibling, 0 replies; 56+ messages in thread
From: David Howells @ 2016-02-29 15:49 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, linux-security-module, keyrings, petkan, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:

> > +    If restrict_link not NULL, it should point to a function will be called to
> > +    vet all attempts to link keys into the keyring, though this can be
> > +    overridden by passing KEY_ALLOC_BYPASS_RESTRICTION to
> > +    key_create_or_update().
> 
> Please fix the first part of the sentence.   Maybe add an example of
> when it is appropriate to bypass the restriction - (eg. loading the
> builtin keys).

Okay:

    If restrict_link not NULL, it should point to a function that will be
    called each time an attempt is made to link a key into the new keyring.
    This function is called to check whether a key may be added into the keying
    or not.  Callers of key_create_or_update() within the kernel can pass
    KEY_ALLOC_BYPASS_RESTRICTION to suppress the check.  An example of using
    this is to manage rings of cryptographic keys that are set up when the
    kernel boots where userspace is also permitted to add keys - provided they
    can be verified by a key the kernel already has.

    When called, the restriction function will be passed the keyring being
    added to, the key flags value and the type and payload of the key being
    added.  Note that when a new key is being created, this is called between
    payload preparsing and actual key creation.  The function should return 0
    to allow the link or an error to reject it.

David

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2016-02-29 15:49 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
2016-01-19 11:30 ` [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key " David Howells
2016-01-20 18:58   ` Mimi Zohar
2016-02-03 15:30   ` David Howells
2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
2016-01-20 19:31   ` Mimi Zohar
2016-01-20 20:26   ` Mimi Zohar
2016-02-03 15:27   ` David Howells
2016-02-08 13:34     ` Mimi Zohar
2016-02-08 13:55     ` David Howells
2016-02-08 15:03       ` Mimi Zohar
2016-02-08 15:53       ` How to add additional blacklist entries? David Howells
2016-02-08 16:32         ` Mimi Zohar
2016-02-08 16:43         ` David Howells
2016-02-08 19:28           ` Mimi Zohar
2016-02-09 10:42           ` David Howells
2016-02-10 14:07             ` Mimi Zohar
2016-02-08 14:55     ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] David Howells
2016-02-08 16:39       ` Mimi Zohar
2016-02-19 11:48       ` David Howells
2016-02-03 15:29   ` David Howells
2016-01-19 11:30 ` [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted " David Howells
2016-01-20 20:33   ` Mimi Zohar
2016-02-03 15:46   ` David Howells
2016-02-05 16:16     ` Mimi Zohar
2016-01-19 11:30 ` [RFC PATCH 04/20] X.509: Don't treat self-signed keys specially " David Howells
2016-01-20 20:40   ` Mimi Zohar
2016-01-19 11:31 ` [RFC PATCH 05/20] KEYS: Generalise system_verify_data() to provide access to internal content " David Howells
2016-01-19 11:31 ` [RFC PATCH 06/20] PKCS#7: Make trust determination dependent on contents of trust keyring " David Howells
2016-01-19 11:31 ` [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a " David Howells
2016-02-08 11:59   ` Mimi Zohar
2016-02-29 15:49   ` David Howells
2016-01-19 11:31 ` [RFC PATCH 08/20] KEYS: Allow authentication data to be stored in an asymmetric key " David Howells
2016-01-19 11:31 ` [RFC PATCH 09/20] KEYS: Add identifier pointers to public_key_signature struct " David Howells
2016-01-19 11:31 ` [RFC PATCH 10/20] X.509: Retain the key verification data " David Howells
2016-01-19 11:31 ` [RFC PATCH 11/20] X.509: Extract signature digest and make self-signed cert checks earlier " David Howells
2016-01-19 11:31 ` [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it " David Howells
2016-02-08 12:00   ` Mimi Zohar
2016-02-19 11:56   ` David Howells
2016-01-19 11:32 ` [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file " David Howells
2016-02-08 11:59   ` Mimi Zohar
2016-01-19 11:32 ` [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() " David Howells
2016-02-08 11:59   ` Mimi Zohar
2016-01-19 11:32 ` [RFC PATCH 15/20] KEYS: Move the point of trust determination to __key_link() " David Howells
2016-01-19 11:32 ` [RFC PATCH 16/20] KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED " David Howells
2016-01-19 11:32 ` [RFC PATCH 17/20] PKCS#7: Handle blacklisted certificates " David Howells
2016-01-19 11:32 ` [RFC PATCH 18/20] IMA: Use the system blacklist keyring " David Howells
2016-02-10 19:12   ` Mimi Zohar
2016-02-19 11:58   ` David Howells
2016-02-19 12:16     ` Mimi Zohar
2016-01-19 11:32 ` [RFC PATCH 19/20] certs: Add a secondary system keyring that can be added to dynamically " David Howells
2016-01-19 11:32 ` [RFC PATCH 20/20] IMA: Replace the .ima_mok keyring with the secondary system keyring " David Howells
2016-01-20 17:24 ` [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings " Petko Manolov
2016-01-20 18:57 ` Mimi Zohar
2016-02-03 15:47 ` David Howells
2016-02-03 15:56 ` David Howells

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.