162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* System trusted keyring for trusted public keys
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/export.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/sched.h>
1162306a36Sopenharmony_ci#include <linux/cred.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/uidgid.h>
1562306a36Sopenharmony_ci#include <linux/verification.h>
1662306a36Sopenharmony_ci#include <keys/asymmetric-type.h>
1762306a36Sopenharmony_ci#include <keys/system_keyring.h>
1862306a36Sopenharmony_ci#include <crypto/pkcs7.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic struct key *builtin_trusted_keys;
2162306a36Sopenharmony_ci#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
2262306a36Sopenharmony_cistatic struct key *secondary_trusted_keys;
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
2562306a36Sopenharmony_cistatic struct key *machine_trusted_keys;
2662306a36Sopenharmony_ci#endif
2762306a36Sopenharmony_ci#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
2862306a36Sopenharmony_cistatic struct key *platform_trusted_keys;
2962306a36Sopenharmony_ci#endif
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciextern __initconst const u8 system_certificate_list[];
3262306a36Sopenharmony_ciextern __initconst const unsigned long system_certificate_list_size;
3362306a36Sopenharmony_ciextern __initconst const unsigned long module_cert_size;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/**
3662306a36Sopenharmony_ci * restrict_link_by_builtin_trusted - Restrict keyring addition by built-in CA
3762306a36Sopenharmony_ci * @dest_keyring: Keyring being linked to.
3862306a36Sopenharmony_ci * @type: The type of key being added.
3962306a36Sopenharmony_ci * @payload: The payload of the new key.
4062306a36Sopenharmony_ci * @restriction_key: A ring of keys that can be used to vouch for the new cert.
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * Restrict the addition of keys into a keyring based on the key-to-be-added
4362306a36Sopenharmony_ci * being vouched for by a key in the built in system keyring.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ciint restrict_link_by_builtin_trusted(struct key *dest_keyring,
4662306a36Sopenharmony_ci				     const struct key_type *type,
4762306a36Sopenharmony_ci				     const union key_payload *payload,
4862306a36Sopenharmony_ci				     struct key *restriction_key)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	return restrict_link_by_signature(dest_keyring, type, payload,
5162306a36Sopenharmony_ci					  builtin_trusted_keys);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/**
5562306a36Sopenharmony_ci * restrict_link_by_digsig_builtin - Restrict digitalSignature key additions by the built-in keyring
5662306a36Sopenharmony_ci * @dest_keyring: Keyring being linked to.
5762306a36Sopenharmony_ci * @type: The type of key being added.
5862306a36Sopenharmony_ci * @payload: The payload of the new key.
5962306a36Sopenharmony_ci * @restriction_key: A ring of keys that can be used to vouch for the new cert.
6062306a36Sopenharmony_ci *
6162306a36Sopenharmony_ci * Restrict the addition of keys into a keyring based on the key-to-be-added
6262306a36Sopenharmony_ci * being vouched for by a key in the built in system keyring. The new key
6362306a36Sopenharmony_ci * must have the digitalSignature usage field set.
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ciint restrict_link_by_digsig_builtin(struct key *dest_keyring,
6662306a36Sopenharmony_ci				    const struct key_type *type,
6762306a36Sopenharmony_ci				    const union key_payload *payload,
6862306a36Sopenharmony_ci				    struct key *restriction_key)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return restrict_link_by_digsig(dest_keyring, type, payload,
7162306a36Sopenharmony_ci				       builtin_trusted_keys);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
7562306a36Sopenharmony_ci/**
7662306a36Sopenharmony_ci * restrict_link_by_builtin_and_secondary_trusted - Restrict keyring
7762306a36Sopenharmony_ci *   addition by both built-in and secondary keyrings.
7862306a36Sopenharmony_ci * @dest_keyring: Keyring being linked to.
7962306a36Sopenharmony_ci * @type: The type of key being added.
8062306a36Sopenharmony_ci * @payload: The payload of the new key.
8162306a36Sopenharmony_ci * @restrict_key: A ring of keys that can be used to vouch for the new cert.
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * Restrict the addition of keys into a keyring based on the key-to-be-added
8462306a36Sopenharmony_ci * being vouched for by a key in either the built-in or the secondary system
8562306a36Sopenharmony_ci * keyrings.
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ciint restrict_link_by_builtin_and_secondary_trusted(
8862306a36Sopenharmony_ci	struct key *dest_keyring,
8962306a36Sopenharmony_ci	const struct key_type *type,
9062306a36Sopenharmony_ci	const union key_payload *payload,
9162306a36Sopenharmony_ci	struct key *restrict_key)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	/* If we have a secondary trusted keyring, then that contains a link
9462306a36Sopenharmony_ci	 * through to the builtin keyring and the search will follow that link.
9562306a36Sopenharmony_ci	 */
9662306a36Sopenharmony_ci	if (type == &key_type_keyring &&
9762306a36Sopenharmony_ci	    dest_keyring == secondary_trusted_keys &&
9862306a36Sopenharmony_ci	    payload == &builtin_trusted_keys->payload)
9962306a36Sopenharmony_ci		/* Allow the builtin keyring to be added to the secondary */
10062306a36Sopenharmony_ci		return 0;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return restrict_link_by_signature(dest_keyring, type, payload,
10362306a36Sopenharmony_ci					  secondary_trusted_keys);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/**
10762306a36Sopenharmony_ci * restrict_link_by_digsig_builtin_and_secondary - Restrict by digitalSignature.
10862306a36Sopenharmony_ci * @dest_keyring: Keyring being linked to.
10962306a36Sopenharmony_ci * @type: The type of key being added.
11062306a36Sopenharmony_ci * @payload: The payload of the new key.
11162306a36Sopenharmony_ci * @restrict_key: A ring of keys that can be used to vouch for the new cert.
11262306a36Sopenharmony_ci *
11362306a36Sopenharmony_ci * Restrict the addition of keys into a keyring based on the key-to-be-added
11462306a36Sopenharmony_ci * being vouched for by a key in either the built-in or the secondary system
11562306a36Sopenharmony_ci * keyrings. The new key must have the digitalSignature usage field set.
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_ciint restrict_link_by_digsig_builtin_and_secondary(struct key *dest_keyring,
11862306a36Sopenharmony_ci						  const struct key_type *type,
11962306a36Sopenharmony_ci						  const union key_payload *payload,
12062306a36Sopenharmony_ci						  struct key *restrict_key)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	/* If we have a secondary trusted keyring, then that contains a link
12362306a36Sopenharmony_ci	 * through to the builtin keyring and the search will follow that link.
12462306a36Sopenharmony_ci	 */
12562306a36Sopenharmony_ci	if (type == &key_type_keyring &&
12662306a36Sopenharmony_ci	    dest_keyring == secondary_trusted_keys &&
12762306a36Sopenharmony_ci	    payload == &builtin_trusted_keys->payload)
12862306a36Sopenharmony_ci		/* Allow the builtin keyring to be added to the secondary */
12962306a36Sopenharmony_ci		return 0;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return restrict_link_by_digsig(dest_keyring, type, payload,
13262306a36Sopenharmony_ci				       secondary_trusted_keys);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/*
13662306a36Sopenharmony_ci * Allocate a struct key_restriction for the "builtin and secondary trust"
13762306a36Sopenharmony_ci * keyring. Only for use in system_trusted_keyring_init().
13862306a36Sopenharmony_ci */
13962306a36Sopenharmony_cistatic __init struct key_restriction *get_builtin_and_secondary_restriction(void)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct key_restriction *restriction;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (!restriction)
14662306a36Sopenharmony_ci		panic("Can't allocate secondary trusted keyring restriction\n");
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING))
14962306a36Sopenharmony_ci		restriction->check = restrict_link_by_builtin_secondary_and_machine;
15062306a36Sopenharmony_ci	else
15162306a36Sopenharmony_ci		restriction->check = restrict_link_by_builtin_and_secondary_trusted;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return restriction;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/**
15762306a36Sopenharmony_ci * add_to_secondary_keyring - Add to secondary keyring.
15862306a36Sopenharmony_ci * @source: Source of key
15962306a36Sopenharmony_ci * @data: The blob holding the key
16062306a36Sopenharmony_ci * @len: The length of the data blob
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci * Add a key to the secondary keyring. The key must be vouched for by a key in the builtin,
16362306a36Sopenharmony_ci * machine or secondary keyring itself.
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_civoid __init add_to_secondary_keyring(const char *source, const void *data, size_t len)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	key_ref_t key;
16862306a36Sopenharmony_ci	key_perm_t perm;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	key = key_create_or_update(make_key_ref(secondary_trusted_keys, 1),
17362306a36Sopenharmony_ci				   "asymmetric",
17462306a36Sopenharmony_ci				   NULL, data, len, perm,
17562306a36Sopenharmony_ci				   KEY_ALLOC_NOT_IN_QUOTA);
17662306a36Sopenharmony_ci	if (IS_ERR(key)) {
17762306a36Sopenharmony_ci		pr_err("Problem loading X.509 certificate from %s to secondary keyring %ld\n",
17862306a36Sopenharmony_ci		       source, PTR_ERR(key));
17962306a36Sopenharmony_ci		return;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	pr_notice("Loaded X.509 cert '%s'\n", key_ref_to_ptr(key)->description);
18362306a36Sopenharmony_ci	key_ref_put(key);
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci#endif
18662306a36Sopenharmony_ci#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
18762306a36Sopenharmony_civoid __init set_machine_trusted_keys(struct key *keyring)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	machine_trusted_keys = keyring;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (key_link(secondary_trusted_keys, machine_trusted_keys) < 0)
19262306a36Sopenharmony_ci		panic("Can't link (machine) trusted keyrings\n");
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/**
19662306a36Sopenharmony_ci * restrict_link_by_builtin_secondary_and_machine - Restrict keyring addition.
19762306a36Sopenharmony_ci * @dest_keyring: Keyring being linked to.
19862306a36Sopenharmony_ci * @type: The type of key being added.
19962306a36Sopenharmony_ci * @payload: The payload of the new key.
20062306a36Sopenharmony_ci * @restrict_key: A ring of keys that can be used to vouch for the new cert.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * Restrict the addition of keys into a keyring based on the key-to-be-added
20362306a36Sopenharmony_ci * being vouched for by a key in either the built-in, the secondary, or
20462306a36Sopenharmony_ci * the machine keyrings.
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_ciint restrict_link_by_builtin_secondary_and_machine(
20762306a36Sopenharmony_ci	struct key *dest_keyring,
20862306a36Sopenharmony_ci	const struct key_type *type,
20962306a36Sopenharmony_ci	const union key_payload *payload,
21062306a36Sopenharmony_ci	struct key *restrict_key)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	if (machine_trusted_keys && type == &key_type_keyring &&
21362306a36Sopenharmony_ci	    dest_keyring == secondary_trusted_keys &&
21462306a36Sopenharmony_ci	    payload == &machine_trusted_keys->payload)
21562306a36Sopenharmony_ci		/* Allow the machine keyring to be added to the secondary */
21662306a36Sopenharmony_ci		return 0;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return restrict_link_by_builtin_and_secondary_trusted(dest_keyring, type,
21962306a36Sopenharmony_ci							      payload, restrict_key);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci#endif
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci/*
22462306a36Sopenharmony_ci * Create the trusted keyrings
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_cistatic __init int system_trusted_keyring_init(void)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	pr_notice("Initialise system trusted keyrings\n");
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	builtin_trusted_keys =
23162306a36Sopenharmony_ci		keyring_alloc(".builtin_trusted_keys",
23262306a36Sopenharmony_ci			      GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
23362306a36Sopenharmony_ci			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
23462306a36Sopenharmony_ci			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
23562306a36Sopenharmony_ci			      KEY_ALLOC_NOT_IN_QUOTA,
23662306a36Sopenharmony_ci			      NULL, NULL);
23762306a36Sopenharmony_ci	if (IS_ERR(builtin_trusted_keys))
23862306a36Sopenharmony_ci		panic("Can't allocate builtin trusted keyring\n");
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
24162306a36Sopenharmony_ci	secondary_trusted_keys =
24262306a36Sopenharmony_ci		keyring_alloc(".secondary_trusted_keys",
24362306a36Sopenharmony_ci			      GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
24462306a36Sopenharmony_ci			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
24562306a36Sopenharmony_ci			       KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH |
24662306a36Sopenharmony_ci			       KEY_USR_WRITE),
24762306a36Sopenharmony_ci			      KEY_ALLOC_NOT_IN_QUOTA,
24862306a36Sopenharmony_ci			      get_builtin_and_secondary_restriction(),
24962306a36Sopenharmony_ci			      NULL);
25062306a36Sopenharmony_ci	if (IS_ERR(secondary_trusted_keys))
25162306a36Sopenharmony_ci		panic("Can't allocate secondary trusted keyring\n");
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0)
25462306a36Sopenharmony_ci		panic("Can't link trusted keyrings\n");
25562306a36Sopenharmony_ci#endif
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/*
26162306a36Sopenharmony_ci * Must be initialised before we try and load the keys into the keyring.
26262306a36Sopenharmony_ci */
26362306a36Sopenharmony_cidevice_initcall(system_trusted_keyring_init);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci__init int load_module_cert(struct key *keyring)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG))
26862306a36Sopenharmony_ci		return 0;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	pr_notice("Loading compiled-in module X.509 certificates\n");
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return x509_load_certificate_list(system_certificate_list,
27362306a36Sopenharmony_ci					  module_cert_size, keyring);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/*
27762306a36Sopenharmony_ci * Load the compiled-in list of X.509 certificates.
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_cistatic __init int load_system_certificate_list(void)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	const u8 *p;
28262306a36Sopenharmony_ci	unsigned long size;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	pr_notice("Loading compiled-in X.509 certificates\n");
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci#ifdef CONFIG_MODULE_SIG
28762306a36Sopenharmony_ci	p = system_certificate_list;
28862306a36Sopenharmony_ci	size = system_certificate_list_size;
28962306a36Sopenharmony_ci#else
29062306a36Sopenharmony_ci	p = system_certificate_list + module_cert_size;
29162306a36Sopenharmony_ci	size = system_certificate_list_size - module_cert_size;
29262306a36Sopenharmony_ci#endif
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return x509_load_certificate_list(p, size, builtin_trusted_keys);
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_cilate_initcall(load_system_certificate_list);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/**
30162306a36Sopenharmony_ci * verify_pkcs7_message_sig - Verify a PKCS#7-based signature on system data.
30262306a36Sopenharmony_ci * @data: The data to be verified (NULL if expecting internal data).
30362306a36Sopenharmony_ci * @len: Size of @data.
30462306a36Sopenharmony_ci * @pkcs7: The PKCS#7 message that is the signature.
30562306a36Sopenharmony_ci * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
30662306a36Sopenharmony_ci *					(void *)1UL for all trusted keys).
30762306a36Sopenharmony_ci * @usage: The use to which the key is being put.
30862306a36Sopenharmony_ci * @view_content: Callback to gain access to content.
30962306a36Sopenharmony_ci * @ctx: Context for callback.
31062306a36Sopenharmony_ci */
31162306a36Sopenharmony_ciint verify_pkcs7_message_sig(const void *data, size_t len,
31262306a36Sopenharmony_ci			     struct pkcs7_message *pkcs7,
31362306a36Sopenharmony_ci			     struct key *trusted_keys,
31462306a36Sopenharmony_ci			     enum key_being_used_for usage,
31562306a36Sopenharmony_ci			     int (*view_content)(void *ctx,
31662306a36Sopenharmony_ci						 const void *data, size_t len,
31762306a36Sopenharmony_ci						 size_t asn1hdrlen),
31862306a36Sopenharmony_ci			     void *ctx)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	int ret;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* The data should be detached - so we need to supply it. */
32362306a36Sopenharmony_ci	if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
32462306a36Sopenharmony_ci		pr_err("PKCS#7 signature with non-detached data\n");
32562306a36Sopenharmony_ci		ret = -EBADMSG;
32662306a36Sopenharmony_ci		goto error;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = pkcs7_verify(pkcs7, usage);
33062306a36Sopenharmony_ci	if (ret < 0)
33162306a36Sopenharmony_ci		goto error;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ret = is_key_on_revocation_list(pkcs7);
33462306a36Sopenharmony_ci	if (ret != -ENOKEY) {
33562306a36Sopenharmony_ci		pr_devel("PKCS#7 key is on revocation list\n");
33662306a36Sopenharmony_ci		goto error;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (!trusted_keys) {
34062306a36Sopenharmony_ci		trusted_keys = builtin_trusted_keys;
34162306a36Sopenharmony_ci	} else if (trusted_keys == VERIFY_USE_SECONDARY_KEYRING) {
34262306a36Sopenharmony_ci#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
34362306a36Sopenharmony_ci		trusted_keys = secondary_trusted_keys;
34462306a36Sopenharmony_ci#else
34562306a36Sopenharmony_ci		trusted_keys = builtin_trusted_keys;
34662306a36Sopenharmony_ci#endif
34762306a36Sopenharmony_ci	} else if (trusted_keys == VERIFY_USE_PLATFORM_KEYRING) {
34862306a36Sopenharmony_ci#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
34962306a36Sopenharmony_ci		trusted_keys = platform_trusted_keys;
35062306a36Sopenharmony_ci#else
35162306a36Sopenharmony_ci		trusted_keys = NULL;
35262306a36Sopenharmony_ci#endif
35362306a36Sopenharmony_ci		if (!trusted_keys) {
35462306a36Sopenharmony_ci			ret = -ENOKEY;
35562306a36Sopenharmony_ci			pr_devel("PKCS#7 platform keyring is not available\n");
35662306a36Sopenharmony_ci			goto error;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
36062306a36Sopenharmony_ci	if (ret < 0) {
36162306a36Sopenharmony_ci		if (ret == -ENOKEY)
36262306a36Sopenharmony_ci			pr_devel("PKCS#7 signature not signed with a trusted key\n");
36362306a36Sopenharmony_ci		goto error;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (view_content) {
36762306a36Sopenharmony_ci		size_t asn1hdrlen;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
37062306a36Sopenharmony_ci		if (ret < 0) {
37162306a36Sopenharmony_ci			if (ret == -ENODATA)
37262306a36Sopenharmony_ci				pr_devel("PKCS#7 message does not contain data\n");
37362306a36Sopenharmony_ci			goto error;
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		ret = view_content(ctx, data, len, asn1hdrlen);
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cierror:
38062306a36Sopenharmony_ci	pr_devel("<==%s() = %d\n", __func__, ret);
38162306a36Sopenharmony_ci	return ret;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/**
38562306a36Sopenharmony_ci * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
38662306a36Sopenharmony_ci * @data: The data to be verified (NULL if expecting internal data).
38762306a36Sopenharmony_ci * @len: Size of @data.
38862306a36Sopenharmony_ci * @raw_pkcs7: The PKCS#7 message that is the signature.
38962306a36Sopenharmony_ci * @pkcs7_len: The size of @raw_pkcs7.
39062306a36Sopenharmony_ci * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
39162306a36Sopenharmony_ci *					(void *)1UL for all trusted keys).
39262306a36Sopenharmony_ci * @usage: The use to which the key is being put.
39362306a36Sopenharmony_ci * @view_content: Callback to gain access to content.
39462306a36Sopenharmony_ci * @ctx: Context for callback.
39562306a36Sopenharmony_ci */
39662306a36Sopenharmony_ciint verify_pkcs7_signature(const void *data, size_t len,
39762306a36Sopenharmony_ci			   const void *raw_pkcs7, size_t pkcs7_len,
39862306a36Sopenharmony_ci			   struct key *trusted_keys,
39962306a36Sopenharmony_ci			   enum key_being_used_for usage,
40062306a36Sopenharmony_ci			   int (*view_content)(void *ctx,
40162306a36Sopenharmony_ci					       const void *data, size_t len,
40262306a36Sopenharmony_ci					       size_t asn1hdrlen),
40362306a36Sopenharmony_ci			   void *ctx)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct pkcs7_message *pkcs7;
40662306a36Sopenharmony_ci	int ret;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
40962306a36Sopenharmony_ci	if (IS_ERR(pkcs7))
41062306a36Sopenharmony_ci		return PTR_ERR(pkcs7);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	ret = verify_pkcs7_message_sig(data, len, pkcs7, trusted_keys, usage,
41362306a36Sopenharmony_ci				       view_content, ctx);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	pkcs7_free_message(pkcs7);
41662306a36Sopenharmony_ci	pr_devel("<==%s() = %d\n", __func__, ret);
41762306a36Sopenharmony_ci	return ret;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(verify_pkcs7_signature);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
42462306a36Sopenharmony_civoid __init set_platform_trusted_keys(struct key *keyring)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	platform_trusted_keys = keyring;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci#endif
429