Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security subsystem updates from James Morris:
 "Highlights:

   - A new LSM, "LoadPin", from Kees Cook is added, which allows forcing
     of modules and firmware to be loaded from a specific device (this
     is from ChromeOS, where the device as a whole is verified
     cryptographically via dm-verity).

     This is disabled by default but can be configured to be enabled by
     default (don't do this if you don't know what you're doing).

   - Keys: allow authentication data to be stored in an asymmetric key.
     Lots of general fixes and updates.

   - SELinux: add restrictions for loading of kernel modules via
     finit_module().  Distinguish non-init user namespace capability
     checks.  Apply execstack check on thread stacks"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (48 commits)
  LSM: LoadPin: provide enablement CONFIG
  Yama: use atomic allocations when reporting
  seccomp: Fix comment typo
  ima: add support for creating files using the mknodat syscall
  ima: fix ima_inode_post_setattr
  vfs: forbid write access when reading a file into memory
  fs: fix over-zealous use of "const"
  selinux: apply execstack check on thread stacks
  selinux: distinguish non-init user namespace capability checks
  LSM: LoadPin for kernel file loading restrictions
  fs: define a string representation of the kernel_read_file_id enumeration
  Yama: consolidate error reporting
  string_helpers: add kstrdup_quotable_file
  string_helpers: add kstrdup_quotable_cmdline
  string_helpers: add kstrdup_quotable
  selinux: check ss_initialized before revalidating an inode label
  selinux: delay inode label lookup as long as possible
  selinux: don't revalidate an inode's label when explicitly setting it
  selinux: Change bool variable name to index.
  KEYS: Add KEYCTL_DH_COMPUTE command
  ...
This commit is contained in:
Linus Torvalds
2016-05-19 09:21:36 -07:00
82 changed files with 1915 additions and 807 deletions

View File

@@ -0,0 +1,17 @@
LoadPin is a Linux Security Module that ensures all kernel-loaded files
(modules, firmware, etc) all originate from the same filesystem, with
the expectation that such a filesystem is backed by a read-only device
such as dm-verity or CDROM. This allows systems that have a verified
and/or unchangeable filesystem to enforce module and firmware loading
restrictions without needing to sign the files individually.
The LSM is selectable at build-time with CONFIG_SECURITY_LOADPIN, and
can be controlled at boot-time with the kernel command line option
"loadpin.enabled". By default, it is enabled, but can be disabled at
boot ("loadpin.enabled=0").
LoadPin starts pinning when it sees the first file loaded. If the
block device backing the filesystem is not read-only, a sysctl is
created to toggle pinning: /proc/sys/kernel/loadpin/enabled. (Having
a mutable filesystem means pinning is mutable too, but having the
sysctl allows for easy testing on systems with a mutable filesystem.)

View File

@@ -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
@@ -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);
@@ -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:

View File

@@ -10025,6 +10025,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
S: Supported
F: security/apparmor/
LOADPIN SECURITY MODULE
M: Kees Cook <keescook@chromium.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
S: Supported
F: security/loadpin/
YAMA SECURITY MODULE
M: Kees Cook <keescook@chromium.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip

View File

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

View File

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

View File

@@ -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;
}
@@ -76,7 +135,7 @@ static __init int load_system_certificate_list(void)
if (plen > end - p)
goto dodgy_cert;
key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1),
"asymmetric",
NULL,
p,
@@ -84,8 +143,8 @@ static __init int load_system_certificate_list(void)
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA |
KEY_ALLOC_TRUSTED |
KEY_ALLOC_BUILT_IN);
KEY_ALLOC_BUILT_IN |
KEY_ALLOC_BYPASS_RESTRICTION);
if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
@@ -108,19 +167,27 @@ 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);
@@ -128,7 +195,7 @@ int system_verify_data(const void *data, unsigned long len,
return PTR_ERR(pkcs7);
/* The data should be detached - so we need to supply it. */
if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
pr_err("PKCS#7 signature with non-detached data\n");
ret = -EBADMSG;
goto error;
@@ -138,13 +205,33 @@ 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 (!trusted) {
pr_err("PKCS#7 signature not signed with a trusted key\n");
ret = -ENOKEY;
if (view_content) {
size_t asn1hdrlen;
ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
if (ret < 0) {
if (ret == -ENODATA)
pr_devel("PKCS#7 message does not contain data\n");
goto error;
}
ret = view_content(ctx, data, len, asn1hdrlen);
}
error:
@@ -152,6 +239,6 @@ error:
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
EXPORT_SYMBOL_GPL(system_verify_data);
EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */

View File

@@ -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
@@ -40,8 +40,7 @@ config PKCS7_MESSAGE_PARSER
config PKCS7_TEST_KEY
tristate "PKCS#7 testing key type"
depends on PKCS7_MESSAGE_PARSER
select SYSTEM_TRUSTED_KEYRING
depends on SYSTEM_DATA_VERIFICATION
help
This option provides a type of key that can be loaded up from a
PKCS#7 message - provided the message is signed by a trusted key. If
@@ -54,6 +53,7 @@ config PKCS7_TEST_KEY
config SIGNED_PE_FILE_VERIFICATION
bool "Support for PE file signature verification"
depends on PKCS7_MESSAGE_PARSER=y
depends on SYSTEM_DATA_VERIFICATION
select ASN1
select OID_REGISTRY
help

View File

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

View File

@@ -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,

View File

@@ -34,6 +34,95 @@ EXPORT_SYMBOL_GPL(key_being_used_for);
static LIST_HEAD(asymmetric_key_parsers);
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
* @val_1: First binary blob
@@ -331,7 +420,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
pr_devel("==>%s()\n", __func__);
if (subtype) {
subtype->destroy(prep->payload.data[asym_crypto]);
subtype->destroy(prep->payload.data[asym_crypto],
prep->payload.data[asym_auth]);
module_put(subtype->owner);
}
asymmetric_key_free_kids(kids);
@@ -346,13 +436,15 @@ static void asymmetric_key_destroy(struct key *key)
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
void *data = key->payload.data[asym_crypto];
void *auth = key->payload.data[asym_auth];
key->payload.data[asym_crypto] = NULL;
key->payload.data[asym_subtype] = NULL;
key->payload.data[asym_key_ids] = NULL;
key->payload.data[asym_auth] = NULL;
if (subtype) {
subtype->destroy(data);
subtype->destroy(data, auth);
module_put(subtype->owner);
}

View File

@@ -21,19 +21,13 @@
/*
* Parse a Microsoft Individual Code Signing blob
*/
int mscode_parse(struct pefile_context *ctx)
int mscode_parse(void *_ctx, const void *content_data, size_t data_len,
size_t asn1hdrlen)
{
const void *content_data;
size_t data_len;
int ret;
ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
if (ret) {
pr_debug("PKCS#7 message does not contain data\n");
return ret;
}
struct pefile_context *ctx = _ctx;
content_data -= asn1hdrlen;
data_len += asn1hdrlen;
pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
content_data);
@@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen,
{
struct pefile_context *ctx = context;
ctx->digest = value;
ctx->digest_len = vlen;
return 0;
ctx->digest = kmemdup(value, vlen, GFP_KERNEL);
return ctx->digest ? 0 : -ENOMEM;
}

View File

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

View File

@@ -44,9 +44,7 @@ struct pkcs7_parse_context {
static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
{
if (sinfo) {
kfree(sinfo->sig.s);
kfree(sinfo->sig.digest);
kfree(sinfo->signing_cert_id);
public_key_signature_free(sinfo->sig);
kfree(sinfo);
}
}
@@ -125,6 +123,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
if (!ctx->sinfo)
goto out_no_sinfo;
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
GFP_KERNEL);
if (!ctx->sinfo->sig)
goto out_no_sig;
ctx->data = (unsigned long)data;
ctx->ppcerts = &ctx->certs;
@@ -150,6 +152,7 @@ out:
ctx->certs = cert->next;
x509_free_certificate(cert);
}
out_no_sig:
pkcs7_free_signed_info(ctx->sinfo);
out_no_sinfo:
pkcs7_free_message(ctx->msg);
@@ -165,24 +168,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message);
* @pkcs7: The preparsed PKCS#7 message to access
* @_data: Place to return a pointer to the data
* @_data_len: Place to return the data length
* @want_wrapper: True if the ASN.1 object header should be included in the data
* @_headerlen: Size of ASN.1 header not included in _data
*
* Get access to the data content of the PKCS#7 message, including, optionally,
* the header of the ASN.1 object that contains it. Returns -ENODATA if the
* data object was missing from the message.
* Get access to the data content of the PKCS#7 message. The size of the
* header of the ASN.1 object that contains it is also provided and can be used
* to adjust *_data and *_data_len to get the entire object.
*
* Returns -ENODATA if the data object was missing from the message.
*/
int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
const void **_data, size_t *_data_len,
bool want_wrapper)
size_t *_headerlen)
{
size_t wrapper;
if (!pkcs7->data)
return -ENODATA;
wrapper = want_wrapper ? pkcs7->data_hdrlen : 0;
*_data = pkcs7->data - wrapper;
*_data_len = pkcs7->data_len + wrapper;
*_data = pkcs7->data;
*_data_len = pkcs7->data_len;
if (_headerlen)
*_headerlen = pkcs7->data_hdrlen;
return 0;
}
EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
@@ -218,25 +222,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) {
case OID_md4:
ctx->sinfo->sig.hash_algo = "md4";
ctx->sinfo->sig->hash_algo = "md4";
break;
case OID_md5:
ctx->sinfo->sig.hash_algo = "md5";
ctx->sinfo->sig->hash_algo = "md5";
break;
case OID_sha1:
ctx->sinfo->sig.hash_algo = "sha1";
ctx->sinfo->sig->hash_algo = "sha1";
break;
case OID_sha256:
ctx->sinfo->sig.hash_algo = "sha256";
ctx->sinfo->sig->hash_algo = "sha256";
break;
case OID_sha384:
ctx->sinfo->sig.hash_algo = "sha384";
ctx->sinfo->sig->hash_algo = "sha384";
break;
case OID_sha512:
ctx->sinfo->sig.hash_algo = "sha512";
ctx->sinfo->sig->hash_algo = "sha512";
break;
case OID_sha224:
ctx->sinfo->sig.hash_algo = "sha224";
ctx->sinfo->sig->hash_algo = "sha224";
break;
default:
printk("Unsupported digest algo: %u\n", ctx->last_oid);
@@ -256,7 +260,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) {
case OID_rsaEncryption:
ctx->sinfo->sig.pkey_algo = "rsa";
ctx->sinfo->sig->pkey_algo = "rsa";
break;
default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
@@ -616,11 +620,11 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen,
{
struct pkcs7_parse_context *ctx = context;
ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL);
if (!ctx->sinfo->sig.s)
ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);
if (!ctx->sinfo->sig->s)
return -ENOMEM;
ctx->sinfo->sig.s_size = vlen;
ctx->sinfo->sig->s_size = vlen;
return 0;
}
@@ -656,12 +660,16 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
sinfo->signing_cert_id = kid;
sinfo->sig->auth_ids[0] = kid;
sinfo->index = ++ctx->sinfo_index;
*ctx->ppsinfo = sinfo;
ctx->ppsinfo = &sinfo->next;
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
if (!ctx->sinfo)
return -ENOMEM;
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
GFP_KERNEL);
if (!ctx->sinfo->sig)
return -ENOMEM;
return 0;
}

View File

@@ -22,7 +22,6 @@ struct pkcs7_signed_info {
struct pkcs7_signed_info *next;
struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
unsigned index;
bool trusted;
bool unsupported_crypto; /* T if not usable due to missing crypto */
/* Message digest - the digest of the Content Data (or NULL) */
@@ -41,19 +40,17 @@ struct pkcs7_signed_info {
#define sinfo_has_ms_statement_type 5
time64_t signing_time;
/* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
* or issuing cert's SKID [CMS ver 3].
*/
struct asymmetric_key_id *signing_cert_id;
/* Message signature.
*
* This contains the generated digest of _either_ the Content Data or
* the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
* the attributes contains the digest of the the Content Data within
* it.
*
* THis also contains the issuing cert serial number and issuer's name
* [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3].
*/
struct public_key_signature sig;
struct public_key_signature *sig;
};
struct pkcs7_message {

View File

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

View File

@@ -25,34 +25,36 @@
static int pkcs7_digest(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct public_key_signature *sig = sinfo->sig;
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
void *digest;
size_t desc_size;
int ret;
kenter(",%u,%s", sinfo->index, sinfo->sig.hash_algo);
kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
if (!sinfo->sig.hash_algo)
if (!sinfo->sig->hash_algo)
return -ENOPKG;
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(sinfo->sig.hash_algo, 0, 0);
tfm = crypto_alloc_shash(sinfo->sig->hash_algo, 0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
sig->digest_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
GFP_KERNEL);
if (!digest)
sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
if (!sig->digest)
goto error_no_desc;
desc = kzalloc(desc_size, GFP_KERNEL);
if (!desc)
goto error_no_desc;
desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
@@ -60,10 +62,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len,
sig->digest);
if (ret < 0)
goto error;
pr_devel("MsgDigest = [%*ph]\n", 8, digest);
pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
@@ -78,14 +81,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
goto error;
}
if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
if (sinfo->msgdigest_len != sig->digest_size) {
pr_debug("Sig %u: Invalid digest size (%u)\n",
sinfo->index, sinfo->msgdigest_len);
ret = -EBADMSG;
goto error;
}
if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
if (memcmp(sig->digest, sinfo->msgdigest,
sinfo->msgdigest_len) != 0) {
pr_debug("Sig %u: Message digest doesn't match\n",
sinfo->index);
ret = -EKEYREJECTED;
@@ -97,7 +101,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
* convert the attributes from a CONT.0 into a SET before we
* hash it.
*/
memset(digest, 0, sinfo->sig.digest_size);
memset(sig->digest, 0, sig->digest_size);
ret = crypto_shash_init(desc);
if (ret < 0)
@@ -107,17 +111,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, sinfo->authattrs,
sinfo->authattrs_len, digest);
sinfo->authattrs_len, sig->digest);
if (ret < 0)
goto error;
pr_devel("AADigest = [%*ph]\n", 8, digest);
pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
}
sinfo->sig.digest = digest;
digest = NULL;
error:
kfree(digest);
kfree(desc);
error_no_desc:
crypto_free_shash(tfm);
kleave(" = %d", ret);
@@ -144,12 +145,12 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
* PKCS#7 message - but I can't be 100% sure of that. It's
* possible this will need element-by-element comparison.
*/
if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0]))
continue;
pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
sinfo->index, certix);
if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) {
pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
sinfo->index);
continue;
@@ -164,7 +165,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
*/
pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
sinfo->index,
sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data);
return 0;
}
@@ -174,6 +175,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct public_key_signature *sig;
struct x509_certificate *x509 = sinfo->signer, *p;
struct asymmetric_key_id *auth;
int ret;
@@ -188,34 +190,26 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
x509->subject,
x509->raw_serial_size, x509->raw_serial);
x509->seen = true;
ret = x509_get_sig_params(x509);
if (ret < 0)
goto maybe_missing_crypto_in_x509;
if (x509->unsupported_key)
goto unsupported_crypto_in_x509;
pr_debug("- issuer %s\n", x509->issuer);
if (x509->akid_id)
sig = x509->sig;
if (sig->auth_ids[0])
pr_debug("- authkeyid.id %*phN\n",
x509->akid_id->len, x509->akid_id->data);
if (x509->akid_skid)
sig->auth_ids[0]->len, sig->auth_ids[0]->data);
if (sig->auth_ids[1])
pr_debug("- authkeyid.skid %*phN\n",
x509->akid_skid->len, x509->akid_skid->data);
sig->auth_ids[1]->len, sig->auth_ids[1]->data);
if ((!x509->akid_id && !x509->akid_skid) ||
strcmp(x509->subject, x509->issuer) == 0) {
if (x509->self_signed) {
/* If there's no authority certificate specified, then
* the certificate must be self-signed and is the root
* of the chain. Likewise if the cert is its own
* authority.
*/
pr_debug("- no auth?\n");
if (x509->raw_subject_size != x509->raw_issuer_size ||
memcmp(x509->raw_subject, x509->raw_issuer,
x509->raw_issuer_size) != 0)
return 0;
ret = x509_check_signature(x509->pub, x509);
if (ret < 0)
goto maybe_missing_crypto_in_x509;
if (x509->unsupported_sig)
goto unsupported_crypto_in_x509;
x509->signer = x509;
pr_debug("- self-signed\n");
return 0;
@@ -224,7 +218,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
/* Look through the X.509 certificates in the PKCS#7 message's
* list to see if the next one is there.
*/
auth = x509->akid_id;
auth = sig->auth_ids[0];
if (auth) {
pr_debug("- want %*phN\n", auth->len, auth->data);
for (p = pkcs7->certs; p; p = p->next) {
@@ -234,7 +228,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
goto found_issuer_check_skid;
}
} else {
auth = x509->akid_skid;
auth = sig->auth_ids[1];
pr_debug("- want %*phN\n", auth->len, auth->data);
for (p = pkcs7->certs; p; p = p->next) {
if (!p->skid)
@@ -254,8 +248,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
/* We matched issuer + serialNumber, but if there's an
* authKeyId.keyId, that must match the CA subjKeyId also.
*/
if (x509->akid_skid &&
!asymmetric_key_id_same(p->skid, x509->akid_skid)) {
if (sig->auth_ids[1] &&
!asymmetric_key_id_same(p->skid, sig->auth_ids[1])) {
pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
sinfo->index, x509->index, p->index);
return -EKEYREJECTED;
@@ -267,7 +261,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
sinfo->index);
return 0;
}
ret = x509_check_signature(p->pub, x509);
ret = public_key_verify_signature(p->pub, p->sig);
if (ret < 0)
return ret;
x509->signer = p;
@@ -279,16 +273,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
might_sleep();
}
maybe_missing_crypto_in_x509:
unsupported_crypto_in_x509:
/* Just prune the certificate chain at this point if we lack some
* crypto module to go further. Note, however, we don't want to set
* sinfo->missing_crypto as the signed info block may still be
* sinfo->unsupported_crypto as the signed info block may still be
* validatable against an X.509 cert lower in the chain that we have a
* trusted copy of.
*/
if (ret == -ENOPKG)
return 0;
return ret;
return 0;
}
/*
@@ -332,7 +324,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
}
/* Verify the PKCS#7 binary against the key */
ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
ret = public_key_verify_signature(sinfo->signer->pub, sinfo->sig);
if (ret < 0)
return ret;
@@ -375,9 +367,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
enum key_being_used_for usage)
{
struct pkcs7_signed_info *sinfo;
struct x509_certificate *x509;
int enopkg = -ENOPKG;
int ret, n;
int ret;
kenter("");
@@ -419,12 +410,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
return -EINVAL;
}
for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
ret = x509_get_sig_params(x509);
if (ret < 0)
return ret;
}
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_verify_one(pkcs7, sinfo);
if (ret < 0) {

View File

@@ -39,15 +39,23 @@ static void public_key_describe(const struct key *asymmetric_key,
/*
* Destroy a public key algorithm key.
*/
void public_key_destroy(void *payload)
void public_key_free(struct public_key *key)
{
struct public_key *key = payload;
if (key)
if (key) {
kfree(key->key);
kfree(key);
kfree(key);
}
}
EXPORT_SYMBOL_GPL(public_key_free);
/*
* Destroy a public key algorithm key.
*/
static void public_key_destroy(void *payload0, void *payload3)
{
public_key_free(payload0);
public_key_signature_free(payload3);
}
EXPORT_SYMBOL_GPL(public_key_destroy);
struct public_key_completion {
struct completion completion;

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

@@ -15,9 +15,27 @@
#include <keys/asymmetric-subtype.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <crypto/public_key.h>
#include "asymmetric_keys.h"
/*
* Destroy a public key signature.
*/
void public_key_signature_free(struct public_key_signature *sig)
{
int i;
if (sig) {
for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
kfree(sig->auth_ids[i]);
kfree(sig->s);
kfree(sig->digest);
kfree(sig);
}
}
EXPORT_SYMBOL_GPL(public_key_signature_free);
/**
* verify_signature - Initiate the use of an asymmetric key to verify a signature
* @key: The asymmetric key to verify against

View File

@@ -16,7 +16,7 @@
#include <linux/err.h>
#include <linux/pe.h>
#include <linux/asn1.h>
#include <crypto/pkcs7.h>
#include <linux/verification.h>
#include <crypto/hash.h>
#include "verify_pefile.h"
@@ -392,9 +392,8 @@ error_no_desc:
* verify_pefile_signature - Verify the signature on a PE binary image
* @pebuf: Buffer containing the PE binary image
* @pelen: Length of the binary image
* @trust_keyring: Signing certificates to use as starting points
* @trust_keys: Signing certificate(s) to use as starting points
* @usage: The use to which the key is being put.
* @_trusted: Set to true if trustworth, false otherwise
*
* Validate that the certificate chain inside the PKCS#7 message inside the PE
* binary image intersects keys we already know and trust.
@@ -418,14 +417,10 @@ error_no_desc:
* May also return -ENOMEM.
*/
int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring,
enum key_being_used_for usage,
bool *_trusted)
struct key *trusted_keys,
enum key_being_used_for usage)
{
struct pkcs7_message *pkcs7;
struct pefile_context ctx;
const void *data;
size_t datalen;
int ret;
kenter("");
@@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
if (ret < 0)
return ret;
pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
if (IS_ERR(pkcs7))
return PTR_ERR(pkcs7);
ctx.pkcs7 = pkcs7;
ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false);
if (ret < 0 || datalen == 0) {
pr_devel("PKCS#7 message does not contain data\n");
ret = -EBADMSG;
goto error;
}
ret = mscode_parse(&ctx);
ret = verify_pkcs7_signature(NULL, 0,
pebuf + ctx.sig_offset, ctx.sig_len,
trusted_keys, usage,
mscode_parse, &ctx);
if (ret < 0)
goto error;
@@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
* contents.
*/
ret = pefile_digest_pe(pebuf, pelen, &ctx);
if (ret < 0)
goto error;
ret = pkcs7_verify(pkcs7, usage);
if (ret < 0)
goto error;
ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted);
error:
pkcs7_free_message(ctx.pkcs7);
kfree(ctx.digest);
return ret;
}

Some files were not shown because too many files have changed in this diff Show More