blob: aec7c509404e39ea1020b370a24edca49b1870a3 [file] [log] [blame]
David Howells26d11642014-07-01 16:02:51 +01001/* Parse a signed PE binary
2 *
3 * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#define pr_fmt(fmt) "PEFILE: "fmt
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/pe.h>
18#include <crypto/pkcs7.h>
19#include <crypto/hash.h>
20#include "verify_pefile.h"
21
22/*
23 * Parse a PE binary.
24 */
25static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
26 struct pefile_context *ctx)
27{
28 const struct mz_hdr *mz = pebuf;
29 const struct pe_hdr *pe;
30 const struct pe32_opt_hdr *pe32;
31 const struct pe32plus_opt_hdr *pe64;
32 const struct data_directory *ddir;
33 const struct data_dirent *dde;
34 const struct section_header *secs, *sec;
35 size_t cursor, datalen = pelen;
36
37 kenter("");
38
39#define chkaddr(base, x, s) \
40 do { \
41 if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
42 return -ELIBBAD; \
43 } while (0)
44
45 chkaddr(0, 0, sizeof(*mz));
46 if (mz->magic != MZ_MAGIC)
47 return -ELIBBAD;
48 cursor = sizeof(*mz);
49
50 chkaddr(cursor, mz->peaddr, sizeof(*pe));
51 pe = pebuf + mz->peaddr;
52 if (pe->magic != PE_MAGIC)
53 return -ELIBBAD;
54 cursor = mz->peaddr + sizeof(*pe);
55
56 chkaddr(0, cursor, sizeof(pe32->magic));
57 pe32 = pebuf + cursor;
58 pe64 = pebuf + cursor;
59
60 switch (pe32->magic) {
61 case PE_OPT_MAGIC_PE32:
62 chkaddr(0, cursor, sizeof(*pe32));
63 ctx->image_checksum_offset =
64 (unsigned long)&pe32->csum - (unsigned long)pebuf;
65 ctx->header_size = pe32->header_size;
66 cursor += sizeof(*pe32);
67 ctx->n_data_dirents = pe32->data_dirs;
68 break;
69
70 case PE_OPT_MAGIC_PE32PLUS:
71 chkaddr(0, cursor, sizeof(*pe64));
72 ctx->image_checksum_offset =
73 (unsigned long)&pe64->csum - (unsigned long)pebuf;
74 ctx->header_size = pe64->header_size;
75 cursor += sizeof(*pe64);
76 ctx->n_data_dirents = pe64->data_dirs;
77 break;
78
79 default:
80 pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
81 return -ELIBBAD;
82 }
83
84 pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
85 pr_debug("header size = %x\n", ctx->header_size);
86
87 if (cursor >= ctx->header_size || ctx->header_size >= datalen)
88 return -ELIBBAD;
89
90 if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
91 return -ELIBBAD;
92
93 ddir = pebuf + cursor;
94 cursor += sizeof(*dde) * ctx->n_data_dirents;
95
96 ctx->cert_dirent_offset =
97 (unsigned long)&ddir->certs - (unsigned long)pebuf;
98 ctx->certs_size = ddir->certs.size;
99
100 if (!ddir->certs.virtual_address || !ddir->certs.size) {
101 pr_debug("Unsigned PE binary\n");
102 return -EKEYREJECTED;
103 }
104
105 chkaddr(ctx->header_size, ddir->certs.virtual_address,
106 ddir->certs.size);
107 ctx->sig_offset = ddir->certs.virtual_address;
108 ctx->sig_len = ddir->certs.size;
109 pr_debug("cert = %x @%x [%*ph]\n",
110 ctx->sig_len, ctx->sig_offset,
111 ctx->sig_len, pebuf + ctx->sig_offset);
112
113 ctx->n_sections = pe->sections;
114 if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
115 return -ELIBBAD;
116 ctx->secs = secs = pebuf + cursor;
117
118 return 0;
119}
120
121/**
122 * verify_pefile_signature - Verify the signature on a PE binary image
123 * @pebuf: Buffer containing the PE binary image
124 * @pelen: Length of the binary image
125 * @trust_keyring: Signing certificates to use as starting points
126 * @_trusted: Set to true if trustworth, false otherwise
127 *
128 * Validate that the certificate chain inside the PKCS#7 message inside the PE
129 * binary image intersects keys we already know and trust.
130 *
131 * Returns, in order of descending priority:
132 *
133 * (*) -ELIBBAD if the image cannot be parsed, or:
134 *
135 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid
136 * key, or:
137 *
138 * (*) 0 if at least one signature chain intersects with the keys in the trust
139 * keyring, or:
140 *
141 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
142 * chain.
143 *
144 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in
145 * the message.
146 *
147 * May also return -ENOMEM.
148 */
149int verify_pefile_signature(const void *pebuf, unsigned pelen,
150 struct key *trusted_keyring, bool *_trusted)
151{
152 struct pefile_context ctx;
153 int ret;
154
155 kenter("");
156
157 memset(&ctx, 0, sizeof(ctx));
158 ret = pefile_parse_binary(pebuf, pelen, &ctx);
159 if (ret < 0)
160 return ret;
161
162 return -ENOANO; // Not yet complete
163}