Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e68503bd authored by David Howells's avatar David Howells
Browse files

KEYS: Generalise system_verify_data() to provide access to internal content



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

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

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

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent ad3043fd
Loading
Loading
Loading
Loading
+4 −14
Original line number Diff line number Diff line
@@ -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

+35 −10
Original line number Diff line number Diff line
@@ -108,16 +108,25 @@ late_initcall(load_system_certificate_list);
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION

/**
 * Verify a PKCS#7-based signature on system data.
 * @data: The data to be verified.
 * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
 * @data: The data to be verified (NULL if expecting internal data).
 * @len: Size of @data.
 * @raw_pkcs7: The PKCS#7 message that is the signature.
 * @pkcs7_len: The size of @raw_pkcs7.
 * @trusted_keys: Trusted keys to use (NULL for system_trusted_keyring).
 * @usage: The use to which the key is being put.
 * @view_content: Callback to gain access to content.
 * @ctx: Context for callback.
 */
int system_verify_data(const void *data, unsigned long len,
int verify_pkcs7_signature(const void *data, size_t len,
			   const void *raw_pkcs7, size_t pkcs7_len,
		       enum key_being_used_for usage)
			   struct key *trusted_keys,
			   int untrusted_error,
			   enum key_being_used_for usage,
			   int (*view_content)(void *ctx,
					       const void *data, size_t len,
					       size_t asn1hdrlen),
			   void *ctx)
{
	struct pkcs7_message *pkcs7;
	bool trusted;
@@ -128,7 +137,7 @@ int system_verify_data(const void *data, unsigned long len,
		return PTR_ERR(pkcs7);

	/* The data should be detached - so we need to supply it. */
	if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
	if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
		pr_err("PKCS#7 signature with non-detached data\n");
		ret = -EBADMSG;
		goto error;
@@ -138,13 +147,29 @@ int system_verify_data(const void *data, unsigned long len,
	if (ret < 0)
		goto error;

	ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
	if (!trusted_keys)
		trusted_keys = system_trusted_keyring;
	ret = pkcs7_validate_trust(pkcs7, trusted_keys, &trusted);
	if (ret < 0)
		goto error;

	if (!trusted) {
	if (!trusted && untrusted_error) {
		pr_err("PKCS#7 signature not signed with a trusted key\n");
		ret = -ENOKEY;
		ret = untrusted_error;
		goto error;
	}

	if (view_content) {
		size_t asn1hdrlen;

		ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
		if (ret < 0) {
			if (ret == -ENODATA)
				pr_devel("PKCS#7 message does not contain data\n");
			goto error;
		}

		ret = view_content(ctx, data, len, asn1hdrlen);
	}

error:
@@ -152,6 +177,6 @@ int system_verify_data(const void *data, unsigned long len,
	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 */
+2 −2
Original line number Diff line number Diff line
@@ -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
+7 −14
Original line number Diff line number Diff line
@@ -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;
}
+28 −44
Original line number Diff line number Diff line
@@ -13,12 +13,9 @@
#include <linux/key.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/verification.h>
#include <linux/key-type.h>
#include <keys/asymmetric-type.h>
#include <crypto/pkcs7.h>
#include <keys/user-type.h>
#include <keys/system_keyring.h>
#include "pkcs7_parser.h"

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PKCS#7 testing key type");
@@ -29,59 +26,46 @@ MODULE_PARM_DESC(pkcs7_usage,
		 "Usage to specify when verifying the PKCS#7 message");

/*
 * Preparse a PKCS#7 wrapped and validated data blob.
 * Retrieve the PKCS#7 message content.
 */
static int pkcs7_preparse(struct key_preparsed_payload *prep)
static int pkcs7_view_content(void *ctx, const void *data, size_t len,
			      size_t asn1hdrlen)
{
	enum key_being_used_for usage = pkcs7_usage;
	struct pkcs7_message *pkcs7;
	const void *data, *saved_prep_data;
	size_t datalen, saved_prep_datalen;
	bool trusted;
	struct key_preparsed_payload *prep = ctx;
	const void *saved_prep_data;
	size_t saved_prep_datalen;
	int ret;

	kenter("");

	if (usage >= NR__KEY_BEING_USED_FOR) {
		pr_err("Invalid usage type %d\n", usage);
		return -EINVAL;
	}

	saved_prep_data = prep->data;
	saved_prep_datalen = prep->datalen;
	pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
	if (IS_ERR(pkcs7)) {
		ret = PTR_ERR(pkcs7);
		goto error;
	}

	ret = pkcs7_verify(pkcs7, usage);
	if (ret < 0)
		goto error_free;

	ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
	if (ret < 0)
		goto error_free;
	if (!trusted)
		pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");

	ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
	if (ret < 0)
		goto error_free;

	prep->data = data;
	prep->datalen = datalen;
	prep->datalen = len;

	ret = user_preparse(prep);

	prep->data = saved_prep_data;
	prep->datalen = saved_prep_datalen;

error_free:
	pkcs7_free_message(pkcs7);
error:
	kleave(" = %d", ret);
	return ret;
}

/*
 * Preparse a PKCS#7 wrapped and validated data blob.
 */
static int pkcs7_preparse(struct key_preparsed_payload *prep)
{
	enum key_being_used_for usage = pkcs7_usage;

	if (usage >= NR__KEY_BEING_USED_FOR) {
		pr_err("Invalid usage type %d\n", usage);
		return -EINVAL;
	}

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

/*
 * user defined keys take an arbitrary string as the description and an
 * arbitrary blob of data as the payload
Loading