Merge branch 'keys-trust' into keys-next

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.

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

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

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

 (5) 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_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY,
     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 this option 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.

Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells 2016-05-04 17:20:20 +01:00
commit d55201ce08
41 changed files with 673 additions and 517 deletions

View File

@ -1029,6 +1029,10 @@ payload contents" for more information.
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred, const struct cred *cred,
key_perm_t perm, key_perm_t perm,
int (*restrict_link)(struct key *,
const struct key_type *,
unsigned long,
const union key_payload *),
unsigned long flags, unsigned long flags,
struct key *dest); struct key *dest);
@ -1040,6 +1044,24 @@ payload contents" for more information.
KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted 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. 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: (*) To check the validity of a key, this function can be called:

View File

@ -19,8 +19,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/verify_pefile.h> #include <linux/verification.h>
#include <keys/system_keyring.h>
#include <asm/bootparam.h> #include <asm/bootparam.h>
#include <asm/setup.h> #include <asm/setup.h>
@ -529,18 +528,9 @@ static int bzImage64_cleanup(void *loader_data)
#ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
{ {
bool trusted; return verify_pefile_signature(kernel, kernel_len,
int ret; NULL,
VERIFYING_KEXEC_PE_SIGNATURE);
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;
} }
#endif #endif

View File

@ -17,6 +17,7 @@ config MODULE_SIG_KEY
config SYSTEM_TRUSTED_KEYRING config SYSTEM_TRUSTED_KEYRING
bool "Provide system-wide ring of trusted keys" bool "Provide system-wide ring of trusted keys"
depends on KEYS depends on KEYS
depends on ASYMMETRIC_KEY_TYPE
help help
Provide a system keyring to which trusted keys can be added. Keys in 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 the keyring are considered to be trusted. Keys may be added at will
@ -55,4 +56,12 @@ config SYSTEM_EXTRA_CERTIFICATE_SIZE
This is the number of bytes reserved in the kernel image for a This is the number of bytes reserved in the kernel image for a
certificate to be inserted. 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 endmenu

View File

@ -18,29 +18,88 @@
#include <keys/system_keyring.h> #include <keys/system_keyring.h>
#include <crypto/pkcs7.h> #include <crypto/pkcs7.h>
struct key *system_trusted_keyring; static struct key *builtin_trusted_keys;
EXPORT_SYMBOL_GPL(system_trusted_keyring); #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
static struct key *secondary_trusted_keys;
#endif
extern __initconst const u8 system_certificate_list[]; extern __initconst const u8 system_certificate_list[];
extern __initconst const unsigned long system_certificate_list_size; extern __initconst const unsigned long system_certificate_list_size;
/**
* 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);
}
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
/**
* restrict_link_by_builtin_and_secondary_trusted - Restrict keyring
* addition by both builtin and secondary keyrings
*
* Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in either the built-in or the secondary system
* keyrings.
*/
int restrict_link_by_builtin_and_secondary_trusted(
struct key *keyring,
const struct key_type *type,
const union key_payload *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.
*/
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);
}
#endif
/* /*
* Load the compiled-in keys * Create the trusted keyrings
*/ */
static __init int system_trusted_keyring_init(void) 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 = builtin_trusted_keys =
keyring_alloc(".system_keyring", keyring_alloc(".builtin_trusted_keys",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH), KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA,
if (IS_ERR(system_trusted_keyring)) NULL, NULL);
panic("Can't allocate system trusted keyring\n"); 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_builtin_and_secondary_trusted,
NULL);
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
set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
return 0; return 0;
} }
@ -76,7 +135,7 @@ static __init int load_system_certificate_list(void)
if (plen > end - p) if (plen > end - p)
goto dodgy_cert; 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", "asymmetric",
NULL, NULL,
p, p,
@ -84,8 +143,8 @@ static __init int load_system_certificate_list(void)
((KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ), KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_NOT_IN_QUOTA |
KEY_ALLOC_TRUSTED | KEY_ALLOC_BUILT_IN |
KEY_ALLOC_BUILT_IN); KEY_ALLOC_BYPASS_RESTRICTION);
if (IS_ERR(key)) { if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key)); PTR_ERR(key));
@ -108,19 +167,27 @@ late_initcall(load_system_certificate_list);
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
/** /**
* Verify a PKCS#7-based signature on system data. * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
* @data: The data to be verified. * @data: The data to be verified (NULL if expecting internal data).
* @len: Size of @data. * @len: Size of @data.
* @raw_pkcs7: The PKCS#7 message that is the signature. * @raw_pkcs7: The PKCS#7 message that is the signature.
* @pkcs7_len: The size of @raw_pkcs7. * @pkcs7_len: The size of @raw_pkcs7.
* @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. * @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, int verify_pkcs7_signature(const void *data, size_t len,
const void *raw_pkcs7, size_t pkcs7_len, const void *raw_pkcs7, size_t pkcs7_len,
enum key_being_used_for usage) struct key *trusted_keys,
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; struct pkcs7_message *pkcs7;
bool trusted;
int ret; int ret;
pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len); pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
@ -128,7 +195,7 @@ int system_verify_data(const void *data, unsigned long len,
return PTR_ERR(pkcs7); return PTR_ERR(pkcs7);
/* The data should be detached - so we need to supply it. */ /* 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"); pr_err("PKCS#7 signature with non-detached data\n");
ret = -EBADMSG; ret = -EBADMSG;
goto error; goto error;
@ -138,13 +205,33 @@ int system_verify_data(const void *data, unsigned long len,
if (ret < 0) if (ret < 0)
goto error; goto error;
ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); if (!trusted_keys) {
if (ret < 0) 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)
pr_err("PKCS#7 signature not signed with a trusted key\n");
goto error; goto error;
}
if (!trusted) { if (view_content) {
pr_err("PKCS#7 signature not signed with a trusted key\n"); size_t asn1hdrlen;
ret = -ENOKEY;
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: error:
@ -152,6 +239,6 @@ error:
pr_devel("<==%s() = %d\n", __func__, ret); pr_devel("<==%s() = %d\n", __func__, ret);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(system_verify_data); EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */

View File

@ -1,5 +1,5 @@
menuconfig ASYMMETRIC_KEY_TYPE menuconfig ASYMMETRIC_KEY_TYPE
tristate "Asymmetric (public-key cryptographic) key type" bool "Asymmetric (public-key cryptographic) key type"
depends on KEYS depends on KEYS
help help
This option provides support for a key type that holds the data for This option provides support for a key type that holds the data for
@ -40,8 +40,7 @@ config PKCS7_MESSAGE_PARSER
config PKCS7_TEST_KEY config PKCS7_TEST_KEY
tristate "PKCS#7 testing key type" tristate "PKCS#7 testing key type"
depends on PKCS7_MESSAGE_PARSER depends on SYSTEM_DATA_VERIFICATION
select SYSTEM_TRUSTED_KEYRING
help help
This option provides a type of key that can be loaded up from a 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 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 config SIGNED_PE_FILE_VERIFICATION
bool "Support for PE file signature verification" bool "Support for PE file signature verification"
depends on PKCS7_MESSAGE_PARSER=y depends on PKCS7_MESSAGE_PARSER=y
depends on SYSTEM_DATA_VERIFICATION
select ASN1 select ASN1
select OID_REGISTRY select OID_REGISTRY
help help

View File

@ -4,7 +4,10 @@
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o 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 obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o

View File

@ -9,6 +9,8 @@
* 2 of the Licence, or (at your option) any later version. * 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 struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
extern int __asymmetric_key_hex_to_key_id(const char *id, extern int __asymmetric_key_hex_to_key_id(const char *id,

View File

@ -34,6 +34,95 @@ EXPORT_SYMBOL_GPL(key_being_used_for);
static LIST_HEAD(asymmetric_key_parsers); static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem); static DECLARE_RWSEM(asymmetric_key_parsers_sem);
/**
* find_asymmetric_key - Find a key by ID.
* @keyring: The keys to search.
* @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 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 *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;
const char *lookup;
char *req, *p;
int len;
if (id_0) {
lookup = id_0->data;
len = id_0->len;
} else {
lookup = id_1->data;
len = id_1->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_0 && id_1) {
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
if (!kids->id[0]) {
pr_debug("First ID matches, but second is missing\n");
goto reject;
}
if (!asymmetric_key_id_same(id_1, kids->id[1])) {
pr_debug("First ID matches, but second 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(find_asymmetric_key);
/** /**
* asymmetric_key_generate_id: Construct an asymmetric key ID * asymmetric_key_generate_id: Construct an asymmetric key ID
* @val_1: First binary blob * @val_1: First binary blob

View File

@ -21,19 +21,13 @@
/* /*
* Parse a Microsoft Individual Code Signing blob * 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; struct pefile_context *ctx = _ctx;
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;
}
content_data -= asn1hdrlen;
data_len += asn1hdrlen;
pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
content_data); content_data);
@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen,
{ {
struct pefile_context *ctx = context; struct pefile_context *ctx = context;
ctx->digest = value; ctx->digest = kmemdup(value, vlen, GFP_KERNEL);
ctx->digest_len = vlen; return ctx->digest ? 0 : -ENOMEM;
return 0;
} }

View File

@ -13,12 +13,9 @@
#include <linux/key.h> #include <linux/key.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/verification.h>
#include <linux/key-type.h> #include <linux/key-type.h>
#include <keys/asymmetric-type.h>
#include <crypto/pkcs7.h>
#include <keys/user-type.h> #include <keys/user-type.h>
#include <keys/system_keyring.h>
#include "pkcs7_parser.h"
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PKCS#7 testing key type"); MODULE_DESCRIPTION("PKCS#7 testing key type");
@ -28,58 +25,45 @@ module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(pkcs7_usage, MODULE_PARM_DESC(pkcs7_usage,
"Usage to specify when verifying the PKCS#7 message"); "Usage to specify when verifying the PKCS#7 message");
/*
* Retrieve the PKCS#7 message content.
*/
static int pkcs7_view_content(void *ctx, const void *data, size_t len,
size_t asn1hdrlen)
{
struct key_preparsed_payload *prep = ctx;
const void *saved_prep_data;
size_t saved_prep_datalen;
int ret;
saved_prep_data = prep->data;
saved_prep_datalen = prep->datalen;
prep->data = data;
prep->datalen = len;
ret = user_preparse(prep);
prep->data = saved_prep_data;
prep->datalen = saved_prep_datalen;
return ret;
}
/* /*
* Preparse a PKCS#7 wrapped and validated data blob. * Preparse a PKCS#7 wrapped and validated data blob.
*/ */
static int pkcs7_preparse(struct key_preparsed_payload *prep) static int pkcs7_preparse(struct key_preparsed_payload *prep)
{ {
enum key_being_used_for usage = pkcs7_usage; enum key_being_used_for usage = pkcs7_usage;
struct pkcs7_message *pkcs7;
const void *data, *saved_prep_data;
size_t datalen, saved_prep_datalen;
bool trusted;
int ret;
kenter("");
if (usage >= NR__KEY_BEING_USED_FOR) { if (usage >= NR__KEY_BEING_USED_FOR) {
pr_err("Invalid usage type %d\n", usage); pr_err("Invalid usage type %d\n", usage);
return -EINVAL; return -EINVAL;
} }
saved_prep_data = prep->data; return verify_pkcs7_signature(NULL, 0,
saved_prep_datalen = prep->datalen; prep->data, prep->datalen,
pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); NULL, usage,
if (IS_ERR(pkcs7)) { pkcs7_view_content, prep);
ret = PTR_ERR(pkcs7);
goto error;
}
ret = pkcs7_verify(pkcs7, usage);
if (ret < 0)
goto error_free;
ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
if (ret < 0)
goto error_free;
if (!trusted)
pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
if (ret < 0)
goto error_free;
prep->data = data;
prep->datalen = datalen;
ret = user_preparse(prep);
prep->data = saved_prep_data;
prep->datalen = saved_prep_datalen;
error_free:
pkcs7_free_message(pkcs7);
error:
kleave(" = %d", ret);
return ret;
} }
/* /*

View File

@ -168,24 +168,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message);
* @pkcs7: The preparsed PKCS#7 message to access * @pkcs7: The preparsed PKCS#7 message to access
* @_data: Place to return a pointer to the data * @_data: Place to return a pointer to the data
* @_data_len: Place to return the data length * @_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, * Get access to the data content of the PKCS#7 message. The size of the
* the header of the ASN.1 object that contains it. Returns -ENODATA if the * header of the ASN.1 object that contains it is also provided and can be used
* data object was missing from the message. * 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, int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
const void **_data, size_t *_data_len, const void **_data, size_t *_data_len,
bool want_wrapper) size_t *_headerlen)
{ {
size_t wrapper;
if (!pkcs7->data) if (!pkcs7->data)
return -ENODATA; return -ENODATA;
wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; *_data = pkcs7->data;
*_data = pkcs7->data - wrapper; *_data_len = pkcs7->data_len;
*_data_len = pkcs7->data_len + wrapper; if (_headerlen)
*_headerlen = pkcs7->data_hdrlen;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pkcs7_get_content_data); EXPORT_SYMBOL_GPL(pkcs7_get_content_data);

View File

@ -22,7 +22,6 @@ struct pkcs7_signed_info {
struct pkcs7_signed_info *next; struct pkcs7_signed_info *next;
struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
unsigned index; unsigned index;
bool trusted;
bool unsupported_crypto; /* T if not usable due to missing crypto */ bool unsupported_crypto; /* T if not usable due to missing crypto */
/* Message digest - the digest of the Content Data (or NULL) */ /* Message digest - the digest of the Content Data (or NULL) */

View File

@ -30,7 +30,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
struct public_key_signature *sig = sinfo->sig; struct public_key_signature *sig = sinfo->sig;
struct x509_certificate *x509, *last = NULL, *p; struct x509_certificate *x509, *last = NULL, *p;
struct key *key; struct key *key;
bool trusted;
int ret; int ret;
kenter(",%u,", sinfo->index); 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) { for (x509 = sinfo->signer; x509; x509 = x509->signer) {
if (x509->seen) { if (x509->seen) {
if (x509->verified) { if (x509->verified)
trusted = x509->trusted;
goto verified; goto verified;
}
kleave(" = -ENOKEY [cached]"); kleave(" = -ENOKEY [cached]");
return -ENOKEY; return -ENOKEY;
} }
@ -54,9 +51,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
/* Look to see if this certificate is present in the trusted /* Look to see if this certificate is present in the trusted
* keys. * keys.
*/ */
key = x509_request_asymmetric_key(trust_keyring, key = find_asymmetric_key(trust_keyring,
x509->id, x509->skid, x509->id, x509->skid, false);
false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
/* One of the X.509 certificates in the PKCS#7 message /* One of the X.509 certificates in the PKCS#7 message
* is apparently the same as one we already trust. * is apparently the same as one we already trust.
@ -87,10 +83,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
* trusted keys. * trusted keys.
*/ */
if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) { if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
key = x509_request_asymmetric_key(trust_keyring, key = find_asymmetric_key(trust_keyring,
last->sig->auth_ids[0], last->sig->auth_ids[0],
last->sig->auth_ids[1], last->sig->auth_ids[1],
false); false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
x509 = last; x509 = last;
pr_devel("sinfo %u: Root cert %u signer is key %x\n", pr_devel("sinfo %u: Root cert %u signer is key %x\n",
@ -104,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 /* As a last resort, see if we have a trusted public key that matches
* the signed info directly. * the signed info directly.
*/ */
key = x509_request_asymmetric_key(trust_keyring, key = find_asymmetric_key(trust_keyring,
sinfo->sig->auth_ids[0], sinfo->sig->auth_ids[0], NULL, false);
NULL,
false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
pr_devel("sinfo %u: Direct signer is key %x\n", pr_devel("sinfo %u: Direct signer is key %x\n",
sinfo->index, key_serial(key)); sinfo->index, key_serial(key));
@ -122,7 +116,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
matched: matched:
ret = verify_signature(key, sig); ret = verify_signature(key, sig);
trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
key_put(key); key_put(key);
if (ret < 0) { if (ret < 0) {
if (ret == -ENOMEM) if (ret == -ENOMEM)
@ -134,12 +127,9 @@ matched:
verified: verified:
if (x509) { if (x509) {
x509->verified = true; 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->verified = true;
p->trusted = trusted;
}
} }
sinfo->trusted = trusted;
kleave(" = 0"); kleave(" = 0");
return 0; return 0;
} }
@ -148,7 +138,6 @@ verified:
* pkcs7_validate_trust - Validate PKCS#7 trust chain * pkcs7_validate_trust - Validate PKCS#7 trust chain
* @pkcs7: The PKCS#7 certificate to validate * @pkcs7: The PKCS#7 certificate to validate
* @trust_keyring: Signing certificates to use as starting points * @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 * Validate that the certificate chain inside the PKCS#7 message intersects
* keys we already know and trust. * keys we already know and trust.
@ -170,16 +159,13 @@ verified:
* May also return -ENOMEM. * May also return -ENOMEM.
*/ */
int pkcs7_validate_trust(struct pkcs7_message *pkcs7, int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring, struct key *trust_keyring)
bool *_trusted)
{ {
struct pkcs7_signed_info *sinfo; struct pkcs7_signed_info *sinfo;
struct x509_certificate *p; struct x509_certificate *p;
int cached_ret = -ENOKEY; int cached_ret = -ENOKEY;
int ret; int ret;
*_trusted = false;
for (p = pkcs7->certs; p; p = p->next) for (p = pkcs7->certs; p; p = p->next)
p->seen = false; p->seen = false;
@ -193,7 +179,6 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
cached_ret = -ENOPKG; cached_ret = -ENOPKG;
continue; continue;
case 0: case 0:
*_trusted |= sinfo->trusted;
cached_ret = 0; cached_ret = 0;
continue; continue;
default: default:

View File

@ -0,0 +1,108 @@
/* Instantiate a public key crypto key from an X.509 Certificate
*
* Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "ASYM: "fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <crypto/public_key.h>
#include "asymmetric_keys.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
/**
* 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.
*
* 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 restrict_link_by_signature(struct key *trust_keyring,
const struct key_type *type,
const union key_payload *payload)
{
const struct public_key_signature *sig;
struct key *key;
int ret;
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;
/* 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 -ENOKEY;
if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = -ENOKEY;
else
ret = verify_signature(key, sig);
key_put(key);
return ret;
}

View File

@ -16,7 +16,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/pe.h> #include <linux/pe.h>
#include <linux/asn1.h> #include <linux/asn1.h>
#include <crypto/pkcs7.h> #include <linux/verification.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include "verify_pefile.h" #include "verify_pefile.h"
@ -392,9 +392,8 @@ error_no_desc:
* verify_pefile_signature - Verify the signature on a PE binary image * verify_pefile_signature - Verify the signature on a PE binary image
* @pebuf: Buffer containing the PE binary image * @pebuf: Buffer containing the PE binary image
* @pelen: Length of the 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. * @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 * Validate that the certificate chain inside the PKCS#7 message inside the PE
* binary image intersects keys we already know and trust. * binary image intersects keys we already know and trust.
@ -418,14 +417,10 @@ error_no_desc:
* May also return -ENOMEM. * May also return -ENOMEM.
*/ */
int verify_pefile_signature(const void *pebuf, unsigned pelen, int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring, struct key *trusted_keys,
enum key_being_used_for usage, enum key_being_used_for usage)
bool *_trusted)
{ {
struct pkcs7_message *pkcs7;
struct pefile_context ctx; struct pefile_context ctx;
const void *data;
size_t datalen;
int ret; int ret;
kenter(""); kenter("");
@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
if (ret < 0) if (ret < 0)
return ret; return ret;
pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len); ret = verify_pkcs7_signature(NULL, 0,
if (IS_ERR(pkcs7)) pebuf + ctx.sig_offset, ctx.sig_len,
return PTR_ERR(pkcs7); trusted_keys, usage,
ctx.pkcs7 = pkcs7; mscode_parse, &ctx);
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);
if (ret < 0) if (ret < 0)
goto error; goto error;
@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
* contents. * contents.
*/ */
ret = pefile_digest_pe(pebuf, pelen, &ctx); 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: error:
pkcs7_free_message(ctx.pkcs7); kfree(ctx.digest);
return ret; return ret;
} }

View File

@ -9,7 +9,6 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
#include <linux/verify_pefile.h>
#include <crypto/pkcs7.h> #include <crypto/pkcs7.h>
#include <crypto/hash_info.h> #include <crypto/hash_info.h>
@ -23,7 +22,6 @@ struct pefile_context {
unsigned sig_offset; unsigned sig_offset;
unsigned sig_len; unsigned sig_len;
const struct section_header *secs; const struct section_header *secs;
struct pkcs7_message *pkcs7;
/* PKCS#7 MS Individual Code Signing content */ /* PKCS#7 MS Individual Code Signing content */
const void *digest; /* Digest */ const void *digest; /* Digest */
@ -39,4 +37,5 @@ struct pefile_context {
/* /*
* mscode_parser.c * 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);

View File

@ -39,7 +39,6 @@ struct x509_certificate {
unsigned index; unsigned index;
bool seen; /* Infinite recursion prevention */ bool seen; /* Infinite recursion prevention */
bool verified; bool verified;
bool trusted;
bool self_signed; /* T if self-signed (check unsupported_sig too) */ bool self_signed; /* T if self-signed (check unsupported_sig too) */
bool unsupported_key; /* T if key uses unsupported crypto */ bool unsupported_key; /* T if key uses unsupported crypto */
bool unsupported_sig; /* T if signature uses unsupported crypto */ bool unsupported_sig; /* T if signature uses unsupported crypto */

View File

@ -20,133 +20,6 @@
#include "asymmetric_keys.h" #include "asymmetric_keys.h"
#include "x509_parser.h" #include "x509_parser.h"
static bool use_builtin_keys;
static struct asymmetric_key_id *ca_keyid;
#ifndef MODULE
static struct {
struct asymmetric_key_id id;
unsigned char data[10];
} cakey;
static int __init ca_keys_setup(char *str)
{
if (!str) /* default system keyring */
return 1;
if (strncmp(str, "id:", 3) == 0) {
struct asymmetric_key_id *p = &cakey.id;
size_t hexlen = (strlen(str) - 3) / 2;
int ret;
if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
pr_err("Missing or invalid ca_keys id\n");
return 1;
}
ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
if (ret < 0)
pr_err("Unparsable ca_keys id hex string\n");
else
ca_keyid = p; /* owner key 'id:xxxxxx' */
} else if (strcmp(str, "builtin") == 0) {
use_builtin_keys = true;
}
return 1;
}
__setup("ca_keys=", ca_keys_setup);
#endif
/**
* x509_request_asymmetric_key - Request a key by X.509 certificate params.
* @keyring: The keys to search.
* @id: The issuer & serialNumber to look for or NULL.
* @skid: The subjectKeyIdentifier to look for or NULL.
* @partial: Use partial match if true, exact if false.
*
* Find a key in the given keyring by identifier. The preferred identifier is
* the issuer + serialNumber and the fallback identifier is the
* subjectKeyIdentifier. If both are given, the lookup is by the former, but
* the latter must also match.
*/
struct key *x509_request_asymmetric_key(struct key *keyring,
const struct asymmetric_key_id *id,
const struct asymmetric_key_id *skid,
bool partial)
{
struct key *key;
key_ref_t ref;
const char *lookup;
char *req, *p;
int len;
if (id) {
lookup = id->data;
len = id->len;
} else {
lookup = skid->data;
len = skid->len;
}
/* Construct an identifier "id:<keyid>". */
p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
if (!req)
return ERR_PTR(-ENOMEM);
if (partial) {
*p++ = 'i';
*p++ = 'd';
} else {
*p++ = 'e';
*p++ = 'x';
}
*p++ = ':';
p = bin2hex(p, lookup, len);
*p = 0;
pr_debug("Look up: \"%s\"\n", req);
ref = keyring_search(make_key_ref(keyring, 1),
&key_type_asymmetric, req);
if (IS_ERR(ref))
pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
kfree(req);
if (IS_ERR(ref)) {
switch (PTR_ERR(ref)) {
/* Hide some search errors */
case -EACCES:
case -ENOTDIR:
case -EAGAIN:
return ERR_PTR(-ENOKEY);
default:
return ERR_CAST(ref);
}
}
key = key_ref_to_ptr(ref);
if (id && skid) {
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
if (!kids->id[1]) {
pr_debug("issuer+serial match, but expected SKID missing\n");
goto reject;
}
if (!asymmetric_key_id_same(skid, kids->id[1])) {
pr_debug("issuer+serial match, but SKID does not\n");
goto reject;
}
}
pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
return key;
reject:
key_put(key);
return ERR_PTR(-EKEYREJECTED);
}
EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
/* /*
* Set up the signature parameters in an X.509 certificate. This involves * Set up the signature parameters in an X.509 certificate. This involves
* digesting the signed data and extracting the signature. * digesting the signed data and extracting the signature.
@ -276,49 +149,6 @@ not_self_signed:
return 0; return 0;
} }
/*
* Check the new certificate against the ones in the trust keyring. If one of
* those is the signing key and validates the new certificate, then mark the
* new certificate as being trusted.
*
* Return 0 if the new certificate was successfully validated, 1 if we couldn't
* find a matching parent certificate in the trusted list and an error if there
* is a matching certificate but the signature check fails.
*/
static int x509_validate_trust(struct x509_certificate *cert,
struct key *trust_keyring)
{
struct public_key_signature *sig = cert->sig;
struct key *key;
int ret = 1;
if (!sig->auth_ids[0] && !sig->auth_ids[1])
return 1;
if (!trust_keyring)
return -EOPNOTSUPP;
if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
return -EPERM;
if (cert->unsupported_sig)
return -ENOPKG;
key = x509_request_asymmetric_key(trust_keyring,
sig->auth_ids[0], sig->auth_ids[1],
false);
if (IS_ERR(key))
return PTR_ERR(key);
if (!use_builtin_keys ||
test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
ret = public_key_verify_signature(
key->payload.data[asym_crypto], cert->sig);
if (ret == -ENOPKG)
cert->unsupported_sig = true;
}
key_put(key);
return ret;
}
/* /*
* Attempt to parse a data blob for a key as an X509 certificate. * Attempt to parse a data blob for a key as an X509 certificate.
*/ */
@ -348,31 +178,12 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
cert->pub->id_type = "X509"; cert->pub->id_type = "X509";
/* See if we can derive the trustability of this certificate. if (cert->unsupported_sig) {
*
* 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) {
public_key_signature_free(cert->sig); public_key_signature_free(cert->sig);
cert->sig = NULL; cert->sig = NULL;
} else { } else {
pr_devel("Cert Signature: %s + %s\n", pr_devel("Cert Signature: %s + %s\n",
cert->sig->pkey_algo, cert->sig->hash_algo); 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 */ /* Propose a description */

View File

@ -360,7 +360,7 @@ init_cifs_idmap(void)
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ, KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto failed_put_cred; goto failed_put_cred;

View File

@ -201,7 +201,7 @@ int nfs_idmap_init(void)
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ, KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto failed_put_cred; goto failed_put_cred;

View File

@ -12,6 +12,7 @@
#ifndef _CRYPTO_PKCS7_H #ifndef _CRYPTO_PKCS7_H
#define _CRYPTO_PKCS7_H #define _CRYPTO_PKCS7_H
#include <linux/verification.h>
#include <crypto/public_key.h> #include <crypto/public_key.h>
struct key; struct key;
@ -26,14 +27,13 @@ extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
const void **_data, size_t *_datalen, const void **_data, size_t *_datalen,
bool want_wrapper); size_t *_headerlen);
/* /*
* pkcs7_trust.c * pkcs7_trust.c
*/ */
extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring, struct key *trust_keyring);
bool *_trusted);
/* /*
* pkcs7_verify.c * pkcs7_verify.c

View File

@ -14,20 +14,6 @@
#ifndef _LINUX_PUBLIC_KEY_H #ifndef _LINUX_PUBLIC_KEY_H
#define _LINUX_PUBLIC_KEY_H #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. * Cryptographic data for the public-key subtype of the asymmetric key type.
* *
@ -61,15 +47,16 @@ extern void public_key_signature_free(struct public_key_signature *sig);
extern struct asymmetric_key_subtype public_key_subtype; extern struct asymmetric_key_subtype public_key_subtype;
struct key; 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, extern int verify_signature(const struct key *key,
const struct public_key_signature *sig); 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, int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig); const struct public_key_signature *sig);

View File

@ -15,6 +15,7 @@
#define _KEYS_ASYMMETRIC_TYPE_H #define _KEYS_ASYMMETRIC_TYPE_H
#include <linux/key-type.h> #include <linux/key-type.h>
#include <linux/verification.h>
extern struct key_type key_type_asymmetric; extern struct key_type key_type_asymmetric;
@ -75,6 +76,11 @@ const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
return key->payload.data[asym_key_ids]; return key->payload.data[asym_key_ids];
} }
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. * The payload is at the discretion of the subtype.
*/ */

View File

@ -12,51 +12,40 @@
#ifndef _KEYS_SYSTEM_KEYRING_H #ifndef _KEYS_SYSTEM_KEYRING_H
#define _KEYS_SYSTEM_KEYRING_H #define _KEYS_SYSTEM_KEYRING_H
#include <linux/key.h>
#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
#include <linux/key.h> extern int restrict_link_by_builtin_trusted(struct key *keyring,
#include <crypto/public_key.h> const struct key_type *type,
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 #else
static inline struct key *get_system_trusted_keyring(void) #define restrict_link_by_builtin_trusted restrict_link_reject
{
return NULL;
}
#endif #endif
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
extern int system_verify_data(const void *data, unsigned long len, extern int restrict_link_by_builtin_and_secondary_trusted(
const void *raw_pkcs7, size_t pkcs7_len, struct key *keyring,
enum key_being_used_for usage); const struct key_type *type,
const union key_payload *payload);
#else
#define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
#endif #endif
#ifdef CONFIG_IMA_MOK_KEYRING #ifdef CONFIG_IMA_BLACKLIST_KEYRING
extern struct key *ima_mok_keyring;
extern struct key *ima_blacklist_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) static inline struct key *get_ima_blacklist_keyring(void)
{ {
return ima_blacklist_keyring; return ima_blacklist_keyring;
} }
#else #else
static inline struct key *get_ima_mok_keyring(void)
{
return NULL;
}
static inline struct key *get_ima_blacklist_keyring(void) static inline struct key *get_ima_blacklist_keyring(void)
{ {
return NULL; return NULL;
} }
#endif /* CONFIG_IMA_MOK_KEYRING */ #endif /* CONFIG_IMA_BLACKLIST_KEYRING */
#endif /* _KEYS_SYSTEM_KEYRING_H */ #endif /* _KEYS_SYSTEM_KEYRING_H */

View File

@ -45,7 +45,6 @@ struct key_preparsed_payload {
size_t datalen; /* Raw datalen */ size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */ size_t quotalen; /* Quota length for proposed payload */
time_t expiry; /* Expiry time of key */ time_t expiry; /* Expiry time of key */
bool trusted; /* True if key is trusted */
}; };
typedef int (*request_key_actor_t)(struct key_construction *key, typedef int (*request_key_actor_t)(struct key_construction *key,

View File

@ -173,11 +173,9 @@ struct key {
#define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ #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_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_INVALIDATED 7 /* set if key has been invalidated */
#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ #define KEY_FLAG_BUILTIN 8 /* set if key is built in to the kernel */
#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ #define KEY_FLAG_ROOT_CAN_INVAL 9 /* set if key can be invalidated by root without permission */
#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */ #define KEY_FLAG_KEEP 10 /* set if key should not be removed */
#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 */
/* the key type and key description string /* the key type and key description string
* - the desc is used to match a key against search criteria * - the desc is used to match a key against search criteria
@ -205,6 +203,20 @@ struct key {
}; };
int reject_error; 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,
const union key_payload *payload);
}; };
extern struct key *key_alloc(struct key_type *type, extern struct key *key_alloc(struct key_type *type,
@ -212,14 +224,17 @@ extern struct key *key_alloc(struct key_type *type,
kuid_t uid, kgid_t gid, kuid_t uid, kgid_t gid,
const struct cred *cred, const struct cred *cred,
key_perm_t perm, key_perm_t perm,
unsigned long flags); unsigned long flags,
int (*restrict_link)(struct key *,
const struct key_type *,
const union key_payload *));
#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ #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_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ #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 0x0004 /* Key is built into kernel */
#define KEY_ALLOC_BUILT_IN 0x0008 /* 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_revoke(struct key *key);
extern void key_invalidate(struct key *key); extern void key_invalidate(struct key *key);
@ -288,8 +303,15 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid
const struct cred *cred, const struct cred *cred,
key_perm_t perm, key_perm_t perm,
unsigned long flags, unsigned long flags,
int (*restrict_link)(struct key *,
const struct key_type *,
const union key_payload *),
struct key *dest); struct key *dest);
extern int restrict_link_reject(struct key *keyring,
const struct key_type *type,
const union key_payload *payload);
extern int keyring_clear(struct key *keyring); extern int keyring_clear(struct key *keyring);
extern key_ref_t keyring_search(key_ref_t keyring, extern key_ref_t keyring_search(key_ref_t keyring,

View File

@ -0,0 +1,49 @@
/* Signature verification
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_VERIFICATION_H
#define _LINUX_VERIFICATION_H
/*
* The use to which an asymmetric key is being put.
*/
enum key_being_used_for {
VERIFYING_MODULE_SIGNATURE,
VERIFYING_FIRMWARE_SIGNATURE,
VERIFYING_KEXEC_PE_SIGNATURE,
VERIFYING_KEY_SIGNATURE,
VERIFYING_KEY_SELF_SIGNATURE,
VERIFYING_UNSPECIFIED_SIGNATURE,
NR__KEY_BEING_USED_FOR
};
extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
struct key;
extern int verify_pkcs7_signature(const void *data, size_t len,
const void *raw_pkcs7, size_t pkcs7_len,
struct key *trusted_keys,
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 */

View File

@ -1,22 +0,0 @@
/* Signed PE file verification
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_VERIFY_PEFILE_H
#define _LINUX_VERIFY_PEFILE_H
#include <crypto/public_key.h>
extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring,
enum key_being_used_for usage,
bool *_trusted);
#endif /* _LINUX_VERIFY_PEFILE_H */

View File

@ -12,7 +12,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
#include <keys/system_keyring.h> #include <linux/verification.h>
#include <crypto/public_key.h> #include <crypto/public_key.h>
#include "module-internal.h" #include "module-internal.h"
@ -80,6 +80,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
return -EBADMSG; return -EBADMSG;
} }
return system_verify_data(mod, modlen, mod + modlen, sig_len, return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
VERIFYING_MODULE_SIGNATURE); NULL, VERIFYING_MODULE_SIGNATURE,
NULL, NULL);
} }

View File

@ -281,7 +281,7 @@ static int __init init_dns_resolver(void)
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ, KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto failed_put_cred; goto failed_put_cred;

View File

@ -965,7 +965,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
key = key_alloc(&key_type_rxrpc, "x", key = key_alloc(&key_type_rxrpc, "x",
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
KEY_ALLOC_NOT_IN_QUOTA); KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(key)) { if (IS_ERR(key)) {
_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key)); _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
return -ENOMEM; return -ENOMEM;
@ -1012,7 +1012,7 @@ struct key *rxrpc_get_null_key(const char *keyname)
key = key_alloc(&key_type_rxrpc, keyname, key = key_alloc(&key_type_rxrpc, keyname,
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 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)) if (IS_ERR(key))
return key; return key;

View File

@ -18,6 +18,8 @@
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/key-type.h> #include <linux/key-type.h>
#include <linux/digsig.h> #include <linux/digsig.h>
#include <crypto/public_key.h>
#include <keys/system_keyring.h>
#include "integrity.h" #include "integrity.h"
@ -40,6 +42,12 @@ static bool init_keyring __initdata = true;
static bool init_keyring __initdata; static bool init_keyring __initdata;
#endif #endif
#ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
#define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted
#else
#define restrict_link_to_ima restrict_link_by_builtin_trusted
#endif
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen) const char *digest, int digestlen)
{ {
@ -83,10 +91,9 @@ int __init integrity_init_keyring(const unsigned int id)
((KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH), KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA,
if (!IS_ERR(keyring[id])) restrict_link_to_ima, NULL);
set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags); if (IS_ERR(keyring[id])) {
else {
err = PTR_ERR(keyring[id]); err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n", pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err); keyring_name[id], err);

View File

@ -155,23 +155,33 @@ config IMA_TRUSTED_KEYRING
This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING
config IMA_MOK_KEYRING config IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
bool "Create IMA machine owner keys (MOK) and blacklist keyrings" bool "Permit keys validly signed by a built-in or secondary CA cert (EXPERIMENTAL)"
depends on SYSTEM_TRUSTED_KEYRING
depends on SECONDARY_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
select INTEGRITY_TRUSTED_KEYRING
default n
help
Keys may be added to the IMA or IMA blacklist keyrings, if the
key is validly signed by a CA cert in the system built-in or
secondary trusted keyrings.
Intermediate keys between those the kernel has compiled in and the
IMA keys to be added may be added to the system secondary keyring,
provided they are validly signed by a key already resident in the
built-in or secondary trusted keyrings.
config IMA_BLACKLIST_KEYRING
bool "Create IMA machine owner blacklist keyrings (EXPERIMENTAL)"
depends on SYSTEM_TRUSTED_KEYRING depends on SYSTEM_TRUSTED_KEYRING
depends on IMA_TRUSTED_KEYRING depends on IMA_TRUSTED_KEYRING
default n default n
help help
This option creates IMA MOK and blacklist keyrings. IMA MOK is an This option creates an IMA blacklist keyring, which contains all
intermediate keyring that sits between .system and .ima keyrings, revoked IMA keys. It is consulted before any other keyring. If
effectively forming a simple CA hierarchy. To successfully import a the search is successful the requested operation is rejected and
key into .ima_mok it must be signed by a key which CA is in .system an error is returned to the caller.
keyring. On turn any key that needs to go in .ima keyring must be
signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty
at kernel boot.
IMA blacklist keyring contains all revoked IMA keys. It is consulted
before any other keyring. If the search is successful the requested
operation is rejected and error is returned to the caller.
config IMA_LOAD_X509 config IMA_LOAD_X509
bool "Load X509 certificate onto the '.ima' trusted keyring" bool "Load X509 certificate onto the '.ima' trusted keyring"

View File

@ -8,4 +8,4 @@ obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o ima_template.o ima_template_lib.o ima_policy.o ima_template.o ima_template_lib.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
obj-$(CONFIG_IMA_MOK_KEYRING) += ima_mok.o obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o

View File

@ -17,38 +17,29 @@
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <keys/asymmetric-type.h> #include <keys/system_keyring.h>
struct key *ima_mok_keyring;
struct key *ima_blacklist_keyring; struct key *ima_blacklist_keyring;
/* /*
* Allocate the IMA MOK and blacklist keyrings * Allocate the IMA blacklist keyring
*/ */
__init int ima_mok_init(void) __init int ima_mok_init(void)
{ {
pr_notice("Allocating IMA MOK and blacklist keyrings.\n"); pr_notice("Allocating IMA blacklist keyring.\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, NULL);
ima_blacklist_keyring = keyring_alloc(".ima_blacklist", ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
(KEY_POS_ALL & ~KEY_POS_SETATTR) | (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH, KEY_USR_WRITE | KEY_USR_SEARCH,
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA,
restrict_link_by_builtin_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."); panic("Can't allocate IMA blacklist keyring.");
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); set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
return 0; return 0;
} }

View File

@ -201,6 +201,7 @@ serial_exists:
* @cred: The credentials specifying UID namespace. * @cred: The credentials specifying UID namespace.
* @perm: The permissions mask of the new key. * @perm: The permissions mask of the new key.
* @flags: Flags specifying quota properties. * @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 * 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 * returned in an uninstantiated state and the caller needs to instantiate the
@ -223,7 +224,10 @@ serial_exists:
*/ */
struct key *key_alloc(struct key_type *type, const char *desc, struct key *key_alloc(struct key_type *type, const char *desc,
kuid_t uid, kgid_t gid, const struct cred *cred, 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 *,
const union key_payload *))
{ {
struct key_user *user = NULL; struct key_user *user = NULL;
struct key *key; struct key *key;
@ -291,11 +295,10 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->uid = uid; key->uid = uid;
key->gid = gid; key->gid = gid;
key->perm = perm; key->perm = perm;
key->restrict_link = restrict_link;
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
key->flags |= 1 << KEY_FLAG_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) if (flags & KEY_ALLOC_BUILT_IN)
key->flags |= 1 << KEY_FLAG_BUILTIN; key->flags |= 1 << KEY_FLAG_BUILTIN;
@ -496,6 +499,12 @@ int key_instantiate_and_link(struct key *key,
} }
if (keyring) { if (keyring) {
if (keyring->restrict_link) {
ret = keyring->restrict_link(keyring, key->type,
&prep.payload);
if (ret < 0)
goto error;
}
ret = __key_link_begin(keyring, &key->index_key, &edit); ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret < 0) if (ret < 0)
goto error; goto error;
@ -551,8 +560,12 @@ int key_reject_and_link(struct key *key,
awaken = 0; awaken = 0;
ret = -EBUSY; ret = -EBUSY;
if (keyring) if (keyring) {
if (keyring->restrict_link)
return -EPERM;
link_ret = __key_link_begin(keyring, &key->index_key, &edit); link_ret = __key_link_begin(keyring, &key->index_key, &edit);
}
mutex_lock(&key_construction_mutex); mutex_lock(&key_construction_mutex);
@ -793,6 +806,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
struct key *keyring, *key = NULL; struct key *keyring, *key = NULL;
key_ref_t key_ref; key_ref_t key_ref;
int ret; int ret;
int (*restrict_link)(struct key *,
const struct key_type *,
const union key_payload *) = NULL;
/* look up the key type to see if it's one of the registered kernel /* look up the key type to see if it's one of the registered kernel
* types */ * types */
@ -811,6 +827,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_check(keyring); key_check(keyring);
key_ref = ERR_PTR(-EPERM);
if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION))
restrict_link = keyring->restrict_link;
key_ref = ERR_PTR(-ENOTDIR); key_ref = ERR_PTR(-ENOTDIR);
if (keyring->type != &key_type_keyring) if (keyring->type != &key_type_keyring)
goto error_put_type; goto error_put_type;
@ -819,7 +839,6 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
prep.data = payload; prep.data = payload;
prep.datalen = plen; prep.datalen = plen;
prep.quotalen = index_key.type->def_datalen; prep.quotalen = index_key.type->def_datalen;
prep.trusted = flags & KEY_ALLOC_TRUSTED;
prep.expiry = TIME_T_MAX; prep.expiry = TIME_T_MAX;
if (index_key.type->preparse) { if (index_key.type->preparse) {
ret = index_key.type->preparse(&prep); ret = index_key.type->preparse(&prep);
@ -835,10 +854,13 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
} }
index_key.desc_len = strlen(index_key.description); index_key.desc_len = strlen(index_key.description);
key_ref = ERR_PTR(-EPERM); if (restrict_link) {
if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags)) ret = restrict_link(keyring, index_key.type, &prep.payload);
goto error_free_prep; if (ret < 0) {
flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0; key_ref = ERR_PTR(ret);
goto error_free_prep;
}
}
ret = __key_link_begin(keyring, &index_key, &edit); ret = __key_link_begin(keyring, &index_key, &edit);
if (ret < 0) { if (ret < 0) {
@ -879,7 +901,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* allocate a new key */ /* allocate a new key */
key = key_alloc(index_key.type, index_key.description, 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)) { if (IS_ERR(key)) {
key_ref = ERR_CAST(key); key_ref = ERR_CAST(key);
goto error_link_end; goto error_link_end;

View File

@ -491,13 +491,17 @@ static long keyring_read(const struct key *keyring,
*/ */
struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
const struct cred *cred, key_perm_t perm, 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 *,
const union key_payload *),
struct key *dest)
{ {
struct key *keyring; struct key *keyring;
int ret; int ret;
keyring = key_alloc(&key_type_keyring, description, keyring = key_alloc(&key_type_keyring, description,
uid, gid, cred, perm, flags); uid, gid, cred, perm, flags, restrict_link);
if (!IS_ERR(keyring)) { if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
if (ret < 0) { if (ret < 0) {
@ -510,6 +514,26 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
} }
EXPORT_SYMBOL(keyring_alloc); EXPORT_SYMBOL(keyring_alloc);
/**
* restrict_link_reject - Give -EPERM to restrict link
* @keyring: The keyring being added to.
* @type: The type of key being added.
* @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,
const union key_payload *payload)
{
return -EPERM;
}
/* /*
* By default, we keys found by getting an exact match on their descriptions. * By default, we keys found by getting an exact match on their descriptions.
*/ */
@ -1191,6 +1215,16 @@ void __key_link_end(struct key *keyring,
up_write(&keyring->sem); 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->payload);
}
/** /**
* key_link - Link a key to a keyring * key_link - Link a key to a keyring
* @keyring: The keyring to make the link in. * @keyring: The keyring to make the link in.
@ -1221,14 +1255,12 @@ int key_link(struct key *keyring, struct key *key)
key_check(keyring); key_check(keyring);
key_check(key); 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); ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret == 0) { if (ret == 0) {
kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage)); 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) if (ret == 0)
__key_link(key, &edit); __key_link(key, &edit);
__key_link_end(keyring, &key->index_key, edit); __key_link_end(keyring, &key->index_key, edit);

View File

@ -26,7 +26,7 @@ static int key_create_persistent_register(struct user_namespace *ns)
current_cred(), current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ), KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(reg)) if (IS_ERR(reg))
return PTR_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(), uid, INVALID_GID, current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ), KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA, KEY_ALLOC_NOT_IN_QUOTA, NULL,
ns->persistent_keyring_register); ns->persistent_keyring_register);
if (IS_ERR(persistent)) if (IS_ERR(persistent))
return ERR_CAST(persistent); return ERR_CAST(persistent);

View File

@ -76,7 +76,8 @@ int install_user_keyrings(void)
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
cred, user_keyring_perm, cred, user_keyring_perm,
KEY_ALLOC_IN_QUOTA, NULL); KEY_ALLOC_IN_QUOTA,
NULL, NULL);
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
ret = PTR_ERR(uid_keyring); ret = PTR_ERR(uid_keyring);
goto error; goto error;
@ -92,7 +93,8 @@ int install_user_keyrings(void)
session_keyring = session_keyring =
keyring_alloc(buf, user->uid, INVALID_GID, keyring_alloc(buf, user->uid, INVALID_GID,
cred, user_keyring_perm, cred, user_keyring_perm,
KEY_ALLOC_IN_QUOTA, NULL); KEY_ALLOC_IN_QUOTA,
NULL, NULL);
if (IS_ERR(session_keyring)) { if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring); ret = PTR_ERR(session_keyring);
goto error_release; 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, keyring = keyring_alloc("_tid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW, KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN, NULL); KEY_ALLOC_QUOTA_OVERRUN,
NULL, NULL);
if (IS_ERR(keyring)) if (IS_ERR(keyring))
return PTR_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, keyring = keyring_alloc("_pid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW, KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN, NULL); KEY_ALLOC_QUOTA_OVERRUN,
NULL, NULL);
if (IS_ERR(keyring)) if (IS_ERR(keyring))
return PTR_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, keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
flags, NULL); flags, NULL, NULL);
if (IS_ERR(keyring)) if (IS_ERR(keyring))
return PTR_ERR(keyring); return PTR_ERR(keyring);
} else { } else {
@ -785,7 +789,7 @@ long join_session_keyring(const char *name)
keyring = keyring_alloc( keyring = keyring_alloc(
name, old->uid, old->gid, old, name, old->uid, old->gid, old,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, 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)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error2; goto error2;

View File

@ -116,7 +116,7 @@ static int call_sbin_request_key(struct key_construction *cons,
cred = get_current_cred(); cred = get_current_cred();
keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_QUOTA_OVERRUN, NULL); KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL);
put_cred(cred); put_cred(cred);
if (IS_ERR(keyring)) { if (IS_ERR(keyring)) {
ret = PTR_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, key = key_alloc(ctx->index_key.type, ctx->index_key.description,
ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred, ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
perm, flags); perm, flags, NULL);
if (IS_ERR(key)) if (IS_ERR(key))
goto alloc_failed; goto alloc_failed;

View File

@ -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, authkey = key_alloc(&key_type_request_key_auth, desc,
cred->fsuid, cred->fsgid, cred, cred->fsuid, cred->fsgid, cred,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | 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)) { if (IS_ERR(authkey)) {
ret = PTR_ERR(authkey); ret = PTR_ERR(authkey);
goto error_alloc; goto error_alloc;