2016-03-04 15:00:27

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 00/12] KEYS: Restrict additions to 'trusted' keyrings [ver #2]


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 trustworthiness 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.

(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.

A second manager function is provided that just rejects with EPERM.

(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 in future for userspace to create a private
set of trusted keys and then to have it sealed 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 a separate UEFI keyring.

(*) 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.

(*) Config option SYSTEM_TRUSTED_KEYS now depends on ASYMMETRIC_KEY_TYPE as
that's the only type currently permitted on the system keyrings.

(*) A new config option, IMA_PERMIT_ADD_TO_IMA_KEYRINGS, is provided to allow
keys to be added to IMA keyrings - subject to the restriction that such
keys are validly signed by a key already in the system keyrings.

If IMA_PERMIT_ADD_TO_IMA_KEYRINGS is enabled, but secondary keyrings
aren't, additions to the IMA keyrings will be restricted to signatures
verifiable by keys in the builtin system keyring only.

The patches can be found here also:

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

This patchset is based on top of

[RFC PATCH 0/7] KEYS: Adjust public key signature handling

which is on branch keys-sig in the GIT repo mentioned above.

David
---
David Howells (12):
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: Move x509_request_asymmetric_key() to asymmetric_type.c
KEYS: Generalise x509_request_asymmetric_key()
X.509: Use verify_signature() if we have a struct key * to use
X.509: Move the trust validation code out to its own file
KEYS: Make the system trusted keyring depend on the asymmetric key type
KEYS: Move the point of trust determination to __key_link()
KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED
certs: Add a secondary system keyring that can be added to dynamically
IMA: Use the the system trusted keyrings instead of .ima_mok


Documentation/security/keys.txt | 22 +++
arch/x86/kernel/kexec-bzimage64.c | 18 +--
certs/Kconfig | 9 +
certs/system_keyring.c | 137 +++++++++++++++++-----
crypto/asymmetric_keys/Kconfig | 4 -
crypto/asymmetric_keys/Makefile | 5 +
crypto/asymmetric_keys/asymmetric_keys.h | 2
crypto/asymmetric_keys/asymmetric_type.c | 89 ++++++++++++++
crypto/asymmetric_keys/mscode_parser.c | 21 +--
crypto/asymmetric_keys/pkcs7_key_type.c | 72 ++++-------
crypto/asymmetric_keys/pkcs7_parser.c | 21 ++-
crypto/asymmetric_keys/pkcs7_parser.h | 1
crypto/asymmetric_keys/pkcs7_trust.c | 35 ++---
crypto/asymmetric_keys/restrict.c | 108 +++++++++++++++++
crypto/asymmetric_keys/verify_pefile.c | 40 +-----
crypto/asymmetric_keys/verify_pefile.h | 5 -
crypto/asymmetric_keys/x509_parser.h | 1
crypto/asymmetric_keys/x509_public_key.c | 191 ------------------------------
fs/cifs/cifsacl.c | 2
fs/nfs/nfs4idmap.c | 2
include/crypto/pkcs7.h | 6 -
include/crypto/public_key.h | 27 +---
include/keys/asymmetric-type.h | 6 +
include/keys/system_keyring.h | 36 ++----
include/linux/key-type.h | 1
include/linux/key.h | 44 +++++--
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 | 16 ++-
security/integrity/ima/Kconfig | 36 ++++--
security/integrity/ima/ima_mok.c | 18 +--
security/keys/key.c | 42 +++++--
security/keys/keyring.c | 46 ++++++-
security/keys/persistent.c | 4 -
security/keys/process_keys.c | 16 ++-
security/keys/request_key.c | 4 -
security/keys/request_key_auth.c | 2
40 files changed, 664 insertions(+), 509 deletions(-)
create mode 100644 crypto/asymmetric_keys/restrict.c
create mode 100644 include/linux/verification.h
delete mode 100644 include/linux/verify_pefile.h


2016-03-04 15:00:41

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 02/12] PKCS#7: Make trust determination dependent on contents of trust keyring [ver #2]

Make the determination of the trustworthiness of a key dependent on whether
a key that can verify it is present in the supplied 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 <[email protected]>
---

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 ab9bf5363ecd..3b92523882e5 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -62,7 +62,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)

return verify_pkcs7_signature(NULL, 0,
prep->data, prep->datalen,
- NULL, -ENOKEY, usage,
+ NULL, usage,
pkcs7_view_content, prep);
}

diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index d5eec31e95b6..f4e81074f5e0 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 554200284ea8..36e77cb07bd0 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 265351075b0e..672a94c2c3ff 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 f24f4d808e7f..05eef1c68881 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -39,7 +39,6 @@ struct x509_certificate {
unsigned index;
bool seen; /* Infinite recursion prevention */
bool verified;
- bool trusted;
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 */
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 593aace88a02..6a64e03b9f44 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -81,6 +81,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);
}

2016-03-04 15:00:47

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 01/12] KEYS: Generalise system_verify_data() to provide access to internal content [ver #2]

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 <[email protected]>
---

arch/x86/kernel/kexec-bzimage64.c | 18 ++------
certs/system_keyring.c | 45 +++++++++++++++----
crypto/asymmetric_keys/Kconfig | 4 +-
crypto/asymmetric_keys/mscode_parser.c | 21 +++------
crypto/asymmetric_keys/pkcs7_key_type.c | 72 ++++++++++++-------------------
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, 155 insertions(+), 173 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 91a7e047a765..f7d2ef9789d8 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -40,8 +40,7 @@ config PKCS7_MESSAGE_PARSER

config PKCS7_TEST_KEY
tristate "PKCS#7 testing key type"
- depends on PKCS7_MESSAGE_PARSER
- select SYSTEM_TRUSTED_KEYRING
+ depends on SYSTEM_DATA_VERIFICATION
help
This option provides a type of key that can be loaded up from a
PKCS#7 message - provided the message is signed by a trusted key. If
@@ -54,6 +53,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 3242cbfaeaa2..6a76d5c70ef6 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..ab9bf5363ecd 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -13,12 +13,9 @@
#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");
MODULE_DESCRIPTION("PKCS#7 testing key type");
@@ -29,60 +26,47 @@ MODULE_PARM_DESC(pkcs7_usage,
"Usage to specify when verifying the PKCS#7 message");

/*
- * Preparse a PKCS#7 wrapped and validated data blob.
+ * Retrieve the PKCS#7 message content.
*/
-static int pkcs7_preparse(struct key_preparsed_payload *prep)
+static int pkcs7_view_content(void *ctx, const void *data, size_t len,
+ size_t asn1hdrlen)
{
- 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;
+ struct key_preparsed_payload *prep = ctx;
+ const void *saved_prep_data;
+ size_t saved_prep_datalen;
int ret;

- kenter("");
-
- if (usage >= NR__KEY_BEING_USED_FOR) {
- pr_err("Invalid usage type %d\n", usage);
- 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;
+ prep->datalen = len;
+
ret = user_preparse(prep);
+
prep->data = saved_prep_data;
prep->datalen = saved_prep_datalen;
-
-error_free:
- pkcs7_free_message(pkcs7);
-error:
- 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;
+
+ if (usage >= NR__KEY_BEING_USED_FOR) {
+ pr_err("Invalid usage type %d\n", usage);
+ return -EINVAL;
+ }
+
+ return verify_pkcs7_signature(NULL, 0,
+ prep->data, prep->datalen,
+ NULL, -ENOKEY, usage,
+ pkcs7_view_content, prep);
+}
+
+/*
* user defined keys take an arbitrary string as the description and an
* arbitrary blob of data as the payload
*/
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 835701613125..af4cd8649117 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -168,24 +168,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 7e8c2338ae25..265351075b0e 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 a133eb81a492..cd4d20930728 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 2f5de5c1a3a0..b3928e801b8c 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -15,20 +15,6 @@
#define _LINUX_PUBLIC_KEY_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];
-
-/*
* 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 70a8775bb444..d1e23dda4363 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 39fd38cfa8c9..b2d645ac35a0 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_IMA_MOK_KEYRING
extern struct key *ima_mok_keyring;
extern struct key *ima_blacklist_keyring;
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 ([email protected])
+ *
+ * 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 ([email protected])
- *
- * 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 64b9dead4a07..593aace88a02 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -80,6 +80,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);
}

2016-03-04 15:01:03

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 03/12] KEYS: Add a facility to restrict new links into a keyring [ver #2]

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 <[email protected]>
Reviewed-by: Mimi Zohar <[email protected]>
---

Documentation/security/keys.txt | 22 +++++++++++
certs/system_keyring.c | 8 ++--
fs/cifs/cifsacl.c | 2 +
fs/nfs/nfs4idmap.c | 2 +
include/linux/key.h | 53 ++++++++++++++++++++++------
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 | 73 ++++++++++++++++++++++++++++++++++----
security/keys/persistent.c | 4 +-
security/keys/process_keys.c | 16 +++++---
security/keys/request_key.c | 4 +-
security/keys/request_key_auth.c | 2 +
15 files changed, 198 insertions(+), 52 deletions(-)

diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 8c183873b2b7..a6a50b359025 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,24 @@ 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 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.
+
+ A convenience function, restrict_link_reject, exists to always return
+ -EPERM to in this case.
+

(*) To check the validity of a key, this function can be called:

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..83b603639d2e 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,22 @@ 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 restrict_link_reject(struct key *keyring,
+ const struct key_type *type,
+ unsigned long flags,
+ 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 b28755131687..deb881754e03 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;
@@ -496,6 +502,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;
@@ -551,8 +563,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);

@@ -793,6 +809,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 */
@@ -811,6 +831,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;
@@ -835,10 +859,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) {
@@ -879,7 +908,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..d2d1f3378008 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,51 @@ 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;
+}
+
+/**
+ * restrict_link_reject - Give -EPERM to restrict link
+ * @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. 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 restrict_link_reject(struct key *keyring,
+ const struct key_type *type,
+ unsigned long flags,
+ const union key_payload *payload)
+{
+ return -EPERM;
+}
+
/*
* By default, we keys found by getting an exact match on their descriptions.
*/
@@ -1191,6 +1241,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 +1282,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 e6d50172872f..40a885239782 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;

2016-03-04 15:01:30

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 08/12] KEYS: Make the system trusted keyring depend on the asymmetric key type [ver #2]

Make the system trusted keyring depend on the asymmetric key type as
there's not a lot of point having it if you can't then load asymmetric keys
onto it.

Signed-off-by: David Howells <[email protected]>
---

certs/Kconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/certs/Kconfig b/certs/Kconfig
index f0f8a4433685..743d480f5f6f 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -17,6 +17,7 @@ config MODULE_SIG_KEY
config SYSTEM_TRUSTED_KEYRING
bool "Provide system-wide ring of trusted keys"
depends on KEYS
+ depends on ASYMMETRIC_KEY_TYPE
help
Provide a system keyring to which trusted keys can be added. Keys in
the keyring are considered to be trusted. Keys may be added at will

2016-03-04 15:01:39

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 09/12] KEYS: Move the point of trust determination to __key_link() [ver #2]

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.


If system keyrings are disabled then restrict_link_by_system_trusted()
resolves to restrict_link_reject(). The integrity digital signature code
still works correctly with this as it was previously using
KEY_FLAG_TRUSTED_ONLY, which doesn't permit anything to be added if there
is no system keyring against which trust can be determined.

Signed-off-by: David Howells <[email protected]>
---

certs/system_keyring.c | 20 ++++++++--
crypto/asymmetric_keys/restrict.c | 62 +++++++++++++++---------------
crypto/asymmetric_keys/x509_parser.h | 6 ---
crypto/asymmetric_keys/x509_public_key.c | 21 ----------
include/crypto/public_key.h | 7 +++
include/keys/system_keyring.h | 19 +++------
kernel/module_signing.c | 2 -
security/integrity/digsig.c | 33 +++++++++++++++-
security/integrity/ima/ima_mok.c | 6 +--
9 files changed, 100 insertions(+), 76 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 417d65882870..dfebab0c1c5a 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -18,12 +18,26 @@
#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 restrict_link_by_signature(system_trusted_keyring,
+ type, payload);
+}
+
/*
* Load the compiled-in keys
*/
@@ -37,7 +51,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/restrict.c b/crypto/asymmetric_keys/restrict.c
index b4c10f2f5034..ac4bddf669de 100644
--- a/crypto/asymmetric_keys/restrict.c
+++ b/crypto/asymmetric_keys/restrict.c
@@ -1,6 +1,6 @@
/* Instantiate a public key crypto key from an X.509 Certificate
*
- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
* Written by David Howells ([email protected])
*
* This program is free software; you can redistribute it and/or
@@ -9,20 +9,12 @@
* 2 of the Licence, or (at your option) any later version.
*/

-#define pr_fmt(fmt) "X.509: "fmt
+#define pr_fmt(fmt) "ASYM: "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 <crypto/public_key.h>
#include "asymmetric_keys.h"
-#include "x509_parser.h"

static bool use_builtin_keys;
static struct asymmetric_key_id *ca_keyid;
@@ -62,45 +54,55 @@ static int __init ca_keys_setup(char *str)
__setup("ca_keys=", ca_keys_setup);
#endif

-/*
+/**
+ * restrict_link_by_signature - 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 restrict_link_by_signature(struct key *trust_keyring,
+ const struct key_type *type,
+ const union key_payload *payload)
{
- struct public_key_signature *sig = cert->sig;
+ const struct public_key_signature *sig;
struct key *key;
- int ret = 1;
+ int ret;

- 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;

+ /* See if we have a key that signed this one. */
key = find_asymmetric_key(trust_keyring,
sig->auth_ids[0], sig->auth_ids[1],
false);
if (IS_ERR(key))
- return PTR_ERR(key);
+ return -ENOKEY;

- if (!use_builtin_keys ||
- test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
- ret = verify_signature(key, cert->sig);
- if (ret == -ENOPKG)
- cert->unsupported_sig = true;
- }
+ if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags))
+ ret = -ENOKEY;
+ else
+ ret = verify_signature(key, sig);
key_put(key);
return ret;
}
-EXPORT_SYMBOL_GPL(x509_validate_trust);
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 7a802b09a509..05eef1c68881 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -58,9 +58,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 6d7f42f0de9a..fb732296cd36 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -178,31 +178,12 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)

cert->pub->id_type = "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_signature_free(cert->sig);
cert->sig = NULL;
} else {
pr_devel("Cert Signature: %s + %s\n",
cert->sig->pkey_algo, cert->sig->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;
}

/* Propose a description */
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 96ef27b8dd41..882ca0e1e7a5 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -47,6 +47,13 @@ extern void public_key_signature_free(struct public_key_signature *sig);
extern struct asymmetric_key_subtype public_key_subtype;

struct key;
+struct key_type;
+union key_payload;
+
+extern int restrict_link_by_signature(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 b2d645ac35a0..71c90b463af9 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -12,22 +12,17 @@
#ifndef _KEYS_SYSTEM_KEYRING_H
#define _KEYS_SYSTEM_KEYRING_H

+#include <linux/key.h>
+
#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING

-#include <linux/key.h>
-#include <linux/verification.h>
-#include <crypto/public_key.h>
+extern int restrict_link_by_system_trusted(struct key *keyring,
+ const struct key_type *type,
+ unsigned long flags,
+ const union key_payload *payload);

-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;
-}
+#define restrict_link_by_system_trusted restrict_link_reject
#endif

#ifdef CONFIG_IMA_MOK_KEYRING
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 6a64e03b9f44..937c844bee4a 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.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..a12f9d097572 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,35 @@ static bool init_keyring __initdata = true;
static bool init_keyring __initdata;
#endif

+#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
+/*
+ * 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 restrict_link_by_signature(get_ima_mok_keyring(),
+ type, payload);
+}
+#else
+/*
+ * If there's no system trusted keyring, then keys cannot be loaded into
+ * .ima_mok and added keys cannot be marked trusted.
+ */
+#define restrict_link_by_ima_mok restrict_link_reject
+#endif
+
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen)
{
@@ -84,7 +115,7 @@ int __init integrity_init_keyring(const unsigned int id)
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA,
- NULL, NULL);
+ restrict_link_by_ima_mok, 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.");

2016-03-04 15:01:45

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 10/12] KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED [ver #2]

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 <[email protected]>
---

certs/system_keyring.c | 2 --
include/keys/system_keyring.h | 1 -
include/linux/key-type.h | 1 -
include/linux/key.h | 21 +++++----------------
security/integrity/digsig.c | 3 +--
security/keys/key.c | 11 ++---------
security/keys/keyring.c | 29 +----------------------------
7 files changed, 9 insertions(+), 59 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index dfebab0c1c5a..3cfc88c76aee 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 restrict_link_by_signature(system_trusted_keyring,
@@ -97,7 +96,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 71c90b463af9..71f3e2523767 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);

#else
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 83b603639d2e..722914798f37 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,18 +305,11 @@ 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 restrict_link_reject(struct key *keyring,
const struct key_type *type,
- unsigned long flags,
const union key_payload *payload);

extern int keyring_clear(struct key *keyring);
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index a12f9d097572..ac2d39232567 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -51,12 +51,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;

diff --git a/security/keys/key.c b/security/keys/key.c
index deb881754e03..bd5a272f28a6 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;

@@ -504,7 +501,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;
}
@@ -811,7 +808,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
@@ -843,7 +839,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);
@@ -860,9 +855,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 d2d1f3378008..c91e4e0cea08 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)
{
@@ -516,33 +515,9 @@ 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;
-}
-
-/**
* restrict_link_reject - Give -EPERM to restrict link
* @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. It can be overridden by
@@ -554,7 +529,6 @@ int keyring_restrict_trusted_only(struct key *keyring,
*/
int restrict_link_reject(struct key *keyring,
const struct key_type *type,
- unsigned long flags,
const union key_payload *payload)
{
return -EPERM;
@@ -1248,8 +1222,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);
}

/**

2016-03-04 15:01:57

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

Provide a config option (IMA_PERMIT_ADD_TO_IMA_KEYRINGS) that, when
enabled, allows keys to be added to the IMA keyrings by userspace - with
the restriction that each must be signed by a key in the system trusted
keyrings.

EPERM will be returned if this option is disabled, ENOKEY will be returned if
no authoritative key can be found and EKEYREJECTED will be returned if the
signature doesn't match. Other errors such as ENOPKG may also be returned.

If this new option is enabled, the builtin system keyring is searched, as is
the secondary system keyring if that is also enabled. Intermediate keys
between the builtin system keyring and the key being added can be added to
the secondary keyring (which replaces .ima_mok) to form a trust chain -
provided they are also validly signed by a key in one of the trusted keyrings.

The .ima_mok keyring is removed.

Signed-off-by: David Howells <[email protected]>
---

include/keys/system_keyring.h | 9 ---------
security/integrity/digsig.c | 31 +++++--------------------------
security/integrity/ima/Kconfig | 36 ++++++++++++++++++++++++------------
security/integrity/ima/ima_mok.c | 12 ++----------
4 files changed, 31 insertions(+), 57 deletions(-)

diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index c6c05f1513f5..0764a8c1c131 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -29,22 +29,13 @@ extern int restrict_link_by_builtin_trusted(struct key *keyring,
#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;
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index ac2d39232567..aef3ac7be868 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -42,32 +42,10 @@ static bool init_keyring __initdata = true;
static bool init_keyring __initdata;
#endif

-#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
-/*
- * 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 restrict_link_by_signature(get_ima_mok_keyring(),
- type, payload);
-}
+#ifdef CONFIG_IMA_PERMIT_ADD_TO_IMA_KEYRINGS
+#define restrict_link_to_ima restrict_link_by_system_trusted
#else
-/*
- * If there's no system trusted keyring, then keys cannot be loaded into
- * .ima_mok and added keys cannot be marked trusted.
- */
-#define restrict_link_by_ima_mok restrict_link_reject
+#define restrict_link_to_ima restrict_link_reject
#endif

int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
@@ -114,7 +92,8 @@ int __init integrity_init_keyring(const unsigned int id)
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA,
- restrict_link_by_ima_mok, NULL);
+ restrict_link_to_ima,
+ 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..890e8aa8ccb4 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -155,23 +155,35 @@ config IMA_TRUSTED_KEYRING

This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING

+config IMA_PERMIT_ADD_TO_IMA_KEYRINGS
+ bool "Allow keys to be added to the ima keyrings, with restrictions"
+ depends on IMA_APPRAISE
+ depends on SYSTEM_TRUSTED_KEYRING
+ select INTEGRITY_TRUSTED_KEYRING
+ default n
+ help
+ This option permits keys to be added to the ima keyrings using
+ add_key() or KEYCTL_LINK - with the restriction that the key must be
+ validly signed by a key in one of the system trusted keyrings.
+
+ Intermediate keys between those the kernel has compiled in and the
+ keys to be added may be added to the system secondary keyring if that
+ is enabled - provided those are validly signed by a key in the system
+ trusted keyrings.
+
+ If this is not set, attempts to add to the ima keyrings will be
+ rejected with EPERM.
+
config IMA_MOK_KEYRING
- bool "Create IMA machine owner keys (MOK) and blacklist keyrings"
+ bool "Create IMA machine owner 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.
+ This option creates IMA blacklist keyring. This 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"
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index be0da013622c..031d65a91297 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -28,15 +28,7 @@ struct key *ima_blacklist_keyring;
*/
__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);
+ pr_notice("Allocating IMA blacklist keyrings.\n");

ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
@@ -46,7 +38,7 @@ __init int ima_mok_init(void)
KEY_ALLOC_NOT_IN_QUOTA,
restrict_link_by_system_trusted, NULL);

- if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
+ if (IS_ERR(ima_blacklist_keyring))
panic("Can't allocate IMA MOK or blacklist keyrings.");

set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);

2016-03-04 15:01:54

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

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 <[email protected]>
---

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

diff --git a/certs/Kconfig b/certs/Kconfig
index 743d480f5f6f..fc5955f5fc8a 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -56,4 +56,12 @@ config SYSTEM_EXTRA_CERTIFICATE_SIZE
This is the number of bytes reserved in the kernel image for a
certificate to be inserted.

+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 3cfc88c76aee..9700f37350ff 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,26 +36,68 @@ int restrict_link_by_system_trusted(struct key *keyring,
const struct key_type *type,
const union key_payload *payload)
{
- return restrict_link_by_signature(system_trusted_keyring,
- type, payload);
+ /* 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)
+ /* Allow the builtin keyring to be added to the secondary */
+ return 0;
+
+ return restrict_link_by_signature(secondary_trusted_keys, type, payload);
+#else
+ return restrict_link_by_signature(builtin_trusted_keys, type, payload);
+#endif
+}
+
+/**
+ * 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 restrict_link_by_signature(builtin_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");
+
+ if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0)
+ panic("Can't link trusted keyrings\n");
+#endif
+
return 0;
}

@@ -88,7 +133,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,
@@ -125,7 +170,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.
@@ -157,8 +203,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 71f3e2523767..c6c05f1513f5 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -19,9 +19,13 @@
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);

#else
#define restrict_link_by_system_trusted restrict_link_reject
+#define restrict_link_by_builtin_trusted restrict_link_reject
#endif

#ifdef CONFIG_IMA_MOK_KEYRING

2016-03-04 15:04:56

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 07/12] X.509: Move the trust validation code out to its own file [ver #2]

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

Signed-off-by: David Howells <[email protected]>
---

crypto/asymmetric_keys/Makefile | 5 +
crypto/asymmetric_keys/restrict.c | 106 ++++++++++++++++++++++++++++++
crypto/asymmetric_keys/x509_parser.h | 6 ++
crypto/asymmetric_keys/x509_public_key.c | 79 ----------------------
4 files changed, 116 insertions(+), 80 deletions(-)
create mode 100644 crypto/asymmetric_keys/restrict.c

diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index f90486256f01..6516855bec18 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -4,7 +4,10 @@

obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o

-asymmetric_keys-y := asymmetric_type.o signature.o
+asymmetric_keys-y := \
+ asymmetric_type.o \
+ restrict.o \
+ signature.o

obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o

diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c
new file mode 100644
index 000000000000..b4c10f2f5034
--- /dev/null
+++ b/crypto/asymmetric_keys/restrict.c
@@ -0,0 +1,106 @@
+/* Instantiate a public key crypto key from an X.509 Certificate
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ *
+ * 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 <crypto/public_key.h>
+#include "asymmetric_keys.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
+
+/*
+ * 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 = find_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 = verify_signature(key, cert->sig);
+ if (ret == -ENOPKG)
+ cert->unsupported_sig = true;
+ }
+ key_put(key);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(x509_validate_trust);
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 05eef1c68881..7a802b09a509 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -58,3 +58,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 117a6ee71a4d..6d7f42f0de9a 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -20,44 +20,6 @@
#include "asymmetric_keys.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
-
/*
* Set up the signature parameters in an X.509 certificate. This involves
* digesting the signed data and extracting the signature.
@@ -188,47 +150,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 = find_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 = verify_signature(key, 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)

2016-03-04 15:05:54

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 06/12] X.509: Use verify_signature() if we have a struct key * to use [ver #2]

We should call verify_signature() rather than directly calling
public_key_verify_signature() if we have a struct key to use as we
shouldn't be poking around in the private data of the key struct as that's
subtype dependent.

Signed-off-by: David Howells <[email protected]>
---

crypto/asymmetric_keys/x509_public_key.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 9c8483ef1cfe..117a6ee71a4d 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -220,8 +220,7 @@ static int x509_validate_trust(struct x509_certificate *cert,

if (!use_builtin_keys ||
test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
- ret = public_key_verify_signature(
- key->payload.data[asym_crypto], cert->sig);
+ ret = verify_signature(key, cert->sig);
if (ret == -ENOPKG)
cert->unsupported_sig = true;
}

2016-03-04 15:07:38

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 05/12] KEYS: Generalise x509_request_asymmetric_key() [ver #2]

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 <[email protected]>
---

crypto/asymmetric_keys/asymmetric_keys.h | 2 +
crypto/asymmetric_keys/asymmetric_type.c | 42 +++++++++++++++---------------
crypto/asymmetric_keys/pkcs7_trust.c | 19 ++++++--------
crypto/asymmetric_keys/x509_public_key.c | 5 +---
include/keys/asymmetric-type.h | 8 +++---
5 files changed, 37 insertions(+), 39 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/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index c4d66cd82860..6600181d5d01 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -35,21 +35,20 @@ static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem);

/**
- * x509_request_asymmetric_key - Request a key by X.509 certificate params.
+ * find_asymmetric_key - Find 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 *find_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;
@@ -57,12 +56,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>". */
@@ -102,14 +101,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;
}
}
@@ -121,7 +121,7 @@ reject:
key_put(key);
return ERR_PTR(-EKEYREJECTED);
}
-EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
+EXPORT_SYMBOL_GPL(find_asymmetric_key);

/**
* asymmetric_key_generate_id: Construct an asymmetric key ID
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 36e77cb07bd0..f6a009d88a33 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -51,9 +51,8 @@ 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 = find_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 +83,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 = find_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 +100,8 @@ 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 = find_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/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 2fb594175cef..9c8483ef1cfe 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -213,9 +213,8 @@ static 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 = find_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/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
index 735db697c4d2..b38240716d41 100644
--- a/include/keys/asymmetric-type.h
+++ b/include/keys/asymmetric-type.h
@@ -76,10 +76,10 @@ const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
return key->payload.data[asym_key_ids];
}

-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 *find_asymmetric_key(struct key *keyring,
+ const struct asymmetric_key_id *id_0,
+ const struct asymmetric_key_id *id_1,
+ bool partial);

/*
* The payload is at the discretion of the subtype.

2016-03-04 15:00:59

by David Howells

[permalink] [raw]
Subject: [RFC PATCH 04/12] KEYS: Move x509_request_asymmetric_key() to asymmetric_type.c [ver #2]

Move x509_request_asymmetric_key() to asymmetric_type.c so that it can be
generalised.

Signed-off-by: David Howells <[email protected]>
---

crypto/asymmetric_keys/asymmetric_type.c | 89 ++++++++++++++++++++++++++++++
crypto/asymmetric_keys/x509_public_key.c | 89 ------------------------------
include/crypto/public_key.h | 6 --
include/keys/asymmetric-type.h | 5 ++
4 files changed, 94 insertions(+), 95 deletions(-)

diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index a79d30128821..c4d66cd82860 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -35,6 +35,95 @@ static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem);

/**
+ * 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);
+
+/**
* asymmetric_key_generate_id: Construct an asymmetric key ID
* @val_1: First binary blob
* @len_1: Length of first binary blob
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index fc77a2bd70ba..2fb594175cef 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -58,95 +58,6 @@ static int __init ca_keys_setup(char *str)
__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.
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index b3928e801b8c..96ef27b8dd41 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -50,12 +50,6 @@ struct key;
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);
-
int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig);

diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
index d1e23dda4363..735db697c4d2 100644
--- a/include/keys/asymmetric-type.h
+++ b/include/keys/asymmetric-type.h
@@ -76,6 +76,11 @@ const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
return key->payload.data[asym_key_ids];
}

+extern struct key *x509_request_asymmetric_key(struct key *keyring,
+ const struct asymmetric_key_id *id,
+ const struct asymmetric_key_id *skid,
+ bool partial);
+
/*
* The payload is at the discretion of the subtype.
*/

2016-03-08 02:05:56

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

On Fri, 2016-03-04 at 15:01 +0000, David Howells wrote:
> 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).

Renaming of the system_trusted_keyring to builtin_trusted_keys is fine,
but we're left with a lot of references to "system_trusted" (eg.
restrict_link_to_system_trusted, depends on SYSTEM_TRUSTED_KEYRING, the
subsequent patch description and Kconfig use "system trusted keyrings",
etc). Without changing these references, I'm not convinced this is an
improvement.

Mimi

> 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 <[email protected]>


2016-03-08 02:26:50

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

On Fri, 2016-03-04 at 15:01 +0000, David Howells wrote:
> Provide a config option (IMA_PERMIT_ADD_TO_IMA_KEYRINGS) that, when
> enabled, allows keys to be added to the IMA keyrings by userspace - with
> the restriction that each must be signed by a key in the system trusted
> keyrings.

Here is an example of using the term "system trusted keyrings", which
the previous patch removes.

> EPERM will be returned if this option is disabled, ENOKEY will be returned if
> no authoritative key can be found and EKEYREJECTED will be returned if the
> signature doesn't match. Other errors such as ENOPKG may also be returned.
>
> If this new option is enabled, the builtin system keyring is searched, as is
> the secondary system keyring if that is also enabled. Intermediate keys
> between the builtin system keyring and the key being added can be added to
> the secondary keyring (which replaces .ima_mok) to form a trust chain -
> provided they are also validly signed by a key in one of the trusted keyrings.

Only certificates signed by a key on the system keyring were added to
the IMA keyring, unless IMA_MOK_KEYRING was configured. Then, the
certificate could be signed by a either a key on the system or ima_mok
keyrings. To replicate this behavior, the default behavior should be to
only permit certificates signed by a key on the builtin keyring, unless
this new Kconfig is enabled. Only then, permit certificates signed by a
key on either the builtin or secondary keyrings to be added to the IMA
keyring.

Mimi


> The .ima_mok keyring is removed.
>
> Signed-off-by: David Howells <[email protected]>
> ---
>
> include/keys/system_keyring.h | 9 ---------
> security/integrity/digsig.c | 31 +++++--------------------------
> security/integrity/ima/Kconfig | 36 ++++++++++++++++++++++++------------
> security/integrity/ima/ima_mok.c | 12 ++----------
> 4 files changed, 31 insertions(+), 57 deletions(-)
>
> diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
> index c6c05f1513f5..0764a8c1c131 100644
> --- a/include/keys/system_keyring.h
> +++ b/include/keys/system_keyring.h
> @@ -29,22 +29,13 @@ extern int restrict_link_by_builtin_trusted(struct key *keyring,
> #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;
> diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
> index ac2d39232567..aef3ac7be868 100644
> --- a/security/integrity/digsig.c
> +++ b/security/integrity/digsig.c
> @@ -42,32 +42,10 @@ static bool init_keyring __initdata = true;
> static bool init_keyring __initdata;
> #endif
>
> -#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
> -/*
> - * 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 restrict_link_by_signature(get_ima_mok_keyring(),
> - type, payload);
> -}
> +#ifdef CONFIG_IMA_PERMIT_ADD_TO_IMA_KEYRINGS
> +#define restrict_link_to_ima restrict_link_by_system_trusted
> #else
> -/*
> - * If there's no system trusted keyring, then keys cannot be loaded into
> - * .ima_mok and added keys cannot be marked trusted.
> - */
> -#define restrict_link_by_ima_mok restrict_link_reject
> +#define restrict_link_to_ima restrict_link_reject
> #endif
>
> int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
> @@ -114,7 +92,8 @@ int __init integrity_init_keyring(const unsigned int id)
> KEY_USR_VIEW | KEY_USR_READ |
> KEY_USR_WRITE | KEY_USR_SEARCH),
> KEY_ALLOC_NOT_IN_QUOTA,
> - restrict_link_by_ima_mok, NULL);
> + restrict_link_to_ima,
> + 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..890e8aa8ccb4 100644
> --- a/security/integrity/ima/Kconfig
> +++ b/security/integrity/ima/Kconfig
> @@ -155,23 +155,35 @@ config IMA_TRUSTED_KEYRING
>
> This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING
>
> +config IMA_PERMIT_ADD_TO_IMA_KEYRINGS
> + bool "Allow keys to be added to the ima keyrings, with restrictions"
> + depends on IMA_APPRAISE
> + depends on SYSTEM_TRUSTED_KEYRING
> + select INTEGRITY_TRUSTED_KEYRING
> + default n
> + help
> + This option permits keys to be added to the ima keyrings using
> + add_key() or KEYCTL_LINK - with the restriction that the key must be
> + validly signed by a key in one of the system trusted keyrings.
> +
> + Intermediate keys between those the kernel has compiled in and the
> + keys to be added may be added to the system secondary keyring if that
> + is enabled - provided those are validly signed by a key in the system
> + trusted keyrings.
> +
> + If this is not set, attempts to add to the ima keyrings will be
> + rejected with EPERM.
> +
> config IMA_MOK_KEYRING
> - bool "Create IMA machine owner keys (MOK) and blacklist keyrings"
> + bool "Create IMA machine owner 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.
> + This option creates IMA blacklist keyring. This 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"
> diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
> index be0da013622c..031d65a91297 100644
> --- a/security/integrity/ima/ima_mok.c
> +++ b/security/integrity/ima/ima_mok.c
> @@ -28,15 +28,7 @@ struct key *ima_blacklist_keyring;
> */
> __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);
> + pr_notice("Allocating IMA blacklist keyrings.\n");
>
> ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
> KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
> @@ -46,7 +38,7 @@ __init int ima_mok_init(void)
> KEY_ALLOC_NOT_IN_QUOTA,
> restrict_link_by_system_trusted, NULL);
>
> - if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
> + if (IS_ERR(ima_blacklist_keyring))
> panic("Can't allocate IMA MOK or blacklist keyrings.");
>
> set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


2016-03-08 13:08:42

by David Howells

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

Mimi Zohar <[email protected]> wrote:

> Only certificates signed by a key on the system keyring were added to
> the IMA keyring, unless IMA_MOK_KEYRING was configured. Then, the
> certificate could be signed by a either a key on the system or ima_mok
> keyrings. To replicate this behavior, the default behavior should be to
> only permit certificates signed by a key on the builtin keyring, unless
> this new Kconfig is enabled. Only then, permit certificates signed by a
> key on either the builtin or secondary keyrings to be added to the IMA
> keyring.

How about I change it to a choice-type item, with the following options:

(1) No addition.

(2) Addition restricted by built-in keyring.

(3) Addition restricted by secondary keyring + built-in keyring.

where the second and third options then depend on the appropriate keyrings
being enabled.

David

2016-03-08 13:14:03

by David Howells

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

Mimi Zohar <[email protected]> wrote:

> but we're left with a lot of references to "system_trusted" (eg.
> restrict_link_to_system_trusted, depends on SYSTEM_TRUSTED_KEYRING

How about I pluralise it to SYSTEM_TRUSTED_KEYRINGS? The fact that one is
called builtin and the other secondary doesn't detract from the fact that
they're both system-wide rings of trusted keys.

Or would you prefer .system_trusted_keys and .secondary_trusted_keys? Even
though the second is also a "system" trusted keyring.

David

2016-03-08 14:13:51

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

On Tue, 2016-03-08 at 13:08 +0000, David Howells wrote:
> Mimi Zohar <[email protected]> wrote:
>
> > Only certificates signed by a key on the system keyring were added to
> > the IMA keyring, unless IMA_MOK_KEYRING was configured. Then, the
> > certificate could be signed by a either a key on the system or ima_mok
> > keyrings. To replicate this behavior, the default behavior should be to
> > only permit certificates signed by a key on the builtin keyring, unless
> > this new Kconfig is enabled. Only then, permit certificates signed by a
> > key on either the builtin or secondary keyrings to be added to the IMA
> > keyring.
>
> How about I change it to a choice-type item, with the following options:
>
> (1) No addition.
>
> (2) Addition restricted by built-in keyring.
>
> (3) Addition restricted by secondary keyring + built-in keyring.
>
> where the second and third options then depend on the appropriate keyrings
> being enabled.

So option 1 is where IMA-appraisal is configured, but neither the
builtin nor the secondary keys are enabled. This would be the
equivalent of having a set of "builtin" keys loaded directly onto the
IMA keyring, without the ability of adding additional keys.

Ok, I'm fine this solution.

thanks,

Mimi

2016-03-08 14:14:39

by Petko Manolov

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

On 16-03-08 13:08:36, David Howells wrote:
> Mimi Zohar <[email protected]> wrote:
>
> > Only certificates signed by a key on the system keyring were added to
> > the IMA keyring, unless IMA_MOK_KEYRING was configured. Then, the
> > certificate could be signed by a either a key on the system or ima_mok
> > keyrings. To replicate this behavior, the default behavior should be to
> > only permit certificates signed by a key on the builtin keyring, unless
> > this new Kconfig is enabled. Only then, permit certificates signed by a
> > key on either the builtin or secondary keyrings to be added to the IMA
> > keyring.
>
> How about I change it to a choice-type item, with the following options:
>
> (1) No addition.
>
> (2) Addition restricted by built-in keyring.
>
> (3) Addition restricted by secondary keyring + built-in keyring.
>
> where the second and third options then depend on the appropriate keyrings
> being enabled.

I would suggest leaving (1) and (3). Since secondary keyring only accepts keys
signed by certificate in the system keyring I think (2) is redundant. It adds
extra complexity (Kconfig is vague enough already) while it doesn't increase the
overall security by much.


cheers,
Petko

2016-03-08 14:17:29

by Petko Manolov

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

On 16-03-08 13:13:59, David Howells wrote:
> Mimi Zohar <[email protected]> wrote:
>
> > but we're left with a lot of references to "system_trusted" (eg.
> > restrict_link_to_system_trusted, depends on SYSTEM_TRUSTED_KEYRING
>
> How about I pluralise it to SYSTEM_TRUSTED_KEYRINGS? The fact that one is
> called builtin and the other secondary doesn't detract from the fact that
> they're both system-wide rings of trusted keys.
>
> Or would you prefer .system_trusted_keys and .secondary_trusted_keys? Even
> though the second is also a "system" trusted keyring.

Ah, naming things... This is true science... :-)


cheers,
Petko

2016-03-08 14:32:26

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

On Tue, 2016-03-08 at 13:13 +0000, David Howells wrote:
> Mimi Zohar <[email protected]> wrote:
>
> > but we're left with a lot of references to "system_trusted" (eg.
> > restrict_link_to_system_trusted, depends on SYSTEM_TRUSTED_KEYRING
>
> How about I pluralise it to SYSTEM_TRUSTED_KEYRINGS? The fact that one is
> called builtin and the other secondary doesn't detract from the fact that
> they're both system-wide rings of trusted keys.

Would then restrict_link_to_system_trusted imply both the builtin and
secondary keyrings or just the builtin keyrings? Changing the system
keyring name to builtin keys, without changing the corresponding
restrict_link name, obfuscates what is really happening.

Mimi


2016-03-08 14:38:46

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

On Tue, 2016-03-08 at 16:14 +0200, Petko Manolov wrote:
> On 16-03-08 13:08:36, David Howells wrote:
> > Mimi Zohar <[email protected]> wrote:
> >
> > > Only certificates signed by a key on the system keyring were added to
> > > the IMA keyring, unless IMA_MOK_KEYRING was configured. Then, the
> > > certificate could be signed by a either a key on the system or ima_mok
> > > keyrings. To replicate this behavior, the default behavior should be to
> > > only permit certificates signed by a key on the builtin keyring, unless
> > > this new Kconfig is enabled. Only then, permit certificates signed by a
> > > key on either the builtin or secondary keyrings to be added to the IMA
> > > keyring.
> >
> > How about I change it to a choice-type item, with the following options:
> >
> > (1) No addition.
> >
> > (2) Addition restricted by built-in keyring.
> >
> > (3) Addition restricted by secondary keyring + built-in keyring.
> >
> > where the second and third options then depend on the appropriate keyrings
> > being enabled.
>
> I would suggest leaving (1) and (3). Since secondary keyring only accepts keys
> signed by certificate in the system keyring I think (2) is redundant. It adds
> extra complexity (Kconfig is vague enough already) while it doesn't increase the
> overall security by much.

I think you mean option 2 or 3, as option 1 implies not allowing any
keys to be added to the IMA keyring.

Mimi

2016-03-08 14:43:23

by David Howells

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

Mimi Zohar <[email protected]> wrote:

> Would then restrict_link_to_system_trusted imply both the builtin and
> secondary keyrings or just the builtin keyrings?

Both, if available; just builtin if the secondary is not available.

restrict_link_by_builtin_trusted() does only the builtin.

> Changing the system keyring name to builtin keys, without changing the
> corresponding restrict_link name, obfuscates what is really happening.

You can still look at the code, it's not as if it's particularly hidden.

The problem boils down to a difficulty in concocting a name that describes a
complex situation that may change depending on the configuration. I can make
it "restrict_link_by_any_system_trusted" if you'd prefer.

That's why I want "system trusted keyrings" to refer to the builtin and the
secondary - *and* an extra UEFI keyring if we grow one of those. It's a
collection of related keyrings.

David

2016-03-08 14:44:34

by David Howells

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

Petko Manolov <[email protected]> wrote:

> I would suggest leaving (1) and (3).

Do you mean dropping option (2) and leaving (1) and (3)? Or do you mean
dropping options (1) and (3)?

David

2016-03-08 15:09:39

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

On Tue, 2016-03-08 at 14:43 +0000, David Howells wrote:
> The problem boils down to a difficulty in concocting a name that describes a
> complex situation that may change depending on the configuration. I can make
> it "restrict_link_by_any_system_trusted" if you'd prefer.
>
> That's why I want "system trusted keyrings" to refer to the builtin and the
> secondary - *and* an extra UEFI keyring if we grow one of those. It's a
> collection of related keyrings.

Sigh, this is the same discussion we've had for years. The UEFI keys
should not be trusted to validate the certificates being added to the
IMA keyring. Neither should the keys on the secondary keyring, unless
specifically IMA Kconfig enabled, be used to validate the certificates
being added to the IMA keyring. Just because the UEFI keys or the
secondary keyring is enabled, doesn't mean that certificates signed by a
key on either of those keyrings, should be added to the IMA keyring.

The machine/system owner should control which keys can be used to verify
certificates being added to the IMA keyring.

Mimi

2016-03-08 15:32:33

by David Howells

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

Mimi Zohar <[email protected]> wrote:

> > The problem boils down to a difficulty in concocting a name that describes a
> > complex situation that may change depending on the configuration. I can make
> > it "restrict_link_by_any_system_trusted" if you'd prefer.
> >
> > That's why I want "system trusted keyrings" to refer to the builtin and the
> > secondary - *and* an extra UEFI keyring if we grow one of those. It's a
> > collection of related keyrings.
>
> Sigh, this is the same discussion we've had for years.

No, it isn't.

> The UEFI keys should not be trusted to validate the certificates being added
> to the IMA keyring.

A machine-security (e.g. UEFI) keyring will conceivably live in
certs/system_keyring.c and only be enabled if CONFIG_SYSTEM_TRUSTED_KEYRINGS=y
and, say, CONFIG_MACHINE_TRUSTED_KEYRING=y. I didn't say that IMA necessarily
has to use it.

What we need to do is define a set of functions allow IMA to get the
restrictions it wants, depending on configuration. In the code I currently
have, I think we have those:

restrict_link_reject
restrict_link_by_builtin_trusted
restrict_link_by_system_trusted

If you really want, I can add a restrict_link_for_ima in there, but I'd rather
not if IMA can use whichever of the above three most suits it. How about:

restrict_link_reject
restrict_link_by_builtin_trusted
restrict_link_by_builtin_or_secondary_trusted

> Neither should the keys on the secondary keyring, unless specifically IMA
> Kconfig enabled, be used to validate the certificates being added to the IMA
> keyring.

Yes.

David

2016-03-08 15:48:49

by Petko Manolov

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

On 16-03-08 14:44:24, David Howells wrote:
> Petko Manolov <[email protected]> wrote:
>
> > I would suggest leaving (1) and (3).
>
> Do you mean dropping option (2) and leaving (1) and (3)? Or do you mean
> dropping options (1) and (3)?

Dropping option (2) and leaving (1) and (3).

(2) is subset of (3) and IMHO adds unnecessary complexity.


Petko

2016-03-08 16:07:09

by David Howells

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

Petko Manolov <[email protected]> wrote:

> > How about I change it to a choice-type item, with the following options:
> >
> > (1) No addition.
> >
> > (2) Addition restricted by built-in keyring.
> >
> > (3) Addition restricted by secondary keyring + built-in keyring.
> >
> > where the second and third options then depend on the appropriate keyrings
> > being enabled.
>
> I would suggest leaving (1) and (3). Since secondary keyring only accepts
> keys signed by certificate in the system keyring I think (2) is redundant.
> It adds extra complexity (Kconfig is vague enough already) while it doesn't
> increase the overall security by much.

If I remove option (2), that would mean that if you want to allow keys to be
added to .ima if they're signed by the built-in keyring, then you also allow
keys to be added to .ima if they're signed by the secondary keyring if
enabled.

Remember - these keyrings aren't necessarily restricted to IMA.

David

2016-03-08 16:15:33

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 11/12] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

On Tue, 2016-03-08 at 15:32 +0000, David Howells wrote:
> Mimi Zohar <[email protected]> wrote:
>
> > > The problem boils down to a difficulty in concocting a name that describes a
> > > complex situation that may change depending on the configuration. I can make
> > > it "restrict_link_by_any_system_trusted" if you'd prefer.
> > >
> > > That's why I want "system trusted keyrings" to refer to the builtin and the
> > > secondary - *and* an extra UEFI keyring if we grow one of those. It's a
> > > collection of related keyrings.
> >
> > Sigh, this is the same discussion we've had for years.
>
> No, it isn't.

Good!

> > The UEFI keys should not be trusted to validate the certificates being added
> > to the IMA keyring.
>
> A machine-security (e.g. UEFI) keyring will conceivably live in
> certs/system_keyring.c and only be enabled if CONFIG_SYSTEM_TRUSTED_KEYRINGS=y
> and, say, CONFIG_MACHINE_TRUSTED_KEYRING=y. I didn't say that IMA necessarily
> has to use it.

Ok.

> What we need to do is define a set of functions allow IMA to get the
> restrictions it wants, depending on configuration. In the code I currently
> have, I think we have those:
>
> restrict_link_reject

Option 1

> restrict_link_by_builtin_trusted

Option 2

> restrict_link_by_system_trusted

By renaming the system keyring to builtin, this is where it becomes
unclear what is included by restrict_link_by_system_trusted - builtin
and secondary, or builtin, secondary, and UEFI.

> If you really want, I can add a restrict_link_for_ima in there, but I'd rather
> not if IMA can use whichever of the above three most suits it. How about:
>
> restrict_link_reject
> restrict_link_by_builtin_trusted
> restrict_link_by_builtin_or_secondary_trusted

Option 3 - "restrict_link_by_builtin_or_secondary_trusted" is a bit
wordy, but there wouldn't be any confusion.

Mimi

> > Neither should the keys on the secondary keyring, unless specifically IMA
> > Kconfig enabled, be used to validate the certificates being added to the IMA
> > keyring.
>
> Yes.
>
> David
>


2016-03-08 16:38:17

by Petko Manolov

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

On 16-03-08 16:07:00, David Howells wrote:
> Petko Manolov <[email protected]> wrote:
>
> > > How about I change it to a choice-type item, with the following options:
> > >
> > > (1) No addition.
> > >
> > > (2) Addition restricted by built-in keyring.
> > >
> > > (3) Addition restricted by secondary keyring + built-in keyring.
> > >
> > > where the second and third options then depend on the appropriate keyrings
> > > being enabled.
> >
> > I would suggest leaving (1) and (3). Since secondary keyring only accepts
> > keys signed by certificate in the system keyring I think (2) is redundant.
> > It adds extra complexity (Kconfig is vague enough already) while it doesn't
> > increase the overall security by much.
>
> If I remove option (2), that would mean that if you want to allow keys to be
> added to .ima if they're signed by the built-in keyring, then you also allow
> keys to be added to .ima if they're signed by the secondary keyring if
> enabled.

Exactly. The primary difference between the built-in and secondary keyring is
that the latter is R/W. Chances are the user want either no addition or need
dynamic key add/remove.

I don't have strong opinions against (2). This is more of a discussion whether
we should sacrifice in favor of simplicity or flexibility.

> Remember - these keyrings aren't necessarily restricted to IMA.

I am well aware of that. At some point (perhaps not now) i'd like to discuss
allowing kernel module loading based on keys in the secondary keyring. It is a
niche feature for those machines that have uptime measured in years. I
certainly don't expect it to be something the regular desktop or embedded users
need.

Another issue that we left unresolved is the system-wide blacklist keyring. It
is at the same hierarchy level as the secondary keyring and serves a similar
purpose although in opposite direction.


Petko

2016-03-08 22:05:46

by Mimi Zohar

[permalink] [raw]
Subject: Re: [RFC PATCH 12/12] IMA: Use the the system trusted keyrings instead of .ima_mok [ver #2]

On Tue, 2016-03-08 at 18:37 +0200, Petko Manolov wrote:
> On 16-03-08 16:07:00, David Howells wrote:
> > Petko Manolov <[email protected]> wrote:
> >
> > > > How about I change it to a choice-type item, with the following options:
> > > >
> > > > (1) No addition.
> > > >
> > > > (2) Addition restricted by built-in keyring.
> > > >
> > > > (3) Addition restricted by secondary keyring + built-in keyring.
> > > >
> > > > where the second and third options then depend on the appropriate keyrings
> > > > being enabled.
> > >
> > > I would suggest leaving (1) and (3). Since secondary keyring only accepts
> > > keys signed by certificate in the system keyring I think (2) is redundant.
> > > It adds extra complexity (Kconfig is vague enough already) while it doesn't
> > > increase the overall security by much.
> >
> > If I remove option (2), that would mean that if you want to allow keys to be
> > added to .ima if they're signed by the built-in keyring, then you also allow
> > keys to be added to .ima if they're signed by the secondary keyring if
> > enabled.
>
> Exactly. The primary difference between the built-in and secondary keyring is
> that the latter is R/W. Chances are the user want either no addition or need
> dynamic key add/remove.

Option 1 will prevent ANY keys from being added to the IMA keyring that
were not builtin and loaded by the kernel, similar to the existing
system certificate list. The keyring itself would need to allow the
builtin keys to be added with the "KEY_ALLOC_BYPASS_RESTRICTION"
override.

Option 2 only allows certificates signed by a key on the builtin keyring
to be added to the IMA keyring. (This should be the default.)

> I don't have strong opinions against (2). This is more of a discussion whether
> we should sacrifice in favor of simplicity or flexibility.

I disagree. There is a major difference between option 2 and 3.

Mimi