Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/asymmetric_keys/verify_pefile.c
26282 views
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 ([email protected])
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
*/
22
static 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 *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 != IMAGE_DOS_SIGNATURE)
44
return -ELIBBAD;
45
cursor = sizeof(*mz);
46
47
chkaddr(cursor, mz->peaddr, sizeof(*pe));
48
pe = pebuf + mz->peaddr;
49
if (pe->magic != IMAGE_NT_SIGNATURE)
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 IMAGE_NT_OPTIONAL_HDR32_MAGIC:
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 IMAGE_NT_OPTIONAL_HDR64_MAGIC:
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_warn("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_warn("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 = 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
*/
122
static 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_warn("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
/* sbsign rounds up the length of certificate table (in optional
139
* header data directories) to 8 byte alignment. However, the PE
140
* specification states that while entries are 8-byte aligned, this is
141
* not included in their length, and as a result, pesign has not
142
* rounded up since 0.110.
143
*/
144
if (wrapper.length > ctx->sig_len) {
145
pr_warn("Signature wrapper bigger than sig len (%x > %x)\n",
146
ctx->sig_len, wrapper.length);
147
return -ELIBBAD;
148
}
149
if (wrapper.revision != WIN_CERT_REVISION_2_0) {
150
pr_warn("Signature is not revision 2.0\n");
151
return -ENOTSUPP;
152
}
153
if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
154
pr_warn("Signature certificate type is not PKCS\n");
155
return -ENOTSUPP;
156
}
157
158
/* It looks like the pkcs signature length in wrapper->length and the
159
* size obtained from the data dir entries, which lists the total size
160
* of certificate table, are both aligned to an octaword boundary, so
161
* we may have to deal with some padding.
162
*/
163
ctx->sig_len = wrapper.length;
164
ctx->sig_offset += sizeof(wrapper);
165
ctx->sig_len -= sizeof(wrapper);
166
if (ctx->sig_len < 4) {
167
pr_warn("Signature data missing\n");
168
return -EKEYREJECTED;
169
}
170
171
/* What's left should be a PKCS#7 cert */
172
pkcs7 = pebuf + ctx->sig_offset;
173
if (pkcs7[0] != (ASN1_CONS_BIT | ASN1_SEQ))
174
goto not_pkcs7;
175
176
switch (pkcs7[1]) {
177
case 0 ... 0x7f:
178
len = pkcs7[1] + 2;
179
goto check_len;
180
case ASN1_INDEFINITE_LENGTH:
181
return 0;
182
case 0x81:
183
len = pkcs7[2] + 3;
184
goto check_len;
185
case 0x82:
186
len = ((pkcs7[2] << 8) | pkcs7[3]) + 4;
187
goto check_len;
188
case 0x83 ... 0xff:
189
return -EMSGSIZE;
190
default:
191
goto not_pkcs7;
192
}
193
194
check_len:
195
if (len <= ctx->sig_len) {
196
/* There may be padding */
197
ctx->sig_len = len;
198
return 0;
199
}
200
not_pkcs7:
201
pr_warn("Signature data not PKCS#7\n");
202
return -ELIBBAD;
203
}
204
205
/*
206
* Compare two sections for canonicalisation.
207
*/
208
static int pefile_compare_shdrs(const void *a, const void *b)
209
{
210
const struct section_header *shdra = a;
211
const struct section_header *shdrb = b;
212
int rc;
213
214
if (shdra->data_addr > shdrb->data_addr)
215
return 1;
216
if (shdrb->data_addr > shdra->data_addr)
217
return -1;
218
219
if (shdra->virtual_address > shdrb->virtual_address)
220
return 1;
221
if (shdrb->virtual_address > shdra->virtual_address)
222
return -1;
223
224
rc = strcmp(shdra->name, shdrb->name);
225
if (rc != 0)
226
return rc;
227
228
if (shdra->virtual_size > shdrb->virtual_size)
229
return 1;
230
if (shdrb->virtual_size > shdra->virtual_size)
231
return -1;
232
233
if (shdra->raw_data_size > shdrb->raw_data_size)
234
return 1;
235
if (shdrb->raw_data_size > shdra->raw_data_size)
236
return -1;
237
238
return 0;
239
}
240
241
/*
242
* Load the contents of the PE binary into the digest, leaving out the image
243
* checksum and the certificate data block.
244
*/
245
static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
246
struct pefile_context *ctx,
247
struct shash_desc *desc)
248
{
249
unsigned *canon, tmp, loop, i, hashed_bytes;
250
int ret;
251
252
/* Digest the header and data directory, but leave out the image
253
* checksum and the data dirent for the signature.
254
*/
255
ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
256
if (ret < 0)
257
return ret;
258
259
tmp = ctx->image_checksum_offset + sizeof(uint32_t);
260
ret = crypto_shash_update(desc, pebuf + tmp,
261
ctx->cert_dirent_offset - tmp);
262
if (ret < 0)
263
return ret;
264
265
tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
266
ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
267
if (ret < 0)
268
return ret;
269
270
canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
271
if (!canon)
272
return -ENOMEM;
273
274
/* We have to canonicalise the section table, so we perform an
275
* insertion sort.
276
*/
277
canon[0] = 0;
278
for (loop = 1; loop < ctx->n_sections; loop++) {
279
for (i = 0; i < loop; i++) {
280
if (pefile_compare_shdrs(&ctx->secs[canon[i]],
281
&ctx->secs[loop]) > 0) {
282
memmove(&canon[i + 1], &canon[i],
283
(loop - i) * sizeof(canon[0]));
284
break;
285
}
286
}
287
canon[i] = loop;
288
}
289
290
hashed_bytes = ctx->header_size;
291
for (loop = 0; loop < ctx->n_sections; loop++) {
292
i = canon[loop];
293
if (ctx->secs[i].raw_data_size == 0)
294
continue;
295
ret = crypto_shash_update(desc,
296
pebuf + ctx->secs[i].data_addr,
297
ctx->secs[i].raw_data_size);
298
if (ret < 0) {
299
kfree(canon);
300
return ret;
301
}
302
hashed_bytes += ctx->secs[i].raw_data_size;
303
}
304
kfree(canon);
305
306
if (pelen > hashed_bytes) {
307
tmp = hashed_bytes + ctx->certs_size;
308
ret = crypto_shash_update(desc,
309
pebuf + hashed_bytes,
310
pelen - tmp);
311
if (ret < 0)
312
return ret;
313
}
314
315
return 0;
316
}
317
318
/*
319
* Digest the contents of the PE binary, leaving out the image checksum and the
320
* certificate data block.
321
*/
322
static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
323
struct pefile_context *ctx)
324
{
325
struct crypto_shash *tfm;
326
struct shash_desc *desc;
327
size_t digest_size, desc_size;
328
void *digest;
329
int ret;
330
331
kenter(",%s", ctx->digest_algo);
332
333
/* Allocate the hashing algorithm we're going to need and find out how
334
* big the hash operational data will be.
335
*/
336
tfm = crypto_alloc_shash(ctx->digest_algo, 0, 0);
337
if (IS_ERR(tfm))
338
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
339
340
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
341
digest_size = crypto_shash_digestsize(tfm);
342
343
if (digest_size != ctx->digest_len) {
344
pr_warn("Digest size mismatch (%zx != %x)\n",
345
digest_size, ctx->digest_len);
346
ret = -EBADMSG;
347
goto error_no_desc;
348
}
349
pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
350
351
ret = -ENOMEM;
352
desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
353
if (!desc)
354
goto error_no_desc;
355
356
desc->tfm = tfm;
357
ret = crypto_shash_init(desc);
358
if (ret < 0)
359
goto error;
360
361
ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
362
if (ret < 0)
363
goto error;
364
365
digest = (void *)desc + desc_size;
366
ret = crypto_shash_final(desc, digest);
367
if (ret < 0)
368
goto error;
369
370
pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
371
372
/* Check that the PE file digest matches that in the MSCODE part of the
373
* PKCS#7 certificate.
374
*/
375
if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
376
pr_warn("Digest mismatch\n");
377
ret = -EKEYREJECTED;
378
} else {
379
pr_debug("The digests match!\n");
380
}
381
382
error:
383
kfree_sensitive(desc);
384
error_no_desc:
385
crypto_free_shash(tfm);
386
kleave(" = %d", ret);
387
return ret;
388
}
389
390
/**
391
* verify_pefile_signature - Verify the signature on a PE binary image
392
* @pebuf: Buffer containing the PE binary image
393
* @pelen: Length of the binary image
394
* @trusted_keys: Signing certificate(s) to use as starting points
395
* @usage: The use to which the key is being put.
396
*
397
* Validate that the certificate chain inside the PKCS#7 message inside the PE
398
* binary image intersects keys we already know and trust.
399
*
400
* Returns, in order of descending priority:
401
*
402
* (*) -ELIBBAD if the image cannot be parsed, or:
403
*
404
* (*) -EKEYREJECTED if a signature failed to match for which we have a valid
405
* key, or:
406
*
407
* (*) 0 if at least one signature chain intersects with the keys in the trust
408
* keyring, or:
409
*
410
* (*) -ENODATA if there is no signature present.
411
*
412
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
413
* chain.
414
*
415
* (*) -ENOKEY if we couldn't find a match for any of the signature chains in
416
* the message.
417
*
418
* May also return -ENOMEM.
419
*/
420
int verify_pefile_signature(const void *pebuf, unsigned pelen,
421
struct key *trusted_keys,
422
enum key_being_used_for usage)
423
{
424
struct pefile_context ctx;
425
int ret;
426
427
kenter("");
428
429
memset(&ctx, 0, sizeof(ctx));
430
ret = pefile_parse_binary(pebuf, pelen, &ctx);
431
if (ret < 0)
432
return ret;
433
434
ret = pefile_strip_sig_wrapper(pebuf, &ctx);
435
if (ret < 0)
436
return ret;
437
438
ret = verify_pkcs7_signature(NULL, 0,
439
pebuf + ctx.sig_offset, ctx.sig_len,
440
trusted_keys, usage,
441
mscode_parse, &ctx);
442
if (ret < 0)
443
goto error;
444
445
pr_debug("Digest: %u [%*ph]\n",
446
ctx.digest_len, ctx.digest_len, ctx.digest);
447
448
/* Generate the digest and check against the PKCS7 certificate
449
* contents.
450
*/
451
ret = pefile_digest_pe(pebuf, pelen, &ctx);
452
453
error:
454
kfree_sensitive(ctx.digest);
455
return ret;
456
}
457
458