cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

verify_pefile.c (11530B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* Parse a signed PE binary
      3 *
      4 * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#define pr_fmt(fmt) "PEFILE: "fmt
      9#include <linux/module.h>
     10#include <linux/kernel.h>
     11#include <linux/slab.h>
     12#include <linux/err.h>
     13#include <linux/pe.h>
     14#include <linux/asn1.h>
     15#include <linux/verification.h>
     16#include <crypto/hash.h>
     17#include "verify_pefile.h"
     18
     19/*
     20 * Parse a PE binary.
     21 */
     22static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
     23			       struct pefile_context *ctx)
     24{
     25	const struct mz_hdr *mz = pebuf;
     26	const struct pe_hdr *pe;
     27	const struct pe32_opt_hdr *pe32;
     28	const struct pe32plus_opt_hdr *pe64;
     29	const struct data_directory *ddir;
     30	const struct data_dirent *dde;
     31	const struct section_header *secs, *sec;
     32	size_t cursor, datalen = pelen;
     33
     34	kenter("");
     35
     36#define chkaddr(base, x, s)						\
     37	do {								\
     38		if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
     39			return -ELIBBAD;				\
     40	} while (0)
     41
     42	chkaddr(0, 0, sizeof(*mz));
     43	if (mz->magic != MZ_MAGIC)
     44		return -ELIBBAD;
     45	cursor = sizeof(*mz);
     46
     47	chkaddr(cursor, mz->peaddr, sizeof(*pe));
     48	pe = pebuf + mz->peaddr;
     49	if (pe->magic != PE_MAGIC)
     50		return -ELIBBAD;
     51	cursor = mz->peaddr + sizeof(*pe);
     52
     53	chkaddr(0, cursor, sizeof(pe32->magic));
     54	pe32 = pebuf + cursor;
     55	pe64 = pebuf + cursor;
     56
     57	switch (pe32->magic) {
     58	case PE_OPT_MAGIC_PE32:
     59		chkaddr(0, cursor, sizeof(*pe32));
     60		ctx->image_checksum_offset =
     61			(unsigned long)&pe32->csum - (unsigned long)pebuf;
     62		ctx->header_size = pe32->header_size;
     63		cursor += sizeof(*pe32);
     64		ctx->n_data_dirents = pe32->data_dirs;
     65		break;
     66
     67	case PE_OPT_MAGIC_PE32PLUS:
     68		chkaddr(0, cursor, sizeof(*pe64));
     69		ctx->image_checksum_offset =
     70			(unsigned long)&pe64->csum - (unsigned long)pebuf;
     71		ctx->header_size = pe64->header_size;
     72		cursor += sizeof(*pe64);
     73		ctx->n_data_dirents = pe64->data_dirs;
     74		break;
     75
     76	default:
     77		pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
     78		return -ELIBBAD;
     79	}
     80
     81	pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
     82	pr_debug("header size = %x\n", ctx->header_size);
     83
     84	if (cursor >= ctx->header_size || ctx->header_size >= datalen)
     85		return -ELIBBAD;
     86
     87	if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
     88		return -ELIBBAD;
     89
     90	ddir = pebuf + cursor;
     91	cursor += sizeof(*dde) * ctx->n_data_dirents;
     92
     93	ctx->cert_dirent_offset =
     94		(unsigned long)&ddir->certs - (unsigned long)pebuf;
     95	ctx->certs_size = ddir->certs.size;
     96
     97	if (!ddir->certs.virtual_address || !ddir->certs.size) {
     98		pr_debug("Unsigned PE binary\n");
     99		return -ENODATA;
    100	}
    101
    102	chkaddr(ctx->header_size, ddir->certs.virtual_address,
    103		ddir->certs.size);
    104	ctx->sig_offset = ddir->certs.virtual_address;
    105	ctx->sig_len = ddir->certs.size;
    106	pr_debug("cert = %x @%x [%*ph]\n",
    107		 ctx->sig_len, ctx->sig_offset,
    108		 ctx->sig_len, pebuf + ctx->sig_offset);
    109
    110	ctx->n_sections = pe->sections;
    111	if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
    112		return -ELIBBAD;
    113	ctx->secs = secs = pebuf + cursor;
    114
    115	return 0;
    116}
    117
    118/*
    119 * Check and strip the PE wrapper from around the signature and check that the
    120 * remnant looks something like PKCS#7.
    121 */
    122static int pefile_strip_sig_wrapper(const void *pebuf,
    123				    struct pefile_context *ctx)
    124{
    125	struct win_certificate wrapper;
    126	const u8 *pkcs7;
    127	unsigned len;
    128
    129	if (ctx->sig_len < sizeof(wrapper)) {
    130		pr_debug("Signature wrapper too short\n");
    131		return -ELIBBAD;
    132	}
    133
    134	memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
    135	pr_debug("sig wrapper = { %x, %x, %x }\n",
    136		 wrapper.length, wrapper.revision, wrapper.cert_type);
    137
    138	/* Both pesign and sbsign round up the length of certificate table
    139	 * (in optional header data directories) to 8 byte alignment.
    140	 */
    141	if (round_up(wrapper.length, 8) != ctx->sig_len) {
    142		pr_debug("Signature wrapper len wrong\n");
    143		return -ELIBBAD;
    144	}
    145	if (wrapper.revision != WIN_CERT_REVISION_2_0) {
    146		pr_debug("Signature is not revision 2.0\n");
    147		return -ENOTSUPP;
    148	}
    149	if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
    150		pr_debug("Signature certificate type is not PKCS\n");
    151		return -ENOTSUPP;
    152	}
    153
    154	/* It looks like the pkcs signature length in wrapper->length and the
    155	 * size obtained from the data dir entries, which lists the total size
    156	 * of certificate table, are both aligned to an octaword boundary, so
    157	 * we may have to deal with some padding.
    158	 */
    159	ctx->sig_len = wrapper.length;
    160	ctx->sig_offset += sizeof(wrapper);
    161	ctx->sig_len -= sizeof(wrapper);
    162	if (ctx->sig_len < 4) {
    163		pr_debug("Signature data missing\n");
    164		return -EKEYREJECTED;
    165	}
    166
    167	/* What's left should be a PKCS#7 cert */
    168	pkcs7 = pebuf + ctx->sig_offset;
    169	if (pkcs7[0] != (ASN1_CONS_BIT | ASN1_SEQ))
    170		goto not_pkcs7;
    171
    172	switch (pkcs7[1]) {
    173	case 0 ... 0x7f:
    174		len = pkcs7[1] + 2;
    175		goto check_len;
    176	case ASN1_INDEFINITE_LENGTH:
    177		return 0;
    178	case 0x81:
    179		len = pkcs7[2] + 3;
    180		goto check_len;
    181	case 0x82:
    182		len = ((pkcs7[2] << 8) | pkcs7[3]) + 4;
    183		goto check_len;
    184	case 0x83 ... 0xff:
    185		return -EMSGSIZE;
    186	default:
    187		goto not_pkcs7;
    188	}
    189
    190check_len:
    191	if (len <= ctx->sig_len) {
    192		/* There may be padding */
    193		ctx->sig_len = len;
    194		return 0;
    195	}
    196not_pkcs7:
    197	pr_debug("Signature data not PKCS#7\n");
    198	return -ELIBBAD;
    199}
    200
    201/*
    202 * Compare two sections for canonicalisation.
    203 */
    204static int pefile_compare_shdrs(const void *a, const void *b)
    205{
    206	const struct section_header *shdra = a;
    207	const struct section_header *shdrb = b;
    208	int rc;
    209
    210	if (shdra->data_addr > shdrb->data_addr)
    211		return 1;
    212	if (shdrb->data_addr > shdra->data_addr)
    213		return -1;
    214
    215	if (shdra->virtual_address > shdrb->virtual_address)
    216		return 1;
    217	if (shdrb->virtual_address > shdra->virtual_address)
    218		return -1;
    219
    220	rc = strcmp(shdra->name, shdrb->name);
    221	if (rc != 0)
    222		return rc;
    223
    224	if (shdra->virtual_size > shdrb->virtual_size)
    225		return 1;
    226	if (shdrb->virtual_size > shdra->virtual_size)
    227		return -1;
    228
    229	if (shdra->raw_data_size > shdrb->raw_data_size)
    230		return 1;
    231	if (shdrb->raw_data_size > shdra->raw_data_size)
    232		return -1;
    233
    234	return 0;
    235}
    236
    237/*
    238 * Load the contents of the PE binary into the digest, leaving out the image
    239 * checksum and the certificate data block.
    240 */
    241static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
    242				     struct pefile_context *ctx,
    243				     struct shash_desc *desc)
    244{
    245	unsigned *canon, tmp, loop, i, hashed_bytes;
    246	int ret;
    247
    248	/* Digest the header and data directory, but leave out the image
    249	 * checksum and the data dirent for the signature.
    250	 */
    251	ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
    252	if (ret < 0)
    253		return ret;
    254
    255	tmp = ctx->image_checksum_offset + sizeof(uint32_t);
    256	ret = crypto_shash_update(desc, pebuf + tmp,
    257				  ctx->cert_dirent_offset - tmp);
    258	if (ret < 0)
    259		return ret;
    260
    261	tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
    262	ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
    263	if (ret < 0)
    264		return ret;
    265
    266	canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
    267	if (!canon)
    268		return -ENOMEM;
    269
    270	/* We have to canonicalise the section table, so we perform an
    271	 * insertion sort.
    272	 */
    273	canon[0] = 0;
    274	for (loop = 1; loop < ctx->n_sections; loop++) {
    275		for (i = 0; i < loop; i++) {
    276			if (pefile_compare_shdrs(&ctx->secs[canon[i]],
    277						 &ctx->secs[loop]) > 0) {
    278				memmove(&canon[i + 1], &canon[i],
    279					(loop - i) * sizeof(canon[0]));
    280				break;
    281			}
    282		}
    283		canon[i] = loop;
    284	}
    285
    286	hashed_bytes = ctx->header_size;
    287	for (loop = 0; loop < ctx->n_sections; loop++) {
    288		i = canon[loop];
    289		if (ctx->secs[i].raw_data_size == 0)
    290			continue;
    291		ret = crypto_shash_update(desc,
    292					  pebuf + ctx->secs[i].data_addr,
    293					  ctx->secs[i].raw_data_size);
    294		if (ret < 0) {
    295			kfree(canon);
    296			return ret;
    297		}
    298		hashed_bytes += ctx->secs[i].raw_data_size;
    299	}
    300	kfree(canon);
    301
    302	if (pelen > hashed_bytes) {
    303		tmp = hashed_bytes + ctx->certs_size;
    304		ret = crypto_shash_update(desc,
    305					  pebuf + hashed_bytes,
    306					  pelen - tmp);
    307		if (ret < 0)
    308			return ret;
    309	}
    310
    311	return 0;
    312}
    313
    314/*
    315 * Digest the contents of the PE binary, leaving out the image checksum and the
    316 * certificate data block.
    317 */
    318static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
    319			    struct pefile_context *ctx)
    320{
    321	struct crypto_shash *tfm;
    322	struct shash_desc *desc;
    323	size_t digest_size, desc_size;
    324	void *digest;
    325	int ret;
    326
    327	kenter(",%s", ctx->digest_algo);
    328
    329	/* Allocate the hashing algorithm we're going to need and find out how
    330	 * big the hash operational data will be.
    331	 */
    332	tfm = crypto_alloc_shash(ctx->digest_algo, 0, 0);
    333	if (IS_ERR(tfm))
    334		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
    335
    336	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
    337	digest_size = crypto_shash_digestsize(tfm);
    338
    339	if (digest_size != ctx->digest_len) {
    340		pr_debug("Digest size mismatch (%zx != %x)\n",
    341			 digest_size, ctx->digest_len);
    342		ret = -EBADMSG;
    343		goto error_no_desc;
    344	}
    345	pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
    346
    347	ret = -ENOMEM;
    348	desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
    349	if (!desc)
    350		goto error_no_desc;
    351
    352	desc->tfm   = tfm;
    353	ret = crypto_shash_init(desc);
    354	if (ret < 0)
    355		goto error;
    356
    357	ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
    358	if (ret < 0)
    359		goto error;
    360
    361	digest = (void *)desc + desc_size;
    362	ret = crypto_shash_final(desc, digest);
    363	if (ret < 0)
    364		goto error;
    365
    366	pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
    367
    368	/* Check that the PE file digest matches that in the MSCODE part of the
    369	 * PKCS#7 certificate.
    370	 */
    371	if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
    372		pr_debug("Digest mismatch\n");
    373		ret = -EKEYREJECTED;
    374	} else {
    375		pr_debug("The digests match!\n");
    376	}
    377
    378error:
    379	kfree_sensitive(desc);
    380error_no_desc:
    381	crypto_free_shash(tfm);
    382	kleave(" = %d", ret);
    383	return ret;
    384}
    385
    386/**
    387 * verify_pefile_signature - Verify the signature on a PE binary image
    388 * @pebuf: Buffer containing the PE binary image
    389 * @pelen: Length of the binary image
    390 * @trust_keys: Signing certificate(s) to use as starting points
    391 * @usage: The use to which the key is being put.
    392 *
    393 * Validate that the certificate chain inside the PKCS#7 message inside the PE
    394 * binary image intersects keys we already know and trust.
    395 *
    396 * Returns, in order of descending priority:
    397 *
    398 *  (*) -ELIBBAD if the image cannot be parsed, or:
    399 *
    400 *  (*) -EKEYREJECTED if a signature failed to match for which we have a valid
    401 *	key, or:
    402 *
    403 *  (*) 0 if at least one signature chain intersects with the keys in the trust
    404 *	keyring, or:
    405 *
    406 *  (*) -ENODATA if there is no signature present.
    407 *
    408 *  (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
    409 *	chain.
    410 *
    411 *  (*) -ENOKEY if we couldn't find a match for any of the signature chains in
    412 *	the message.
    413 *
    414 * May also return -ENOMEM.
    415 */
    416int verify_pefile_signature(const void *pebuf, unsigned pelen,
    417			    struct key *trusted_keys,
    418			    enum key_being_used_for usage)
    419{
    420	struct pefile_context ctx;
    421	int ret;
    422
    423	kenter("");
    424
    425	memset(&ctx, 0, sizeof(ctx));
    426	ret = pefile_parse_binary(pebuf, pelen, &ctx);
    427	if (ret < 0)
    428		return ret;
    429
    430	ret = pefile_strip_sig_wrapper(pebuf, &ctx);
    431	if (ret < 0)
    432		return ret;
    433
    434	ret = verify_pkcs7_signature(NULL, 0,
    435				     pebuf + ctx.sig_offset, ctx.sig_len,
    436				     trusted_keys, usage,
    437				     mscode_parse, &ctx);
    438	if (ret < 0)
    439		goto error;
    440
    441	pr_debug("Digest: %u [%*ph]\n",
    442		 ctx.digest_len, ctx.digest_len, ctx.digest);
    443
    444	/* Generate the digest and check against the PKCS7 certificate
    445	 * contents.
    446	 */
    447	ret = pefile_digest_pe(pebuf, pelen, &ctx);
    448
    449error:
    450	kfree_sensitive(ctx.digest);
    451	return ret;
    452}