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