18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Parse a signed PE binary 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "PEFILE: "fmt 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/pe.h> 148c2ecf20Sopenharmony_ci#include <linux/asn1.h> 158c2ecf20Sopenharmony_ci#include <linux/verification.h> 168c2ecf20Sopenharmony_ci#include <crypto/hash.h> 178c2ecf20Sopenharmony_ci#include "verify_pefile.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Parse a PE binary. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_cistatic int pefile_parse_binary(const void *pebuf, unsigned int pelen, 238c2ecf20Sopenharmony_ci struct pefile_context *ctx) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci const struct mz_hdr *mz = pebuf; 268c2ecf20Sopenharmony_ci const struct pe_hdr *pe; 278c2ecf20Sopenharmony_ci const struct pe32_opt_hdr *pe32; 288c2ecf20Sopenharmony_ci const struct pe32plus_opt_hdr *pe64; 298c2ecf20Sopenharmony_ci const struct data_directory *ddir; 308c2ecf20Sopenharmony_ci const struct data_dirent *dde; 318c2ecf20Sopenharmony_ci const struct section_header *secs, *sec; 328c2ecf20Sopenharmony_ci size_t cursor, datalen = pelen; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci kenter(""); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define chkaddr(base, x, s) \ 378c2ecf20Sopenharmony_ci do { \ 388c2ecf20Sopenharmony_ci if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \ 398c2ecf20Sopenharmony_ci return -ELIBBAD; \ 408c2ecf20Sopenharmony_ci } while (0) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci chkaddr(0, 0, sizeof(*mz)); 438c2ecf20Sopenharmony_ci if (mz->magic != MZ_MAGIC) 448c2ecf20Sopenharmony_ci return -ELIBBAD; 458c2ecf20Sopenharmony_ci cursor = sizeof(*mz); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci chkaddr(cursor, mz->peaddr, sizeof(*pe)); 488c2ecf20Sopenharmony_ci pe = pebuf + mz->peaddr; 498c2ecf20Sopenharmony_ci if (pe->magic != PE_MAGIC) 508c2ecf20Sopenharmony_ci return -ELIBBAD; 518c2ecf20Sopenharmony_ci cursor = mz->peaddr + sizeof(*pe); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci chkaddr(0, cursor, sizeof(pe32->magic)); 548c2ecf20Sopenharmony_ci pe32 = pebuf + cursor; 558c2ecf20Sopenharmony_ci pe64 = pebuf + cursor; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci switch (pe32->magic) { 588c2ecf20Sopenharmony_ci case PE_OPT_MAGIC_PE32: 598c2ecf20Sopenharmony_ci chkaddr(0, cursor, sizeof(*pe32)); 608c2ecf20Sopenharmony_ci ctx->image_checksum_offset = 618c2ecf20Sopenharmony_ci (unsigned long)&pe32->csum - (unsigned long)pebuf; 628c2ecf20Sopenharmony_ci ctx->header_size = pe32->header_size; 638c2ecf20Sopenharmony_ci cursor += sizeof(*pe32); 648c2ecf20Sopenharmony_ci ctx->n_data_dirents = pe32->data_dirs; 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci case PE_OPT_MAGIC_PE32PLUS: 688c2ecf20Sopenharmony_ci chkaddr(0, cursor, sizeof(*pe64)); 698c2ecf20Sopenharmony_ci ctx->image_checksum_offset = 708c2ecf20Sopenharmony_ci (unsigned long)&pe64->csum - (unsigned long)pebuf; 718c2ecf20Sopenharmony_ci ctx->header_size = pe64->header_size; 728c2ecf20Sopenharmony_ci cursor += sizeof(*pe64); 738c2ecf20Sopenharmony_ci ctx->n_data_dirents = pe64->data_dirs; 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci default: 778c2ecf20Sopenharmony_ci pr_warn("Unknown PEOPT magic = %04hx\n", pe32->magic); 788c2ecf20Sopenharmony_ci return -ELIBBAD; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci pr_debug("checksum @ %x\n", ctx->image_checksum_offset); 828c2ecf20Sopenharmony_ci pr_debug("header size = %x\n", ctx->header_size); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (cursor >= ctx->header_size || ctx->header_size >= datalen) 858c2ecf20Sopenharmony_ci return -ELIBBAD; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde)) 888c2ecf20Sopenharmony_ci return -ELIBBAD; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ddir = pebuf + cursor; 918c2ecf20Sopenharmony_ci cursor += sizeof(*dde) * ctx->n_data_dirents; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci ctx->cert_dirent_offset = 948c2ecf20Sopenharmony_ci (unsigned long)&ddir->certs - (unsigned long)pebuf; 958c2ecf20Sopenharmony_ci ctx->certs_size = ddir->certs.size; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (!ddir->certs.virtual_address || !ddir->certs.size) { 988c2ecf20Sopenharmony_ci pr_warn("Unsigned PE binary\n"); 998c2ecf20Sopenharmony_ci return -ENODATA; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci chkaddr(ctx->header_size, ddir->certs.virtual_address, 1038c2ecf20Sopenharmony_ci ddir->certs.size); 1048c2ecf20Sopenharmony_ci ctx->sig_offset = ddir->certs.virtual_address; 1058c2ecf20Sopenharmony_ci ctx->sig_len = ddir->certs.size; 1068c2ecf20Sopenharmony_ci pr_debug("cert = %x @%x [%*ph]\n", 1078c2ecf20Sopenharmony_ci ctx->sig_len, ctx->sig_offset, 1088c2ecf20Sopenharmony_ci ctx->sig_len, pebuf + ctx->sig_offset); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci ctx->n_sections = pe->sections; 1118c2ecf20Sopenharmony_ci if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec)) 1128c2ecf20Sopenharmony_ci return -ELIBBAD; 1138c2ecf20Sopenharmony_ci ctx->secs = secs = pebuf + cursor; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * Check and strip the PE wrapper from around the signature and check that the 1208c2ecf20Sopenharmony_ci * remnant looks something like PKCS#7. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic int pefile_strip_sig_wrapper(const void *pebuf, 1238c2ecf20Sopenharmony_ci struct pefile_context *ctx) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct win_certificate wrapper; 1268c2ecf20Sopenharmony_ci const u8 *pkcs7; 1278c2ecf20Sopenharmony_ci unsigned len; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (ctx->sig_len < sizeof(wrapper)) { 1308c2ecf20Sopenharmony_ci pr_warn("Signature wrapper too short\n"); 1318c2ecf20Sopenharmony_ci return -ELIBBAD; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper)); 1358c2ecf20Sopenharmony_ci pr_debug("sig wrapper = { %x, %x, %x }\n", 1368c2ecf20Sopenharmony_ci wrapper.length, wrapper.revision, wrapper.cert_type); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* sbsign rounds up the length of certificate table (in optional 1398c2ecf20Sopenharmony_ci * header data directories) to 8 byte alignment. However, the PE 1408c2ecf20Sopenharmony_ci * specification states that while entries are 8-byte aligned, this is 1418c2ecf20Sopenharmony_ci * not included in their length, and as a result, pesign has not 1428c2ecf20Sopenharmony_ci * rounded up since 0.110. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci if (wrapper.length > ctx->sig_len) { 1458c2ecf20Sopenharmony_ci pr_warn("Signature wrapper bigger than sig len (%x > %x)\n", 1468c2ecf20Sopenharmony_ci ctx->sig_len, wrapper.length); 1478c2ecf20Sopenharmony_ci return -ELIBBAD; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci if (wrapper.revision != WIN_CERT_REVISION_2_0) { 1508c2ecf20Sopenharmony_ci pr_warn("Signature is not revision 2.0\n"); 1518c2ecf20Sopenharmony_ci return -ENOTSUPP; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) { 1548c2ecf20Sopenharmony_ci pr_warn("Signature certificate type is not PKCS\n"); 1558c2ecf20Sopenharmony_ci return -ENOTSUPP; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* It looks like the pkcs signature length in wrapper->length and the 1598c2ecf20Sopenharmony_ci * size obtained from the data dir entries, which lists the total size 1608c2ecf20Sopenharmony_ci * of certificate table, are both aligned to an octaword boundary, so 1618c2ecf20Sopenharmony_ci * we may have to deal with some padding. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci ctx->sig_len = wrapper.length; 1648c2ecf20Sopenharmony_ci ctx->sig_offset += sizeof(wrapper); 1658c2ecf20Sopenharmony_ci ctx->sig_len -= sizeof(wrapper); 1668c2ecf20Sopenharmony_ci if (ctx->sig_len < 4) { 1678c2ecf20Sopenharmony_ci pr_warn("Signature data missing\n"); 1688c2ecf20Sopenharmony_ci return -EKEYREJECTED; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* What's left should be a PKCS#7 cert */ 1728c2ecf20Sopenharmony_ci pkcs7 = pebuf + ctx->sig_offset; 1738c2ecf20Sopenharmony_ci if (pkcs7[0] != (ASN1_CONS_BIT | ASN1_SEQ)) 1748c2ecf20Sopenharmony_ci goto not_pkcs7; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci switch (pkcs7[1]) { 1778c2ecf20Sopenharmony_ci case 0 ... 0x7f: 1788c2ecf20Sopenharmony_ci len = pkcs7[1] + 2; 1798c2ecf20Sopenharmony_ci goto check_len; 1808c2ecf20Sopenharmony_ci case ASN1_INDEFINITE_LENGTH: 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci case 0x81: 1838c2ecf20Sopenharmony_ci len = pkcs7[2] + 3; 1848c2ecf20Sopenharmony_ci goto check_len; 1858c2ecf20Sopenharmony_ci case 0x82: 1868c2ecf20Sopenharmony_ci len = ((pkcs7[2] << 8) | pkcs7[3]) + 4; 1878c2ecf20Sopenharmony_ci goto check_len; 1888c2ecf20Sopenharmony_ci case 0x83 ... 0xff: 1898c2ecf20Sopenharmony_ci return -EMSGSIZE; 1908c2ecf20Sopenharmony_ci default: 1918c2ecf20Sopenharmony_ci goto not_pkcs7; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cicheck_len: 1958c2ecf20Sopenharmony_ci if (len <= ctx->sig_len) { 1968c2ecf20Sopenharmony_ci /* There may be padding */ 1978c2ecf20Sopenharmony_ci ctx->sig_len = len; 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_cinot_pkcs7: 2018c2ecf20Sopenharmony_ci pr_warn("Signature data not PKCS#7\n"); 2028c2ecf20Sopenharmony_ci return -ELIBBAD; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * Compare two sections for canonicalisation. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_cistatic int pefile_compare_shdrs(const void *a, const void *b) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci const struct section_header *shdra = a; 2118c2ecf20Sopenharmony_ci const struct section_header *shdrb = b; 2128c2ecf20Sopenharmony_ci int rc; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (shdra->data_addr > shdrb->data_addr) 2158c2ecf20Sopenharmony_ci return 1; 2168c2ecf20Sopenharmony_ci if (shdrb->data_addr > shdra->data_addr) 2178c2ecf20Sopenharmony_ci return -1; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (shdra->virtual_address > shdrb->virtual_address) 2208c2ecf20Sopenharmony_ci return 1; 2218c2ecf20Sopenharmony_ci if (shdrb->virtual_address > shdra->virtual_address) 2228c2ecf20Sopenharmony_ci return -1; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci rc = strcmp(shdra->name, shdrb->name); 2258c2ecf20Sopenharmony_ci if (rc != 0) 2268c2ecf20Sopenharmony_ci return rc; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (shdra->virtual_size > shdrb->virtual_size) 2298c2ecf20Sopenharmony_ci return 1; 2308c2ecf20Sopenharmony_ci if (shdrb->virtual_size > shdra->virtual_size) 2318c2ecf20Sopenharmony_ci return -1; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (shdra->raw_data_size > shdrb->raw_data_size) 2348c2ecf20Sopenharmony_ci return 1; 2358c2ecf20Sopenharmony_ci if (shdrb->raw_data_size > shdra->raw_data_size) 2368c2ecf20Sopenharmony_ci return -1; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* 2428c2ecf20Sopenharmony_ci * Load the contents of the PE binary into the digest, leaving out the image 2438c2ecf20Sopenharmony_ci * checksum and the certificate data block. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_cistatic int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen, 2468c2ecf20Sopenharmony_ci struct pefile_context *ctx, 2478c2ecf20Sopenharmony_ci struct shash_desc *desc) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci unsigned *canon, tmp, loop, i, hashed_bytes; 2508c2ecf20Sopenharmony_ci int ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Digest the header and data directory, but leave out the image 2538c2ecf20Sopenharmony_ci * checksum and the data dirent for the signature. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset); 2568c2ecf20Sopenharmony_ci if (ret < 0) 2578c2ecf20Sopenharmony_ci return ret; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci tmp = ctx->image_checksum_offset + sizeof(uint32_t); 2608c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, pebuf + tmp, 2618c2ecf20Sopenharmony_ci ctx->cert_dirent_offset - tmp); 2628c2ecf20Sopenharmony_ci if (ret < 0) 2638c2ecf20Sopenharmony_ci return ret; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent); 2668c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp); 2678c2ecf20Sopenharmony_ci if (ret < 0) 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL); 2718c2ecf20Sopenharmony_ci if (!canon) 2728c2ecf20Sopenharmony_ci return -ENOMEM; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* We have to canonicalise the section table, so we perform an 2758c2ecf20Sopenharmony_ci * insertion sort. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci canon[0] = 0; 2788c2ecf20Sopenharmony_ci for (loop = 1; loop < ctx->n_sections; loop++) { 2798c2ecf20Sopenharmony_ci for (i = 0; i < loop; i++) { 2808c2ecf20Sopenharmony_ci if (pefile_compare_shdrs(&ctx->secs[canon[i]], 2818c2ecf20Sopenharmony_ci &ctx->secs[loop]) > 0) { 2828c2ecf20Sopenharmony_ci memmove(&canon[i + 1], &canon[i], 2838c2ecf20Sopenharmony_ci (loop - i) * sizeof(canon[0])); 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci canon[i] = loop; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci hashed_bytes = ctx->header_size; 2918c2ecf20Sopenharmony_ci for (loop = 0; loop < ctx->n_sections; loop++) { 2928c2ecf20Sopenharmony_ci i = canon[loop]; 2938c2ecf20Sopenharmony_ci if (ctx->secs[i].raw_data_size == 0) 2948c2ecf20Sopenharmony_ci continue; 2958c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, 2968c2ecf20Sopenharmony_ci pebuf + ctx->secs[i].data_addr, 2978c2ecf20Sopenharmony_ci ctx->secs[i].raw_data_size); 2988c2ecf20Sopenharmony_ci if (ret < 0) { 2998c2ecf20Sopenharmony_ci kfree(canon); 3008c2ecf20Sopenharmony_ci return ret; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci hashed_bytes += ctx->secs[i].raw_data_size; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci kfree(canon); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (pelen > hashed_bytes) { 3078c2ecf20Sopenharmony_ci tmp = hashed_bytes + ctx->certs_size; 3088c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, 3098c2ecf20Sopenharmony_ci pebuf + hashed_bytes, 3108c2ecf20Sopenharmony_ci pelen - tmp); 3118c2ecf20Sopenharmony_ci if (ret < 0) 3128c2ecf20Sopenharmony_ci return ret; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/* 3198c2ecf20Sopenharmony_ci * Digest the contents of the PE binary, leaving out the image checksum and the 3208c2ecf20Sopenharmony_ci * certificate data block. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_cistatic int pefile_digest_pe(const void *pebuf, unsigned int pelen, 3238c2ecf20Sopenharmony_ci struct pefile_context *ctx) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct crypto_shash *tfm; 3268c2ecf20Sopenharmony_ci struct shash_desc *desc; 3278c2ecf20Sopenharmony_ci size_t digest_size, desc_size; 3288c2ecf20Sopenharmony_ci void *digest; 3298c2ecf20Sopenharmony_ci int ret; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci kenter(",%s", ctx->digest_algo); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Allocate the hashing algorithm we're going to need and find out how 3348c2ecf20Sopenharmony_ci * big the hash operational data will be. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash(ctx->digest_algo, 0, 0); 3378c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 3388c2ecf20Sopenharmony_ci return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); 3418c2ecf20Sopenharmony_ci digest_size = crypto_shash_digestsize(tfm); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (digest_size != ctx->digest_len) { 3448c2ecf20Sopenharmony_ci pr_warn("Digest size mismatch (%zx != %x)\n", 3458c2ecf20Sopenharmony_ci digest_size, ctx->digest_len); 3468c2ecf20Sopenharmony_ci ret = -EBADMSG; 3478c2ecf20Sopenharmony_ci goto error_no_desc; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci ret = -ENOMEM; 3528c2ecf20Sopenharmony_ci desc = kzalloc(desc_size + digest_size, GFP_KERNEL); 3538c2ecf20Sopenharmony_ci if (!desc) 3548c2ecf20Sopenharmony_ci goto error_no_desc; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci desc->tfm = tfm; 3578c2ecf20Sopenharmony_ci ret = crypto_shash_init(desc); 3588c2ecf20Sopenharmony_ci if (ret < 0) 3598c2ecf20Sopenharmony_ci goto error; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc); 3628c2ecf20Sopenharmony_ci if (ret < 0) 3638c2ecf20Sopenharmony_ci goto error; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci digest = (void *)desc + desc_size; 3668c2ecf20Sopenharmony_ci ret = crypto_shash_final(desc, digest); 3678c2ecf20Sopenharmony_ci if (ret < 0) 3688c2ecf20Sopenharmony_ci goto error; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* Check that the PE file digest matches that in the MSCODE part of the 3738c2ecf20Sopenharmony_ci * PKCS#7 certificate. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) { 3768c2ecf20Sopenharmony_ci pr_warn("Digest mismatch\n"); 3778c2ecf20Sopenharmony_ci ret = -EKEYREJECTED; 3788c2ecf20Sopenharmony_ci } else { 3798c2ecf20Sopenharmony_ci pr_debug("The digests match!\n"); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cierror: 3838c2ecf20Sopenharmony_ci kfree_sensitive(desc); 3848c2ecf20Sopenharmony_cierror_no_desc: 3858c2ecf20Sopenharmony_ci crypto_free_shash(tfm); 3868c2ecf20Sopenharmony_ci kleave(" = %d", ret); 3878c2ecf20Sopenharmony_ci return ret; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/** 3918c2ecf20Sopenharmony_ci * verify_pefile_signature - Verify the signature on a PE binary image 3928c2ecf20Sopenharmony_ci * @pebuf: Buffer containing the PE binary image 3938c2ecf20Sopenharmony_ci * @pelen: Length of the binary image 3948c2ecf20Sopenharmony_ci * @trust_keys: Signing certificate(s) to use as starting points 3958c2ecf20Sopenharmony_ci * @usage: The use to which the key is being put. 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci * Validate that the certificate chain inside the PKCS#7 message inside the PE 3988c2ecf20Sopenharmony_ci * binary image intersects keys we already know and trust. 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * Returns, in order of descending priority: 4018c2ecf20Sopenharmony_ci * 4028c2ecf20Sopenharmony_ci * (*) -ELIBBAD if the image cannot be parsed, or: 4038c2ecf20Sopenharmony_ci * 4048c2ecf20Sopenharmony_ci * (*) -EKEYREJECTED if a signature failed to match for which we have a valid 4058c2ecf20Sopenharmony_ci * key, or: 4068c2ecf20Sopenharmony_ci * 4078c2ecf20Sopenharmony_ci * (*) 0 if at least one signature chain intersects with the keys in the trust 4088c2ecf20Sopenharmony_ci * keyring, or: 4098c2ecf20Sopenharmony_ci * 4108c2ecf20Sopenharmony_ci * (*) -ENODATA if there is no signature present. 4118c2ecf20Sopenharmony_ci * 4128c2ecf20Sopenharmony_ci * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a 4138c2ecf20Sopenharmony_ci * chain. 4148c2ecf20Sopenharmony_ci * 4158c2ecf20Sopenharmony_ci * (*) -ENOKEY if we couldn't find a match for any of the signature chains in 4168c2ecf20Sopenharmony_ci * the message. 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * May also return -ENOMEM. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ciint verify_pefile_signature(const void *pebuf, unsigned pelen, 4218c2ecf20Sopenharmony_ci struct key *trusted_keys, 4228c2ecf20Sopenharmony_ci enum key_being_used_for usage) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct pefile_context ctx; 4258c2ecf20Sopenharmony_ci int ret; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci kenter(""); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci memset(&ctx, 0, sizeof(ctx)); 4308c2ecf20Sopenharmony_ci ret = pefile_parse_binary(pebuf, pelen, &ctx); 4318c2ecf20Sopenharmony_ci if (ret < 0) 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ret = pefile_strip_sig_wrapper(pebuf, &ctx); 4358c2ecf20Sopenharmony_ci if (ret < 0) 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci ret = verify_pkcs7_signature(NULL, 0, 4398c2ecf20Sopenharmony_ci pebuf + ctx.sig_offset, ctx.sig_len, 4408c2ecf20Sopenharmony_ci trusted_keys, usage, 4418c2ecf20Sopenharmony_ci mscode_parse, &ctx); 4428c2ecf20Sopenharmony_ci if (ret < 0) 4438c2ecf20Sopenharmony_ci goto error; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci pr_debug("Digest: %u [%*ph]\n", 4468c2ecf20Sopenharmony_ci ctx.digest_len, ctx.digest_len, ctx.digest); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Generate the digest and check against the PKCS7 certificate 4498c2ecf20Sopenharmony_ci * contents. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci ret = pefile_digest_pe(pebuf, pelen, &ctx); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cierror: 4548c2ecf20Sopenharmony_ci kfree_sensitive(ctx.digest); 4558c2ecf20Sopenharmony_ci return ret; 4568c2ecf20Sopenharmony_ci} 457