Skip to content

Commit

Permalink
Merge tag 'keys-next-20160505' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/dhowells/linux-fs into next
  • Loading branch information
James Morris committed May 5, 2016
2 parents 74f430c + d55201c commit 0250abc
Show file tree
Hide file tree
Showing 56 changed files with 1,341 additions and 717 deletions.
52 changes: 52 additions & 0 deletions Documentation/security/keys.txt
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,36 @@ The keyctl syscall functions are:
A process must have search permission on the key for this function to be
successful.

(*) Compute a Diffie-Hellman shared secret or public key

long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
char *buffer, size_t buflen);

The params struct contains serial numbers for three keys:

- The prime, p, known to both parties
- The local private key
- The base integer, which is either a shared generator or the
remote public key

The value computed is:

result = base ^ private (mod prime)

If the base is the shared generator, the result is the local
public key. If the base is the remote public key, the result is
the shared secret.

The buffer length must be at least the length of the prime, or zero.

If the buffer length is nonzero, the length of the result is
returned when it is successfully calculated and copied in to the
buffer. When the buffer length is zero, the minimum required
buffer length is returned.

This function will return error EOPNOTSUPP if the key type is not
supported, error ENOKEY if the key could not be found, or error
EACCES if the key is not readable by the caller.

===============
KERNEL SERVICES
Expand Down Expand Up @@ -999,6 +1029,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);

Expand All @@ -1010,6 +1044,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:

Expand Down
18 changes: 4 additions & 14 deletions arch/x86/kernel/kexec-bzimage64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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

Expand Down
9 changes: 9 additions & 0 deletions certs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -55,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
139 changes: 113 additions & 26 deletions certs/system_keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,88 @@
#include <keys/system_keyring.h>
#include <crypto/pkcs7.h>

struct key *system_trusted_keyring;
EXPORT_SYMBOL_GPL(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;

/**
* 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)
{
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);
if (IS_ERR(system_trusted_keyring))
panic("Can't allocate system trusted keyring\n");
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_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;
}

Expand Down Expand Up @@ -76,16 +135,16 @@ 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,
plen,
((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_BUILT_IN |
KEY_ALLOC_BYPASS_RESTRICTION);
if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
Expand All @@ -108,27 +167,35 @@ 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 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.
*/
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,
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;
int ret;

pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
if (IS_ERR(pkcs7))
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;
Expand All @@ -138,20 +205,40 @@ 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 (ret < 0)
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)
pr_err("PKCS#7 signature not signed with a trusted key\n");
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;
}

if (!trusted) {
pr_err("PKCS#7 signature not signed with a trusted key\n");
ret = -ENOKEY;
ret = view_content(ctx, data, len, asn1hdrlen);
}

error:
pkcs7_free_message(pkcs7);
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 */
6 changes: 3 additions & 3 deletions crypto/asymmetric_keys/Kconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
menuconfig ASYMMETRIC_KEY_TYPE
tristate "Asymmetric (public-key cryptographic) key type"
bool "Asymmetric (public-key cryptographic) key type"
depends on KEYS
help
This option provides support for a key type that holds the data for
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
5 changes: 4 additions & 1 deletion crypto/asymmetric_keys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions crypto/asymmetric_keys/asymmetric_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 0250abc

Please sign in to comment.