162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* Parse a signed PE binary
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) "PEFILE: "fmt
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/pe.h>
1462306a36Sopenharmony_ci#include <linux/asn1.h>
1562306a36Sopenharmony_ci#include <linux/verification.h>
1662306a36Sopenharmony_ci#include <crypto/hash.h>
1762306a36Sopenharmony_ci#include "verify_pefile.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Parse a PE binary.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_cistatic int pefile_parse_binary(const void *pebuf, unsigned int pelen,
2362306a36Sopenharmony_ci			       struct pefile_context *ctx)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	const struct mz_hdr *mz = pebuf;
2662306a36Sopenharmony_ci	const struct pe_hdr *pe;
2762306a36Sopenharmony_ci	const struct pe32_opt_hdr *pe32;
2862306a36Sopenharmony_ci	const struct pe32plus_opt_hdr *pe64;
2962306a36Sopenharmony_ci	const struct data_directory *ddir;
3062306a36Sopenharmony_ci	const struct data_dirent *dde;
3162306a36Sopenharmony_ci	const struct section_header *secs, *sec;
3262306a36Sopenharmony_ci	size_t cursor, datalen = pelen;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	kenter("");
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define chkaddr(base, x, s)						\
3762306a36Sopenharmony_ci	do {								\
3862306a36Sopenharmony_ci		if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
3962306a36Sopenharmony_ci			return -ELIBBAD;				\
4062306a36Sopenharmony_ci	} while (0)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	chkaddr(0, 0, sizeof(*mz));
4362306a36Sopenharmony_ci	if (mz->magic != MZ_MAGIC)
4462306a36Sopenharmony_ci		return -ELIBBAD;
4562306a36Sopenharmony_ci	cursor = sizeof(*mz);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	chkaddr(cursor, mz->peaddr, sizeof(*pe));
4862306a36Sopenharmony_ci	pe = pebuf + mz->peaddr;
4962306a36Sopenharmony_ci	if (pe->magic != PE_MAGIC)
5062306a36Sopenharmony_ci		return -ELIBBAD;
5162306a36Sopenharmony_ci	cursor = mz->peaddr + sizeof(*pe);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	chkaddr(0, cursor, sizeof(pe32->magic));
5462306a36Sopenharmony_ci	pe32 = pebuf + cursor;
5562306a36Sopenharmony_ci	pe64 = pebuf + cursor;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	switch (pe32->magic) {
5862306a36Sopenharmony_ci	case PE_OPT_MAGIC_PE32:
5962306a36Sopenharmony_ci		chkaddr(0, cursor, sizeof(*pe32));
6062306a36Sopenharmony_ci		ctx->image_checksum_offset =
6162306a36Sopenharmony_ci			(unsigned long)&pe32->csum - (unsigned long)pebuf;
6262306a36Sopenharmony_ci		ctx->header_size = pe32->header_size;
6362306a36Sopenharmony_ci		cursor += sizeof(*pe32);
6462306a36Sopenharmony_ci		ctx->n_data_dirents = pe32->data_dirs;
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	case PE_OPT_MAGIC_PE32PLUS:
6862306a36Sopenharmony_ci		chkaddr(0, cursor, sizeof(*pe64));
6962306a36Sopenharmony_ci		ctx->image_checksum_offset =
7062306a36Sopenharmony_ci			(unsigned long)&pe64->csum - (unsigned long)pebuf;
7162306a36Sopenharmony_ci		ctx->header_size = pe64->header_size;
7262306a36Sopenharmony_ci		cursor += sizeof(*pe64);
7362306a36Sopenharmony_ci		ctx->n_data_dirents = pe64->data_dirs;
7462306a36Sopenharmony_ci		break;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	default:
7762306a36Sopenharmony_ci		pr_warn("Unknown PEOPT magic = %04hx\n", pe32->magic);
7862306a36Sopenharmony_ci		return -ELIBBAD;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
8262306a36Sopenharmony_ci	pr_debug("header size = %x\n", ctx->header_size);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (cursor >= ctx->header_size || ctx->header_size >= datalen)
8562306a36Sopenharmony_ci		return -ELIBBAD;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
8862306a36Sopenharmony_ci		return -ELIBBAD;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	ddir = pebuf + cursor;
9162306a36Sopenharmony_ci	cursor += sizeof(*dde) * ctx->n_data_dirents;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	ctx->cert_dirent_offset =
9462306a36Sopenharmony_ci		(unsigned long)&ddir->certs - (unsigned long)pebuf;
9562306a36Sopenharmony_ci	ctx->certs_size = ddir->certs.size;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (!ddir->certs.virtual_address || !ddir->certs.size) {
9862306a36Sopenharmony_ci		pr_warn("Unsigned PE binary\n");
9962306a36Sopenharmony_ci		return -ENODATA;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	chkaddr(ctx->header_size, ddir->certs.virtual_address,
10362306a36Sopenharmony_ci		ddir->certs.size);
10462306a36Sopenharmony_ci	ctx->sig_offset = ddir->certs.virtual_address;
10562306a36Sopenharmony_ci	ctx->sig_len = ddir->certs.size;
10662306a36Sopenharmony_ci	pr_debug("cert = %x @%x [%*ph]\n",
10762306a36Sopenharmony_ci		 ctx->sig_len, ctx->sig_offset,
10862306a36Sopenharmony_ci		 ctx->sig_len, pebuf + ctx->sig_offset);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ctx->n_sections = pe->sections;
11162306a36Sopenharmony_ci	if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
11262306a36Sopenharmony_ci		return -ELIBBAD;
11362306a36Sopenharmony_ci	ctx->secs = secs = pebuf + cursor;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return 0;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/*
11962306a36Sopenharmony_ci * Check and strip the PE wrapper from around the signature and check that the
12062306a36Sopenharmony_ci * remnant looks something like PKCS#7.
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_cistatic int pefile_strip_sig_wrapper(const void *pebuf,
12362306a36Sopenharmony_ci				    struct pefile_context *ctx)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct win_certificate wrapper;
12662306a36Sopenharmony_ci	const u8 *pkcs7;
12762306a36Sopenharmony_ci	unsigned len;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (ctx->sig_len < sizeof(wrapper)) {
13062306a36Sopenharmony_ci		pr_warn("Signature wrapper too short\n");
13162306a36Sopenharmony_ci		return -ELIBBAD;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
13562306a36Sopenharmony_ci	pr_debug("sig wrapper = { %x, %x, %x }\n",
13662306a36Sopenharmony_ci		 wrapper.length, wrapper.revision, wrapper.cert_type);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* sbsign rounds up the length of certificate table (in optional
13962306a36Sopenharmony_ci	 * header data directories) to 8 byte alignment.  However, the PE
14062306a36Sopenharmony_ci	 * specification states that while entries are 8-byte aligned, this is
14162306a36Sopenharmony_ci	 * not included in their length, and as a result, pesign has not
14262306a36Sopenharmony_ci	 * rounded up since 0.110.
14362306a36Sopenharmony_ci	 */
14462306a36Sopenharmony_ci	if (wrapper.length > ctx->sig_len) {
14562306a36Sopenharmony_ci		pr_warn("Signature wrapper bigger than sig len (%x > %x)\n",
14662306a36Sopenharmony_ci			ctx->sig_len, wrapper.length);
14762306a36Sopenharmony_ci		return -ELIBBAD;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci	if (wrapper.revision != WIN_CERT_REVISION_2_0) {
15062306a36Sopenharmony_ci		pr_warn("Signature is not revision 2.0\n");
15162306a36Sopenharmony_ci		return -ENOTSUPP;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci	if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
15462306a36Sopenharmony_ci		pr_warn("Signature certificate type is not PKCS\n");
15562306a36Sopenharmony_ci		return -ENOTSUPP;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* It looks like the pkcs signature length in wrapper->length and the
15962306a36Sopenharmony_ci	 * size obtained from the data dir entries, which lists the total size
16062306a36Sopenharmony_ci	 * of certificate table, are both aligned to an octaword boundary, so
16162306a36Sopenharmony_ci	 * we may have to deal with some padding.
16262306a36Sopenharmony_ci	 */
16362306a36Sopenharmony_ci	ctx->sig_len = wrapper.length;
16462306a36Sopenharmony_ci	ctx->sig_offset += sizeof(wrapper);
16562306a36Sopenharmony_ci	ctx->sig_len -= sizeof(wrapper);
16662306a36Sopenharmony_ci	if (ctx->sig_len < 4) {
16762306a36Sopenharmony_ci		pr_warn("Signature data missing\n");
16862306a36Sopenharmony_ci		return -EKEYREJECTED;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* What's left should be a PKCS#7 cert */
17262306a36Sopenharmony_ci	pkcs7 = pebuf + ctx->sig_offset;
17362306a36Sopenharmony_ci	if (pkcs7[0] != (ASN1_CONS_BIT | ASN1_SEQ))
17462306a36Sopenharmony_ci		goto not_pkcs7;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	switch (pkcs7[1]) {
17762306a36Sopenharmony_ci	case 0 ... 0x7f:
17862306a36Sopenharmony_ci		len = pkcs7[1] + 2;
17962306a36Sopenharmony_ci		goto check_len;
18062306a36Sopenharmony_ci	case ASN1_INDEFINITE_LENGTH:
18162306a36Sopenharmony_ci		return 0;
18262306a36Sopenharmony_ci	case 0x81:
18362306a36Sopenharmony_ci		len = pkcs7[2] + 3;
18462306a36Sopenharmony_ci		goto check_len;
18562306a36Sopenharmony_ci	case 0x82:
18662306a36Sopenharmony_ci		len = ((pkcs7[2] << 8) | pkcs7[3]) + 4;
18762306a36Sopenharmony_ci		goto check_len;
18862306a36Sopenharmony_ci	case 0x83 ... 0xff:
18962306a36Sopenharmony_ci		return -EMSGSIZE;
19062306a36Sopenharmony_ci	default:
19162306a36Sopenharmony_ci		goto not_pkcs7;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cicheck_len:
19562306a36Sopenharmony_ci	if (len <= ctx->sig_len) {
19662306a36Sopenharmony_ci		/* There may be padding */
19762306a36Sopenharmony_ci		ctx->sig_len = len;
19862306a36Sopenharmony_ci		return 0;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_cinot_pkcs7:
20162306a36Sopenharmony_ci	pr_warn("Signature data not PKCS#7\n");
20262306a36Sopenharmony_ci	return -ELIBBAD;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/*
20662306a36Sopenharmony_ci * Compare two sections for canonicalisation.
20762306a36Sopenharmony_ci */
20862306a36Sopenharmony_cistatic int pefile_compare_shdrs(const void *a, const void *b)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	const struct section_header *shdra = a;
21162306a36Sopenharmony_ci	const struct section_header *shdrb = b;
21262306a36Sopenharmony_ci	int rc;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (shdra->data_addr > shdrb->data_addr)
21562306a36Sopenharmony_ci		return 1;
21662306a36Sopenharmony_ci	if (shdrb->data_addr > shdra->data_addr)
21762306a36Sopenharmony_ci		return -1;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (shdra->virtual_address > shdrb->virtual_address)
22062306a36Sopenharmony_ci		return 1;
22162306a36Sopenharmony_ci	if (shdrb->virtual_address > shdra->virtual_address)
22262306a36Sopenharmony_ci		return -1;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	rc = strcmp(shdra->name, shdrb->name);
22562306a36Sopenharmony_ci	if (rc != 0)
22662306a36Sopenharmony_ci		return rc;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (shdra->virtual_size > shdrb->virtual_size)
22962306a36Sopenharmony_ci		return 1;
23062306a36Sopenharmony_ci	if (shdrb->virtual_size > shdra->virtual_size)
23162306a36Sopenharmony_ci		return -1;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (shdra->raw_data_size > shdrb->raw_data_size)
23462306a36Sopenharmony_ci		return 1;
23562306a36Sopenharmony_ci	if (shdrb->raw_data_size > shdra->raw_data_size)
23662306a36Sopenharmony_ci		return -1;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/*
24262306a36Sopenharmony_ci * Load the contents of the PE binary into the digest, leaving out the image
24362306a36Sopenharmony_ci * checksum and the certificate data block.
24462306a36Sopenharmony_ci */
24562306a36Sopenharmony_cistatic int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
24662306a36Sopenharmony_ci				     struct pefile_context *ctx,
24762306a36Sopenharmony_ci				     struct shash_desc *desc)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	unsigned *canon, tmp, loop, i, hashed_bytes;
25062306a36Sopenharmony_ci	int ret;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/* Digest the header and data directory, but leave out the image
25362306a36Sopenharmony_ci	 * checksum and the data dirent for the signature.
25462306a36Sopenharmony_ci	 */
25562306a36Sopenharmony_ci	ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
25662306a36Sopenharmony_ci	if (ret < 0)
25762306a36Sopenharmony_ci		return ret;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	tmp = ctx->image_checksum_offset + sizeof(uint32_t);
26062306a36Sopenharmony_ci	ret = crypto_shash_update(desc, pebuf + tmp,
26162306a36Sopenharmony_ci				  ctx->cert_dirent_offset - tmp);
26262306a36Sopenharmony_ci	if (ret < 0)
26362306a36Sopenharmony_ci		return ret;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
26662306a36Sopenharmony_ci	ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
26762306a36Sopenharmony_ci	if (ret < 0)
26862306a36Sopenharmony_ci		return ret;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
27162306a36Sopenharmony_ci	if (!canon)
27262306a36Sopenharmony_ci		return -ENOMEM;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* We have to canonicalise the section table, so we perform an
27562306a36Sopenharmony_ci	 * insertion sort.
27662306a36Sopenharmony_ci	 */
27762306a36Sopenharmony_ci	canon[0] = 0;
27862306a36Sopenharmony_ci	for (loop = 1; loop < ctx->n_sections; loop++) {
27962306a36Sopenharmony_ci		for (i = 0; i < loop; i++) {
28062306a36Sopenharmony_ci			if (pefile_compare_shdrs(&ctx->secs[canon[i]],
28162306a36Sopenharmony_ci						 &ctx->secs[loop]) > 0) {
28262306a36Sopenharmony_ci				memmove(&canon[i + 1], &canon[i],
28362306a36Sopenharmony_ci					(loop - i) * sizeof(canon[0]));
28462306a36Sopenharmony_ci				break;
28562306a36Sopenharmony_ci			}
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci		canon[i] = loop;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	hashed_bytes = ctx->header_size;
29162306a36Sopenharmony_ci	for (loop = 0; loop < ctx->n_sections; loop++) {
29262306a36Sopenharmony_ci		i = canon[loop];
29362306a36Sopenharmony_ci		if (ctx->secs[i].raw_data_size == 0)
29462306a36Sopenharmony_ci			continue;
29562306a36Sopenharmony_ci		ret = crypto_shash_update(desc,
29662306a36Sopenharmony_ci					  pebuf + ctx->secs[i].data_addr,
29762306a36Sopenharmony_ci					  ctx->secs[i].raw_data_size);
29862306a36Sopenharmony_ci		if (ret < 0) {
29962306a36Sopenharmony_ci			kfree(canon);
30062306a36Sopenharmony_ci			return ret;
30162306a36Sopenharmony_ci		}
30262306a36Sopenharmony_ci		hashed_bytes += ctx->secs[i].raw_data_size;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	kfree(canon);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (pelen > hashed_bytes) {
30762306a36Sopenharmony_ci		tmp = hashed_bytes + ctx->certs_size;
30862306a36Sopenharmony_ci		ret = crypto_shash_update(desc,
30962306a36Sopenharmony_ci					  pebuf + hashed_bytes,
31062306a36Sopenharmony_ci					  pelen - tmp);
31162306a36Sopenharmony_ci		if (ret < 0)
31262306a36Sopenharmony_ci			return ret;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return 0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/*
31962306a36Sopenharmony_ci * Digest the contents of the PE binary, leaving out the image checksum and the
32062306a36Sopenharmony_ci * certificate data block.
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_cistatic int pefile_digest_pe(const void *pebuf, unsigned int pelen,
32362306a36Sopenharmony_ci			    struct pefile_context *ctx)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct crypto_shash *tfm;
32662306a36Sopenharmony_ci	struct shash_desc *desc;
32762306a36Sopenharmony_ci	size_t digest_size, desc_size;
32862306a36Sopenharmony_ci	void *digest;
32962306a36Sopenharmony_ci	int ret;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	kenter(",%s", ctx->digest_algo);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Allocate the hashing algorithm we're going to need and find out how
33462306a36Sopenharmony_ci	 * big the hash operational data will be.
33562306a36Sopenharmony_ci	 */
33662306a36Sopenharmony_ci	tfm = crypto_alloc_shash(ctx->digest_algo, 0, 0);
33762306a36Sopenharmony_ci	if (IS_ERR(tfm))
33862306a36Sopenharmony_ci		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
34162306a36Sopenharmony_ci	digest_size = crypto_shash_digestsize(tfm);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (digest_size != ctx->digest_len) {
34462306a36Sopenharmony_ci		pr_warn("Digest size mismatch (%zx != %x)\n",
34562306a36Sopenharmony_ci			digest_size, ctx->digest_len);
34662306a36Sopenharmony_ci		ret = -EBADMSG;
34762306a36Sopenharmony_ci		goto error_no_desc;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci	pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ret = -ENOMEM;
35262306a36Sopenharmony_ci	desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
35362306a36Sopenharmony_ci	if (!desc)
35462306a36Sopenharmony_ci		goto error_no_desc;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	desc->tfm   = tfm;
35762306a36Sopenharmony_ci	ret = crypto_shash_init(desc);
35862306a36Sopenharmony_ci	if (ret < 0)
35962306a36Sopenharmony_ci		goto error;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
36262306a36Sopenharmony_ci	if (ret < 0)
36362306a36Sopenharmony_ci		goto error;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	digest = (void *)desc + desc_size;
36662306a36Sopenharmony_ci	ret = crypto_shash_final(desc, digest);
36762306a36Sopenharmony_ci	if (ret < 0)
36862306a36Sopenharmony_ci		goto error;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* Check that the PE file digest matches that in the MSCODE part of the
37362306a36Sopenharmony_ci	 * PKCS#7 certificate.
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
37662306a36Sopenharmony_ci		pr_warn("Digest mismatch\n");
37762306a36Sopenharmony_ci		ret = -EKEYREJECTED;
37862306a36Sopenharmony_ci	} else {
37962306a36Sopenharmony_ci		pr_debug("The digests match!\n");
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cierror:
38362306a36Sopenharmony_ci	kfree_sensitive(desc);
38462306a36Sopenharmony_cierror_no_desc:
38562306a36Sopenharmony_ci	crypto_free_shash(tfm);
38662306a36Sopenharmony_ci	kleave(" = %d", ret);
38762306a36Sopenharmony_ci	return ret;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/**
39162306a36Sopenharmony_ci * verify_pefile_signature - Verify the signature on a PE binary image
39262306a36Sopenharmony_ci * @pebuf: Buffer containing the PE binary image
39362306a36Sopenharmony_ci * @pelen: Length of the binary image
39462306a36Sopenharmony_ci * @trusted_keys: Signing certificate(s) to use as starting points
39562306a36Sopenharmony_ci * @usage: The use to which the key is being put.
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * Validate that the certificate chain inside the PKCS#7 message inside the PE
39862306a36Sopenharmony_ci * binary image intersects keys we already know and trust.
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * Returns, in order of descending priority:
40162306a36Sopenharmony_ci *
40262306a36Sopenharmony_ci *  (*) -ELIBBAD if the image cannot be parsed, or:
40362306a36Sopenharmony_ci *
40462306a36Sopenharmony_ci *  (*) -EKEYREJECTED if a signature failed to match for which we have a valid
40562306a36Sopenharmony_ci *	key, or:
40662306a36Sopenharmony_ci *
40762306a36Sopenharmony_ci *  (*) 0 if at least one signature chain intersects with the keys in the trust
40862306a36Sopenharmony_ci *	keyring, or:
40962306a36Sopenharmony_ci *
41062306a36Sopenharmony_ci *  (*) -ENODATA if there is no signature present.
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci *  (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
41362306a36Sopenharmony_ci *	chain.
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci *  (*) -ENOKEY if we couldn't find a match for any of the signature chains in
41662306a36Sopenharmony_ci *	the message.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * May also return -ENOMEM.
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_ciint verify_pefile_signature(const void *pebuf, unsigned pelen,
42162306a36Sopenharmony_ci			    struct key *trusted_keys,
42262306a36Sopenharmony_ci			    enum key_being_used_for usage)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct pefile_context ctx;
42562306a36Sopenharmony_ci	int ret;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	kenter("");
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	memset(&ctx, 0, sizeof(ctx));
43062306a36Sopenharmony_ci	ret = pefile_parse_binary(pebuf, pelen, &ctx);
43162306a36Sopenharmony_ci	if (ret < 0)
43262306a36Sopenharmony_ci		return ret;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ret = pefile_strip_sig_wrapper(pebuf, &ctx);
43562306a36Sopenharmony_ci	if (ret < 0)
43662306a36Sopenharmony_ci		return ret;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	ret = verify_pkcs7_signature(NULL, 0,
43962306a36Sopenharmony_ci				     pebuf + ctx.sig_offset, ctx.sig_len,
44062306a36Sopenharmony_ci				     trusted_keys, usage,
44162306a36Sopenharmony_ci				     mscode_parse, &ctx);
44262306a36Sopenharmony_ci	if (ret < 0)
44362306a36Sopenharmony_ci		goto error;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	pr_debug("Digest: %u [%*ph]\n",
44662306a36Sopenharmony_ci		 ctx.digest_len, ctx.digest_len, ctx.digest);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	/* Generate the digest and check against the PKCS7 certificate
44962306a36Sopenharmony_ci	 * contents.
45062306a36Sopenharmony_ci	 */
45162306a36Sopenharmony_ci	ret = pefile_digest_pe(pebuf, pelen, &ctx);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cierror:
45462306a36Sopenharmony_ci	kfree_sensitive(ctx.digest);
45562306a36Sopenharmony_ci	return ret;
45662306a36Sopenharmony_ci}
457