mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-16 14:02:10 +00:00
Signed PE file verifier
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIVAwUAU71KqhOxKuMESys7AQKIwRAAgOXB0hjYkWKCHL2B1/8bNUtRKQKHsCms 4HgNuLQ4v+RjpXDd4u0HvjkuD2ADDZlBPNSylsLsrnSXS7gH/b36vetAi8zYR/6B Tuvorh6BfnOkN61Xg0mwlnXkp9jisTwaZofMTDlpQ4gPAAy098Lb73ONIIlJFIH9 WrUH/LLcPqtexdOOFtXPTBH0uz+qu8tcQHAotkP7Uwr4lDliVu1u4F2HkxRPvLjc IKSgb1mRa0AU0mKXbdqFREBhpVIOPS7r5mIisKnUh2d8LysSiA++zlD8/t2pfsVM enR7fo9pBEtJwhCrkff2p39DijR4M7s+SYF9soa9+9HQADt9D4bEtliqejGEkuQP CBl4LZ4eHlh1bjQbay+PixDmFxEbN14IKkvNaXBvoax8f0DdXV2URGxmhU0tM08U SFt2FaHhlBOsn4mhSoKJQnfHla5MP06ukrz4T+Qn2xd+lAX9e/sEBUQqT26o5Mgt 3yTaBrg4PREYjPVhguKT04tWrMdtvxY0nKRuUUeEcT7EQNVB5v/efGaWCxLI5k3O wbkq5JvzSdq+VJOrby8m37fnEN7pxmF7mwOPXYfe3WPwJeX7xiYRc2ZGFntKdNzn zSNKC4/OYiNwn+2ANL89kcJ3pJyoJ57SsMPiXpCCekPIcLtvGddoCvZae6f171HA ZzlbxkjIxg0= =e1NL -----END PGP SIGNATURE----- Merge tag 'keys-pefile-20140709' into keys-next Here's a set of changes that implement a PE file signature checker. This provides the following facility: (1) Extract the signature from the PE file. This is a PKCS#7 message containing, as its data, a hash of the signed parts of the file. (2) Digest the signed parts of the file. (3) Compare the digest with the one from the PKCS#7 message. (4) Validate the signatures on the PKCS#7 message and indicate whether it was matched by a trusted key. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
commit
6204e00255
@ -33,7 +33,7 @@ config X509_CERTIFICATE_PARSER
|
||||
select ASN1
|
||||
select OID_REGISTRY
|
||||
help
|
||||
This option procides support for parsing X.509 format blobs for key
|
||||
This option provides support for parsing X.509 format blobs for key
|
||||
data and provides the ability to instantiate a crypto key from a
|
||||
public key packet found inside the certificate.
|
||||
|
||||
@ -59,4 +59,13 @@ config PKCS7_TEST_KEY
|
||||
|
||||
This is intended for testing the PKCS#7 parser.
|
||||
|
||||
config SIGNED_PE_FILE_VERIFICATION
|
||||
bool "Support for PE file signature verification"
|
||||
depends on PKCS7_MESSAGE_PARSER=y
|
||||
select ASN1
|
||||
select OID_REGISTRY
|
||||
help
|
||||
This option provides support for verifying the signature(s) on a
|
||||
signed PE binary.
|
||||
|
||||
endif # ASYMMETRIC_KEY_TYPE
|
||||
|
@ -47,3 +47,18 @@ clean-files += pkcs7-asn1.c pkcs7-asn1.h
|
||||
obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o
|
||||
pkcs7_test_key-y := \
|
||||
pkcs7_key_type.o
|
||||
|
||||
#
|
||||
# Signed PE binary-wrapped key handling
|
||||
#
|
||||
obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o
|
||||
|
||||
verify_signed_pefile-y := \
|
||||
verify_pefile.o \
|
||||
mscode_parser.o \
|
||||
mscode-asn1.o
|
||||
|
||||
$(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h
|
||||
$(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h
|
||||
|
||||
clean-files += mscode-asn1.c mscode-asn1.h
|
||||
|
28
crypto/asymmetric_keys/mscode.asn1
Normal file
28
crypto/asymmetric_keys/mscode.asn1
Normal file
@ -0,0 +1,28 @@
|
||||
--- Microsoft individual code signing data blob parser
|
||||
---
|
||||
--- Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
--- Written by David Howells (dhowells@redhat.com)
|
||||
---
|
||||
--- This program is free software; you can redistribute it and/or
|
||||
--- modify it under the terms of the GNU General Public Licence
|
||||
--- as published by the Free Software Foundation; either version
|
||||
--- 2 of the Licence, or (at your option) any later version.
|
||||
---
|
||||
|
||||
MSCode ::= SEQUENCE {
|
||||
type SEQUENCE {
|
||||
contentType ContentType,
|
||||
parameters ANY
|
||||
},
|
||||
content SEQUENCE {
|
||||
digestAlgorithm DigestAlgorithmIdentifier,
|
||||
digest OCTET STRING ({ mscode_note_digest })
|
||||
}
|
||||
}
|
||||
|
||||
ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type })
|
||||
|
||||
DigestAlgorithmIdentifier ::= SEQUENCE {
|
||||
algorithm OBJECT IDENTIFIER ({ mscode_note_digest_algo }),
|
||||
parameters ANY OPTIONAL
|
||||
}
|
126
crypto/asymmetric_keys/mscode_parser.c
Normal file
126
crypto/asymmetric_keys/mscode_parser.c
Normal file
@ -0,0 +1,126 @@
|
||||
/* Parse a Microsoft Individual Code Signing blob
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "MSCODE: "fmt
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/oid_registry.h>
|
||||
#include <crypto/pkcs7.h>
|
||||
#include "verify_pefile.h"
|
||||
#include "mscode-asn1.h"
|
||||
|
||||
/*
|
||||
* Parse a Microsoft Individual Code Signing blob
|
||||
*/
|
||||
int mscode_parse(struct pefile_context *ctx)
|
||||
{
|
||||
const void *content_data;
|
||||
size_t data_len;
|
||||
int ret;
|
||||
|
||||
ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
|
||||
|
||||
if (ret) {
|
||||
pr_debug("PKCS#7 message does not contain data\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
|
||||
content_data);
|
||||
|
||||
return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the content type OID
|
||||
*/
|
||||
int mscode_note_content_type(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
enum OID oid;
|
||||
|
||||
oid = look_up_OID(value, vlen);
|
||||
if (oid == OID__NR) {
|
||||
char buffer[50];
|
||||
|
||||
sprint_oid(value, vlen, buffer, sizeof(buffer));
|
||||
pr_err("Unknown OID: %s\n", buffer);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/*
|
||||
* pesign utility had a bug where it was putting
|
||||
* OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId
|
||||
* So allow both OIDs.
|
||||
*/
|
||||
if (oid != OID_msPeImageDataObjId &&
|
||||
oid != OID_msIndividualSPKeyPurpose) {
|
||||
pr_err("Unexpected content type OID %u\n", oid);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the digest algorithm OID
|
||||
*/
|
||||
int mscode_note_digest_algo(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pefile_context *ctx = context;
|
||||
char buffer[50];
|
||||
enum OID oid;
|
||||
|
||||
oid = look_up_OID(value, vlen);
|
||||
switch (oid) {
|
||||
case OID_md4:
|
||||
ctx->digest_algo = HASH_ALGO_MD4;
|
||||
break;
|
||||
case OID_md5:
|
||||
ctx->digest_algo = HASH_ALGO_MD5;
|
||||
break;
|
||||
case OID_sha1:
|
||||
ctx->digest_algo = HASH_ALGO_SHA1;
|
||||
break;
|
||||
case OID_sha256:
|
||||
ctx->digest_algo = HASH_ALGO_SHA256;
|
||||
break;
|
||||
|
||||
case OID__NR:
|
||||
sprint_oid(value, vlen, buffer, sizeof(buffer));
|
||||
pr_err("Unknown OID: %s\n", buffer);
|
||||
return -EBADMSG;
|
||||
|
||||
default:
|
||||
pr_err("Unsupported content type: %u\n", oid);
|
||||
return -ENOPKG;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the digest we're guaranteeing with this certificate
|
||||
*/
|
||||
int mscode_note_digest(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pefile_context *ctx = context;
|
||||
|
||||
ctx->digest = value;
|
||||
ctx->digest_len = vlen;
|
||||
return 0;
|
||||
}
|
457
crypto/asymmetric_keys/verify_pefile.c
Normal file
457
crypto/asymmetric_keys/verify_pefile.c
Normal file
@ -0,0 +1,457 @@
|
||||
/* Parse a signed PE binary
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "PEFILE: "fmt
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pe.h>
|
||||
#include <linux/asn1.h>
|
||||
#include <crypto/pkcs7.h>
|
||||
#include <crypto/hash.h>
|
||||
#include "verify_pefile.h"
|
||||
|
||||
/*
|
||||
* Parse a PE binary.
|
||||
*/
|
||||
static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
|
||||
struct pefile_context *ctx)
|
||||
{
|
||||
const struct mz_hdr *mz = pebuf;
|
||||
const struct pe_hdr *pe;
|
||||
const struct pe32_opt_hdr *pe32;
|
||||
const struct pe32plus_opt_hdr *pe64;
|
||||
const struct data_directory *ddir;
|
||||
const struct data_dirent *dde;
|
||||
const struct section_header *secs, *sec;
|
||||
size_t cursor, datalen = pelen;
|
||||
|
||||
kenter("");
|
||||
|
||||
#define chkaddr(base, x, s) \
|
||||
do { \
|
||||
if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
|
||||
return -ELIBBAD; \
|
||||
} while (0)
|
||||
|
||||
chkaddr(0, 0, sizeof(*mz));
|
||||
if (mz->magic != MZ_MAGIC)
|
||||
return -ELIBBAD;
|
||||
cursor = sizeof(*mz);
|
||||
|
||||
chkaddr(cursor, mz->peaddr, sizeof(*pe));
|
||||
pe = pebuf + mz->peaddr;
|
||||
if (pe->magic != PE_MAGIC)
|
||||
return -ELIBBAD;
|
||||
cursor = mz->peaddr + sizeof(*pe);
|
||||
|
||||
chkaddr(0, cursor, sizeof(pe32->magic));
|
||||
pe32 = pebuf + cursor;
|
||||
pe64 = pebuf + cursor;
|
||||
|
||||
switch (pe32->magic) {
|
||||
case PE_OPT_MAGIC_PE32:
|
||||
chkaddr(0, cursor, sizeof(*pe32));
|
||||
ctx->image_checksum_offset =
|
||||
(unsigned long)&pe32->csum - (unsigned long)pebuf;
|
||||
ctx->header_size = pe32->header_size;
|
||||
cursor += sizeof(*pe32);
|
||||
ctx->n_data_dirents = pe32->data_dirs;
|
||||
break;
|
||||
|
||||
case PE_OPT_MAGIC_PE32PLUS:
|
||||
chkaddr(0, cursor, sizeof(*pe64));
|
||||
ctx->image_checksum_offset =
|
||||
(unsigned long)&pe64->csum - (unsigned long)pebuf;
|
||||
ctx->header_size = pe64->header_size;
|
||||
cursor += sizeof(*pe64);
|
||||
ctx->n_data_dirents = pe64->data_dirs;
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
|
||||
return -ELIBBAD;
|
||||
}
|
||||
|
||||
pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
|
||||
pr_debug("header size = %x\n", ctx->header_size);
|
||||
|
||||
if (cursor >= ctx->header_size || ctx->header_size >= datalen)
|
||||
return -ELIBBAD;
|
||||
|
||||
if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
|
||||
return -ELIBBAD;
|
||||
|
||||
ddir = pebuf + cursor;
|
||||
cursor += sizeof(*dde) * ctx->n_data_dirents;
|
||||
|
||||
ctx->cert_dirent_offset =
|
||||
(unsigned long)&ddir->certs - (unsigned long)pebuf;
|
||||
ctx->certs_size = ddir->certs.size;
|
||||
|
||||
if (!ddir->certs.virtual_address || !ddir->certs.size) {
|
||||
pr_debug("Unsigned PE binary\n");
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
|
||||
chkaddr(ctx->header_size, ddir->certs.virtual_address,
|
||||
ddir->certs.size);
|
||||
ctx->sig_offset = ddir->certs.virtual_address;
|
||||
ctx->sig_len = ddir->certs.size;
|
||||
pr_debug("cert = %x @%x [%*ph]\n",
|
||||
ctx->sig_len, ctx->sig_offset,
|
||||
ctx->sig_len, pebuf + ctx->sig_offset);
|
||||
|
||||
ctx->n_sections = pe->sections;
|
||||
if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
|
||||
return -ELIBBAD;
|
||||
ctx->secs = secs = pebuf + cursor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check and strip the PE wrapper from around the signature and check that the
|
||||
* remnant looks something like PKCS#7.
|
||||
*/
|
||||
static int pefile_strip_sig_wrapper(const void *pebuf,
|
||||
struct pefile_context *ctx)
|
||||
{
|
||||
struct win_certificate wrapper;
|
||||
const u8 *pkcs7;
|
||||
|
||||
if (ctx->sig_len < sizeof(wrapper)) {
|
||||
pr_debug("Signature wrapper too short\n");
|
||||
return -ELIBBAD;
|
||||
}
|
||||
|
||||
memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
|
||||
pr_debug("sig wrapper = { %x, %x, %x }\n",
|
||||
wrapper.length, wrapper.revision, wrapper.cert_type);
|
||||
|
||||
/* Both pesign and sbsign round up the length of certificate table
|
||||
* (in optional header data directories) to 8 byte alignment.
|
||||
*/
|
||||
if (round_up(wrapper.length, 8) != ctx->sig_len) {
|
||||
pr_debug("Signature wrapper len wrong\n");
|
||||
return -ELIBBAD;
|
||||
}
|
||||
if (wrapper.revision != WIN_CERT_REVISION_2_0) {
|
||||
pr_debug("Signature is not revision 2.0\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
|
||||
pr_debug("Signature certificate type is not PKCS\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/* Looks like actual pkcs signature length is in wrapper->length.
|
||||
* size obtained from data dir entries lists the total size of
|
||||
* certificate table which is also aligned to octawrod boundary.
|
||||
*
|
||||
* So set signature length field appropriately.
|
||||
*/
|
||||
ctx->sig_len = wrapper.length;
|
||||
ctx->sig_offset += sizeof(wrapper);
|
||||
ctx->sig_len -= sizeof(wrapper);
|
||||
if (ctx->sig_len == 0) {
|
||||
pr_debug("Signature data missing\n");
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
|
||||
/* What's left should a PKCS#7 cert */
|
||||
pkcs7 = pebuf + ctx->sig_offset;
|
||||
if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) {
|
||||
if (pkcs7[1] == 0x82 &&
|
||||
pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) &&
|
||||
pkcs7[3] == ((ctx->sig_len - 4) & 0xff))
|
||||
return 0;
|
||||
if (pkcs7[1] == 0x80)
|
||||
return 0;
|
||||
if (pkcs7[1] > 0x82)
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
pr_debug("Signature data not PKCS#7\n");
|
||||
return -ELIBBAD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two sections for canonicalisation.
|
||||
*/
|
||||
static int pefile_compare_shdrs(const void *a, const void *b)
|
||||
{
|
||||
const struct section_header *shdra = a;
|
||||
const struct section_header *shdrb = b;
|
||||
int rc;
|
||||
|
||||
if (shdra->data_addr > shdrb->data_addr)
|
||||
return 1;
|
||||
if (shdrb->data_addr > shdra->data_addr)
|
||||
return -1;
|
||||
|
||||
if (shdra->virtual_address > shdrb->virtual_address)
|
||||
return 1;
|
||||
if (shdrb->virtual_address > shdra->virtual_address)
|
||||
return -1;
|
||||
|
||||
rc = strcmp(shdra->name, shdrb->name);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (shdra->virtual_size > shdrb->virtual_size)
|
||||
return 1;
|
||||
if (shdrb->virtual_size > shdra->virtual_size)
|
||||
return -1;
|
||||
|
||||
if (shdra->raw_data_size > shdrb->raw_data_size)
|
||||
return 1;
|
||||
if (shdrb->raw_data_size > shdra->raw_data_size)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the contents of the PE binary into the digest, leaving out the image
|
||||
* checksum and the certificate data block.
|
||||
*/
|
||||
static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
|
||||
struct pefile_context *ctx,
|
||||
struct shash_desc *desc)
|
||||
{
|
||||
unsigned *canon, tmp, loop, i, hashed_bytes;
|
||||
int ret;
|
||||
|
||||
/* Digest the header and data directory, but leave out the image
|
||||
* checksum and the data dirent for the signature.
|
||||
*/
|
||||
ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tmp = ctx->image_checksum_offset + sizeof(uint32_t);
|
||||
ret = crypto_shash_update(desc, pebuf + tmp,
|
||||
ctx->cert_dirent_offset - tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
|
||||
ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
|
||||
if (!canon)
|
||||
return -ENOMEM;
|
||||
|
||||
/* We have to canonicalise the section table, so we perform an
|
||||
* insertion sort.
|
||||
*/
|
||||
canon[0] = 0;
|
||||
for (loop = 1; loop < ctx->n_sections; loop++) {
|
||||
for (i = 0; i < loop; i++) {
|
||||
if (pefile_compare_shdrs(&ctx->secs[canon[i]],
|
||||
&ctx->secs[loop]) > 0) {
|
||||
memmove(&canon[i + 1], &canon[i],
|
||||
(loop - i) * sizeof(canon[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
canon[i] = loop;
|
||||
}
|
||||
|
||||
hashed_bytes = ctx->header_size;
|
||||
for (loop = 0; loop < ctx->n_sections; loop++) {
|
||||
i = canon[loop];
|
||||
if (ctx->secs[i].raw_data_size == 0)
|
||||
continue;
|
||||
ret = crypto_shash_update(desc,
|
||||
pebuf + ctx->secs[i].data_addr,
|
||||
ctx->secs[i].raw_data_size);
|
||||
if (ret < 0) {
|
||||
kfree(canon);
|
||||
return ret;
|
||||
}
|
||||
hashed_bytes += ctx->secs[i].raw_data_size;
|
||||
}
|
||||
kfree(canon);
|
||||
|
||||
if (pelen > hashed_bytes) {
|
||||
tmp = hashed_bytes + ctx->certs_size;
|
||||
ret = crypto_shash_update(desc,
|
||||
pebuf + hashed_bytes,
|
||||
pelen - tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Digest the contents of the PE binary, leaving out the image checksum and the
|
||||
* certificate data block.
|
||||
*/
|
||||
static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
|
||||
struct pefile_context *ctx)
|
||||
{
|
||||
struct crypto_shash *tfm;
|
||||
struct shash_desc *desc;
|
||||
size_t digest_size, desc_size;
|
||||
void *digest;
|
||||
int ret;
|
||||
|
||||
kenter(",%u", ctx->digest_algo);
|
||||
|
||||
/* Allocate the hashing algorithm we're going to need and find out how
|
||||
* big the hash operational data will be.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(hash_algo_name[ctx->digest_algo], 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
|
||||
|
||||
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
|
||||
digest_size = crypto_shash_digestsize(tfm);
|
||||
|
||||
if (digest_size != ctx->digest_len) {
|
||||
pr_debug("Digest size mismatch (%zx != %x)\n",
|
||||
digest_size, ctx->digest_len);
|
||||
ret = -EBADMSG;
|
||||
goto error_no_desc;
|
||||
}
|
||||
pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
|
||||
|
||||
ret = -ENOMEM;
|
||||
desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
|
||||
if (!desc)
|
||||
goto error_no_desc;
|
||||
|
||||
desc->tfm = tfm;
|
||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
digest = (void *)desc + desc_size;
|
||||
ret = crypto_shash_final(desc, digest);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
|
||||
|
||||
/* Check that the PE file digest matches that in the MSCODE part of the
|
||||
* PKCS#7 certificate.
|
||||
*/
|
||||
if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
|
||||
pr_debug("Digest mismatch\n");
|
||||
ret = -EKEYREJECTED;
|
||||
} else {
|
||||
pr_debug("The digests match!\n");
|
||||
}
|
||||
|
||||
error:
|
||||
kfree(desc);
|
||||
error_no_desc:
|
||||
crypto_free_shash(tfm);
|
||||
kleave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* verify_pefile_signature - Verify the signature on a PE binary image
|
||||
* @pebuf: Buffer containing the PE binary image
|
||||
* @pelen: Length of the binary image
|
||||
* @trust_keyring: Signing certificates to use as starting points
|
||||
* @_trusted: Set to true if trustworth, false otherwise
|
||||
*
|
||||
* Validate that the certificate chain inside the PKCS#7 message inside the PE
|
||||
* binary image intersects keys we already know and trust.
|
||||
*
|
||||
* Returns, in order of descending priority:
|
||||
*
|
||||
* (*) -ELIBBAD if the image cannot be parsed, or:
|
||||
*
|
||||
* (*) -EKEYREJECTED if a signature failed to match for which we have a valid
|
||||
* key, or:
|
||||
*
|
||||
* (*) 0 if at least one signature chain intersects with the keys in the trust
|
||||
* keyring, or:
|
||||
*
|
||||
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
|
||||
* chain.
|
||||
*
|
||||
* (*) -ENOKEY if we couldn't find a match for any of the signature chains in
|
||||
* the message.
|
||||
*
|
||||
* May also return -ENOMEM.
|
||||
*/
|
||||
int verify_pefile_signature(const void *pebuf, unsigned pelen,
|
||||
struct key *trusted_keyring, bool *_trusted)
|
||||
{
|
||||
struct pkcs7_message *pkcs7;
|
||||
struct pefile_context ctx;
|
||||
const void *data;
|
||||
size_t datalen;
|
||||
int ret;
|
||||
|
||||
kenter("");
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ret = pefile_parse_binary(pebuf, pelen, &ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pefile_strip_sig_wrapper(pebuf, &ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
|
||||
if (IS_ERR(pkcs7))
|
||||
return PTR_ERR(pkcs7);
|
||||
ctx.pkcs7 = pkcs7;
|
||||
|
||||
ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false);
|
||||
if (ret < 0 || datalen == 0) {
|
||||
pr_devel("PKCS#7 message does not contain data\n");
|
||||
ret = -EBADMSG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = mscode_parse(&ctx);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
pr_debug("Digest: %u [%*ph]\n",
|
||||
ctx.digest_len, ctx.digest_len, ctx.digest);
|
||||
|
||||
/* Generate the digest and check against the PKCS7 certificate
|
||||
* contents.
|
||||
*/
|
||||
ret = pefile_digest_pe(pebuf, pelen, &ctx);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = pkcs7_verify(pkcs7);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted);
|
||||
|
||||
error:
|
||||
pkcs7_free_message(ctx.pkcs7);
|
||||
return ret;
|
||||
}
|
42
crypto/asymmetric_keys/verify_pefile.h
Normal file
42
crypto/asymmetric_keys/verify_pefile.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* PE Binary parser bits
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/verify_pefile.h>
|
||||
#include <crypto/pkcs7.h>
|
||||
#include <crypto/hash_info.h>
|
||||
|
||||
struct pefile_context {
|
||||
unsigned header_size;
|
||||
unsigned image_checksum_offset;
|
||||
unsigned cert_dirent_offset;
|
||||
unsigned n_data_dirents;
|
||||
unsigned n_sections;
|
||||
unsigned certs_size;
|
||||
unsigned sig_offset;
|
||||
unsigned sig_len;
|
||||
const struct section_header *secs;
|
||||
struct pkcs7_message *pkcs7;
|
||||
|
||||
/* PKCS#7 MS Individual Code Signing content */
|
||||
const void *digest; /* Digest */
|
||||
unsigned digest_len; /* Digest length */
|
||||
enum hash_algo digest_algo; /* Digest algorithm */
|
||||
};
|
||||
|
||||
#define kenter(FMT, ...) \
|
||||
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
|
||||
#define kleave(FMT, ...) \
|
||||
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* mscode_parser.c
|
||||
*/
|
||||
extern int mscode_parse(struct pefile_context *ctx);
|
@ -52,8 +52,13 @@ enum OID {
|
||||
OID_md4, /* 1.2.840.113549.2.4 */
|
||||
OID_md5, /* 1.2.840.113549.2.5 */
|
||||
|
||||
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
|
||||
/* Microsoft Authenticode & Software Publishing */
|
||||
OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
|
||||
OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */
|
||||
OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */
|
||||
OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
|
||||
|
||||
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
|
||||
OID_sha1, /* 1.3.14.3.2.26 */
|
||||
OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
|
||||
|
||||
|
448
include/linux/pe.h
Normal file
448
include/linux/pe.h
Normal file
@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright 2011 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author(s): Peter Jones <pjones@redhat.com>
|
||||
*/
|
||||
#ifndef __LINUX_PE_H
|
||||
#define __LINUX_PE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define MZ_MAGIC 0x5a4d /* "MZ" */
|
||||
|
||||
struct mz_hdr {
|
||||
uint16_t magic; /* MZ_MAGIC */
|
||||
uint16_t lbsize; /* size of last used block */
|
||||
uint16_t blocks; /* pages in file, 0x3 */
|
||||
uint16_t relocs; /* relocations */
|
||||
uint16_t hdrsize; /* header size in "paragraphs" */
|
||||
uint16_t min_extra_pps; /* .bss */
|
||||
uint16_t max_extra_pps; /* runtime limit for the arena size */
|
||||
uint16_t ss; /* relative stack segment */
|
||||
uint16_t sp; /* initial %sp register */
|
||||
uint16_t checksum; /* word checksum */
|
||||
uint16_t ip; /* initial %ip register */
|
||||
uint16_t cs; /* initial %cs relative to load segment */
|
||||
uint16_t reloc_table_offset; /* offset of the first relocation */
|
||||
uint16_t overlay_num; /* overlay number. set to 0. */
|
||||
uint16_t reserved0[4]; /* reserved */
|
||||
uint16_t oem_id; /* oem identifier */
|
||||
uint16_t oem_info; /* oem specific */
|
||||
uint16_t reserved1[10]; /* reserved */
|
||||
uint32_t peaddr; /* address of pe header */
|
||||
char message[64]; /* message to print */
|
||||
};
|
||||
|
||||
struct mz_reloc {
|
||||
uint16_t offset;
|
||||
uint16_t segment;
|
||||
};
|
||||
|
||||
#define PE_MAGIC 0x00004550 /* "PE\0\0" */
|
||||
#define PE_OPT_MAGIC_PE32 0x010b
|
||||
#define PE_OPT_MAGIC_PE32_ROM 0x0107
|
||||
#define PE_OPT_MAGIC_PE32PLUS 0x020b
|
||||
|
||||
/* machine type */
|
||||
#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000
|
||||
#define IMAGE_FILE_MACHINE_AM33 0x01d3
|
||||
#define IMAGE_FILE_MACHINE_AMD64 0x8664
|
||||
#define IMAGE_FILE_MACHINE_ARM 0x01c0
|
||||
#define IMAGE_FILE_MACHINE_ARMV7 0x01c4
|
||||
#define IMAGE_FILE_MACHINE_EBC 0x0ebc
|
||||
#define IMAGE_FILE_MACHINE_I386 0x014c
|
||||
#define IMAGE_FILE_MACHINE_IA64 0x0200
|
||||
#define IMAGE_FILE_MACHINE_M32R 0x9041
|
||||
#define IMAGE_FILE_MACHINE_MIPS16 0x0266
|
||||
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366
|
||||
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466
|
||||
#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
|
||||
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
|
||||
#define IMAGE_FILE_MACHINE_R4000 0x0166
|
||||
#define IMAGE_FILE_MACHINE_SH3 0x01a2
|
||||
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
|
||||
#define IMAGE_FILE_MACHINE_SH3E 0x01a4
|
||||
#define IMAGE_FILE_MACHINE_SH4 0x01a6
|
||||
#define IMAGE_FILE_MACHINE_SH5 0x01a8
|
||||
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
|
||||
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
|
||||
|
||||
/* flags */
|
||||
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
|
||||
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
|
||||
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
|
||||
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
|
||||
#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
|
||||
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
|
||||
#define IMAGE_FILE_16BIT_MACHINE 0x0040
|
||||
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
|
||||
#define IMAGE_FILE_32BIT_MACHINE 0x0100
|
||||
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
|
||||
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
|
||||
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
|
||||
#define IMAGE_FILE_SYSTEM 0x1000
|
||||
#define IMAGE_FILE_DLL 0x2000
|
||||
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
|
||||
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
|
||||
|
||||
struct pe_hdr {
|
||||
uint32_t magic; /* PE magic */
|
||||
uint16_t machine; /* machine type */
|
||||
uint16_t sections; /* number of sections */
|
||||
uint32_t timestamp; /* time_t */
|
||||
uint32_t symbol_table; /* symbol table offset */
|
||||
uint32_t symbols; /* number of symbols */
|
||||
uint16_t opt_hdr_size; /* size of optional header */
|
||||
uint16_t flags; /* flags */
|
||||
};
|
||||
|
||||
#define IMAGE_FILE_OPT_ROM_MAGIC 0x107
|
||||
#define IMAGE_FILE_OPT_PE32_MAGIC 0x10b
|
||||
#define IMAGE_FILE_OPT_PE32_PLUS_MAGIC 0x20b
|
||||
|
||||
#define IMAGE_SUBSYSTEM_UNKNOWN 0
|
||||
#define IMAGE_SUBSYSTEM_NATIVE 1
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
|
||||
#define IMAGE_SUBSYSTEM_POSIX_CUI 7
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
|
||||
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
|
||||
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
|
||||
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
|
||||
#define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13
|
||||
#define IMAGE_SUBSYSTEM_XBOX 14
|
||||
|
||||
#define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040
|
||||
#define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080
|
||||
#define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100
|
||||
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200
|
||||
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
|
||||
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
|
||||
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
|
||||
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
|
||||
|
||||
/* the fact that pe32 isn't padded where pe32+ is 64-bit means union won't
|
||||
* work right. vomit. */
|
||||
struct pe32_opt_hdr {
|
||||
/* "standard" header */
|
||||
uint16_t magic; /* file type */
|
||||
uint8_t ld_major; /* linker major version */
|
||||
uint8_t ld_minor; /* linker minor version */
|
||||
uint32_t text_size; /* size of text section(s) */
|
||||
uint32_t data_size; /* size of data section(s) */
|
||||
uint32_t bss_size; /* size of bss section(s) */
|
||||
uint32_t entry_point; /* file offset of entry point */
|
||||
uint32_t code_base; /* relative code addr in ram */
|
||||
uint32_t data_base; /* relative data addr in ram */
|
||||
/* "windows" header */
|
||||
uint32_t image_base; /* preferred load address */
|
||||
uint32_t section_align; /* alignment in bytes */
|
||||
uint32_t file_align; /* file alignment in bytes */
|
||||
uint16_t os_major; /* major OS version */
|
||||
uint16_t os_minor; /* minor OS version */
|
||||
uint16_t image_major; /* major image version */
|
||||
uint16_t image_minor; /* minor image version */
|
||||
uint16_t subsys_major; /* major subsystem version */
|
||||
uint16_t subsys_minor; /* minor subsystem version */
|
||||
uint32_t win32_version; /* reserved, must be 0 */
|
||||
uint32_t image_size; /* image size */
|
||||
uint32_t header_size; /* header size rounded up to
|
||||
file_align */
|
||||
uint32_t csum; /* checksum */
|
||||
uint16_t subsys; /* subsystem */
|
||||
uint16_t dll_flags; /* more flags! */
|
||||
uint32_t stack_size_req;/* amt of stack requested */
|
||||
uint32_t stack_size; /* amt of stack required */
|
||||
uint32_t heap_size_req; /* amt of heap requested */
|
||||
uint32_t heap_size; /* amt of heap required */
|
||||
uint32_t loader_flags; /* reserved, must be 0 */
|
||||
uint32_t data_dirs; /* number of data dir entries */
|
||||
};
|
||||
|
||||
struct pe32plus_opt_hdr {
|
||||
uint16_t magic; /* file type */
|
||||
uint8_t ld_major; /* linker major version */
|
||||
uint8_t ld_minor; /* linker minor version */
|
||||
uint32_t text_size; /* size of text section(s) */
|
||||
uint32_t data_size; /* size of data section(s) */
|
||||
uint32_t bss_size; /* size of bss section(s) */
|
||||
uint32_t entry_point; /* file offset of entry point */
|
||||
uint32_t code_base; /* relative code addr in ram */
|
||||
/* "windows" header */
|
||||
uint64_t image_base; /* preferred load address */
|
||||
uint32_t section_align; /* alignment in bytes */
|
||||
uint32_t file_align; /* file alignment in bytes */
|
||||
uint16_t os_major; /* major OS version */
|
||||
uint16_t os_minor; /* minor OS version */
|
||||
uint16_t image_major; /* major image version */
|
||||
uint16_t image_minor; /* minor image version */
|
||||
uint16_t subsys_major; /* major subsystem version */
|
||||
uint16_t subsys_minor; /* minor subsystem version */
|
||||
uint32_t win32_version; /* reserved, must be 0 */
|
||||
uint32_t image_size; /* image size */
|
||||
uint32_t header_size; /* header size rounded up to
|
||||
file_align */
|
||||
uint32_t csum; /* checksum */
|
||||
uint16_t subsys; /* subsystem */
|
||||
uint16_t dll_flags; /* more flags! */
|
||||
uint64_t stack_size_req;/* amt of stack requested */
|
||||
uint64_t stack_size; /* amt of stack required */
|
||||
uint64_t heap_size_req; /* amt of heap requested */
|
||||
uint64_t heap_size; /* amt of heap required */
|
||||
uint32_t loader_flags; /* reserved, must be 0 */
|
||||
uint32_t data_dirs; /* number of data dir entries */
|
||||
};
|
||||
|
||||
struct data_dirent {
|
||||
uint32_t virtual_address; /* relative to load address */
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct data_directory {
|
||||
struct data_dirent exports; /* .edata */
|
||||
struct data_dirent imports; /* .idata */
|
||||
struct data_dirent resources; /* .rsrc */
|
||||
struct data_dirent exceptions; /* .pdata */
|
||||
struct data_dirent certs; /* certs */
|
||||
struct data_dirent base_relocations; /* .reloc */
|
||||
struct data_dirent debug; /* .debug */
|
||||
struct data_dirent arch; /* reservered */
|
||||
struct data_dirent global_ptr; /* global pointer reg. Size=0 */
|
||||
struct data_dirent tls; /* .tls */
|
||||
struct data_dirent load_config; /* load configuration structure */
|
||||
struct data_dirent bound_imports; /* no idea */
|
||||
struct data_dirent import_addrs; /* import address table */
|
||||
struct data_dirent delay_imports; /* delay-load import table */
|
||||
struct data_dirent clr_runtime_hdr; /* .cor (object only) */
|
||||
struct data_dirent reserved;
|
||||
};
|
||||
|
||||
struct section_header {
|
||||
char name[8]; /* name or "/12\0" string tbl offset */
|
||||
uint32_t virtual_size; /* size of loaded section in ram */
|
||||
uint32_t virtual_address; /* relative virtual address */
|
||||
uint32_t raw_data_size; /* size of the section */
|
||||
uint32_t data_addr; /* file pointer to first page of sec */
|
||||
uint32_t relocs; /* file pointer to relocation entries */
|
||||
uint32_t line_numbers; /* line numbers! */
|
||||
uint16_t num_relocs; /* number of relocations */
|
||||
uint16_t num_lin_numbers; /* srsly. */
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/* they actually defined 0x00000000 as well, but I think we'll skip that one. */
|
||||
#define IMAGE_SCN_RESERVED_0 0x00000001
|
||||
#define IMAGE_SCN_RESERVED_1 0x00000002
|
||||
#define IMAGE_SCN_RESERVED_2 0x00000004
|
||||
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* don't pad - obsolete */
|
||||
#define IMAGE_SCN_RESERVED_3 0x00000010
|
||||
#define IMAGE_SCN_CNT_CODE 0x00000020 /* .text */
|
||||
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */
|
||||
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */
|
||||
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* reserved */
|
||||
#define IMAGE_SCN_LNK_INFO 0x00000200 /* .drectve comments */
|
||||
#define IMAGE_SCN_RESERVED_4 0x00000400
|
||||
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* .o only - scn to be rm'd*/
|
||||
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* .o only - COMDAT data */
|
||||
#define IMAGE_SCN_RESERVED_5 0x00002000 /* spec omits this */
|
||||
#define IMAGE_SCN_RESERVED_6 0x00004000 /* spec omits this */
|
||||
#define IMAGE_SCN_GPREL 0x00008000 /* global pointer referenced data */
|
||||
/* spec lists 0x20000 twice, I suspect they meant 0x10000 for one of them */
|
||||
#define IMAGE_SCN_MEM_PURGEABLE 0x00010000 /* reserved for "future" use */
|
||||
#define IMAGE_SCN_16BIT 0x00020000 /* reserved for "future" use */
|
||||
#define IMAGE_SCN_LOCKED 0x00040000 /* reserved for "future" use */
|
||||
#define IMAGE_SCN_PRELOAD 0x00080000 /* reserved for "future" use */
|
||||
/* and here they just stuck a 1-byte integer in the middle of a bitfield */
|
||||
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 /* it does what it says on the box */
|
||||
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
|
||||
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
|
||||
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
|
||||
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
|
||||
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
|
||||
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
|
||||
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
|
||||
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
|
||||
#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000
|
||||
#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
|
||||
#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
|
||||
#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
|
||||
#define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000
|
||||
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* extended relocations */
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */
|
||||
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */
|
||||
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* not pageable */
|
||||
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* can be shared */
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 /* can be executed as code */
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000 /* readable */
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000 /* writeable */
|
||||
|
||||
enum x64_coff_reloc_type {
|
||||
IMAGE_REL_AMD64_ABSOLUTE = 0,
|
||||
IMAGE_REL_AMD64_ADDR64,
|
||||
IMAGE_REL_AMD64_ADDR32,
|
||||
IMAGE_REL_AMD64_ADDR32N,
|
||||
IMAGE_REL_AMD64_REL32,
|
||||
IMAGE_REL_AMD64_REL32_1,
|
||||
IMAGE_REL_AMD64_REL32_2,
|
||||
IMAGE_REL_AMD64_REL32_3,
|
||||
IMAGE_REL_AMD64_REL32_4,
|
||||
IMAGE_REL_AMD64_REL32_5,
|
||||
IMAGE_REL_AMD64_SECTION,
|
||||
IMAGE_REL_AMD64_SECREL,
|
||||
IMAGE_REL_AMD64_SECREL7,
|
||||
IMAGE_REL_AMD64_TOKEN,
|
||||
IMAGE_REL_AMD64_SREL32,
|
||||
IMAGE_REL_AMD64_PAIR,
|
||||
IMAGE_REL_AMD64_SSPAN32,
|
||||
};
|
||||
|
||||
enum arm_coff_reloc_type {
|
||||
IMAGE_REL_ARM_ABSOLUTE,
|
||||
IMAGE_REL_ARM_ADDR32,
|
||||
IMAGE_REL_ARM_ADDR32N,
|
||||
IMAGE_REL_ARM_BRANCH2,
|
||||
IMAGE_REL_ARM_BRANCH1,
|
||||
IMAGE_REL_ARM_SECTION,
|
||||
IMAGE_REL_ARM_SECREL,
|
||||
};
|
||||
|
||||
enum sh_coff_reloc_type {
|
||||
IMAGE_REL_SH3_ABSOLUTE,
|
||||
IMAGE_REL_SH3_DIRECT16,
|
||||
IMAGE_REL_SH3_DIRECT32,
|
||||
IMAGE_REL_SH3_DIRECT8,
|
||||
IMAGE_REL_SH3_DIRECT8_WORD,
|
||||
IMAGE_REL_SH3_DIRECT8_LONG,
|
||||
IMAGE_REL_SH3_DIRECT4,
|
||||
IMAGE_REL_SH3_DIRECT4_WORD,
|
||||
IMAGE_REL_SH3_DIRECT4_LONG,
|
||||
IMAGE_REL_SH3_PCREL8_WORD,
|
||||
IMAGE_REL_SH3_PCREL8_LONG,
|
||||
IMAGE_REL_SH3_PCREL12_WORD,
|
||||
IMAGE_REL_SH3_STARTOF_SECTION,
|
||||
IMAGE_REL_SH3_SIZEOF_SECTION,
|
||||
IMAGE_REL_SH3_SECTION,
|
||||
IMAGE_REL_SH3_SECREL,
|
||||
IMAGE_REL_SH3_DIRECT32_NB,
|
||||
IMAGE_REL_SH3_GPREL4_LONG,
|
||||
IMAGE_REL_SH3_TOKEN,
|
||||
IMAGE_REL_SHM_PCRELPT,
|
||||
IMAGE_REL_SHM_REFLO,
|
||||
IMAGE_REL_SHM_REFHALF,
|
||||
IMAGE_REL_SHM_RELLO,
|
||||
IMAGE_REL_SHM_RELHALF,
|
||||
IMAGE_REL_SHM_PAIR,
|
||||
IMAGE_REL_SHM_NOMODE,
|
||||
};
|
||||
|
||||
enum ppc_coff_reloc_type {
|
||||
IMAGE_REL_PPC_ABSOLUTE,
|
||||
IMAGE_REL_PPC_ADDR64,
|
||||
IMAGE_REL_PPC_ADDR32,
|
||||
IMAGE_REL_PPC_ADDR24,
|
||||
IMAGE_REL_PPC_ADDR16,
|
||||
IMAGE_REL_PPC_ADDR14,
|
||||
IMAGE_REL_PPC_REL24,
|
||||
IMAGE_REL_PPC_REL14,
|
||||
IMAGE_REL_PPC_ADDR32N,
|
||||
IMAGE_REL_PPC_SECREL,
|
||||
IMAGE_REL_PPC_SECTION,
|
||||
IMAGE_REL_PPC_SECREL16,
|
||||
IMAGE_REL_PPC_REFHI,
|
||||
IMAGE_REL_PPC_REFLO,
|
||||
IMAGE_REL_PPC_PAIR,
|
||||
IMAGE_REL_PPC_SECRELLO,
|
||||
IMAGE_REL_PPC_GPREL,
|
||||
IMAGE_REL_PPC_TOKEN,
|
||||
};
|
||||
|
||||
enum x86_coff_reloc_type {
|
||||
IMAGE_REL_I386_ABSOLUTE,
|
||||
IMAGE_REL_I386_DIR16,
|
||||
IMAGE_REL_I386_REL16,
|
||||
IMAGE_REL_I386_DIR32,
|
||||
IMAGE_REL_I386_DIR32NB,
|
||||
IMAGE_REL_I386_SEG12,
|
||||
IMAGE_REL_I386_SECTION,
|
||||
IMAGE_REL_I386_SECREL,
|
||||
IMAGE_REL_I386_TOKEN,
|
||||
IMAGE_REL_I386_SECREL7,
|
||||
IMAGE_REL_I386_REL32,
|
||||
};
|
||||
|
||||
enum ia64_coff_reloc_type {
|
||||
IMAGE_REL_IA64_ABSOLUTE,
|
||||
IMAGE_REL_IA64_IMM14,
|
||||
IMAGE_REL_IA64_IMM22,
|
||||
IMAGE_REL_IA64_IMM64,
|
||||
IMAGE_REL_IA64_DIR32,
|
||||
IMAGE_REL_IA64_DIR64,
|
||||
IMAGE_REL_IA64_PCREL21B,
|
||||
IMAGE_REL_IA64_PCREL21M,
|
||||
IMAGE_REL_IA64_PCREL21F,
|
||||
IMAGE_REL_IA64_GPREL22,
|
||||
IMAGE_REL_IA64_LTOFF22,
|
||||
IMAGE_REL_IA64_SECTION,
|
||||
IMAGE_REL_IA64_SECREL22,
|
||||
IMAGE_REL_IA64_SECREL64I,
|
||||
IMAGE_REL_IA64_SECREL32,
|
||||
IMAGE_REL_IA64_DIR32NB,
|
||||
IMAGE_REL_IA64_SREL14,
|
||||
IMAGE_REL_IA64_SREL22,
|
||||
IMAGE_REL_IA64_SREL32,
|
||||
IMAGE_REL_IA64_UREL32,
|
||||
IMAGE_REL_IA64_PCREL60X,
|
||||
IMAGE_REL_IA64_PCREL60B,
|
||||
IMAGE_REL_IA64_PCREL60F,
|
||||
IMAGE_REL_IA64_PCREL60I,
|
||||
IMAGE_REL_IA64_PCREL60M,
|
||||
IMAGE_REL_IA64_IMMGPREL6,
|
||||
IMAGE_REL_IA64_TOKEN,
|
||||
IMAGE_REL_IA64_GPREL32,
|
||||
IMAGE_REL_IA64_ADDEND,
|
||||
};
|
||||
|
||||
struct coff_reloc {
|
||||
uint32_t virtual_address;
|
||||
uint32_t symbol_table_index;
|
||||
union {
|
||||
enum x64_coff_reloc_type x64_type;
|
||||
enum arm_coff_reloc_type arm_type;
|
||||
enum sh_coff_reloc_type sh_type;
|
||||
enum ppc_coff_reloc_type ppc_type;
|
||||
enum x86_coff_reloc_type x86_type;
|
||||
enum ia64_coff_reloc_type ia64_type;
|
||||
uint16_t data;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Definitions for the contents of the certs data block
|
||||
*/
|
||||
#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
||||
#define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0
|
||||
#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
|
||||
|
||||
#define WIN_CERT_REVISION_1_0 0x0100
|
||||
#define WIN_CERT_REVISION_2_0 0x0200
|
||||
|
||||
struct win_certificate {
|
||||
uint32_t length;
|
||||
uint16_t revision;
|
||||
uint16_t cert_type;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_PE_H */
|
18
include/linux/verify_pefile.h
Normal file
18
include/linux/verify_pefile.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* Signed PE file verification
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_VERIFY_PEFILE_H
|
||||
#define _LINUX_VERIFY_PEFILE_H
|
||||
|
||||
extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
|
||||
struct key *trusted_keyring, bool *_trusted);
|
||||
|
||||
#endif /* _LINUX_VERIFY_PEFILE_H */
|
Loading…
Reference in New Issue
Block a user