blob: 6a261ff549dc3577515e8f6c6fa2a6ea792fc85a [file] [log] [blame]
AKASHI Takahirofab430b2020-11-30 18:12:15 +09001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2018 Linaro Limited
4 * Author: AKASHI Takahiro
5 */
6
7#include <getopt.h>
AKASHI Takahiro16abff22022-02-09 19:10:35 +09008#include <pe.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +09009#include <stdbool.h>
AKASHI Takahiro9e637862022-01-18 13:39:45 +090010#include <stdint.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +090011#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <linux/types.h>
Sughosh Ganu322c8132020-12-30 19:26:59 +053015
AKASHI Takahirofab430b2020-11-30 18:12:15 +090016#include <sys/stat.h>
17#include <sys/types.h>
AKASHI Takahirod9612f42022-02-09 19:10:39 +090018#include <uuid/uuid.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +090019
AKASHI Takahiro16abff22022-02-09 19:10:35 +090020#include <gnutls/gnutls.h>
21#include <gnutls/pkcs7.h>
22#include <gnutls/abstract.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +090023
AKASHI Takahiro16abff22022-02-09 19:10:35 +090024#include "eficapsule.h"
AKASHI Takahirofab430b2020-11-30 18:12:15 +090025
26static const char *tool_name = "mkeficapsule";
27
28efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
AKASHI Takahiro16abff22022-02-09 19:10:35 +090029efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
30
Sughosh Ganu69840772023-10-10 14:40:54 +053031static const char *opts_short = "g:i:I:v:p:c:m:o:dhARD";
Sughosh Ganu6da92712022-10-21 18:16:06 +053032
33enum {
34 CAPSULE_NORMAL_BLOB = 0,
35 CAPSULE_ACCEPT,
36 CAPSULE_REVERT,
37} capsule_type;
AKASHI Takahirofab430b2020-11-30 18:12:15 +090038
39static struct option options[] = {
AKASHI Takahirod9612f42022-02-09 19:10:39 +090040 {"guid", required_argument, NULL, 'g'},
AKASHI Takahirofab430b2020-11-30 18:12:15 +090041 {"index", required_argument, NULL, 'i'},
42 {"instance", required_argument, NULL, 'I'},
Masahisa Kojima000806f2023-06-07 14:41:56 +090043 {"fw-version", required_argument, NULL, 'v'},
AKASHI Takahiro16abff22022-02-09 19:10:35 +090044 {"private-key", required_argument, NULL, 'p'},
45 {"certificate", required_argument, NULL, 'c'},
46 {"monotonic-count", required_argument, NULL, 'm'},
47 {"dump-sig", no_argument, NULL, 'd'},
Sughosh Ganu6da92712022-10-21 18:16:06 +053048 {"fw-accept", no_argument, NULL, 'A'},
49 {"fw-revert", no_argument, NULL, 'R'},
Sughosh Ganuf65ee992022-10-21 18:16:07 +053050 {"capoemflag", required_argument, NULL, 'o'},
Sughosh Ganu69840772023-10-10 14:40:54 +053051 {"dump-capsule", no_argument, NULL, 'D'},
AKASHI Takahirofab430b2020-11-30 18:12:15 +090052 {"help", no_argument, NULL, 'h'},
53 {NULL, 0, NULL, 0},
54};
55
56static void print_usage(void)
57{
AKASHI Takahirod9612f42022-02-09 19:10:39 +090058 fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
AKASHI Takahiro9e637862022-01-18 13:39:45 +090059 "Options:\n"
Sughosh Ganu322c8132020-12-30 19:26:59 +053060
AKASHI Takahirod9612f42022-02-09 19:10:39 +090061 "\t-g, --guid <guid string> guid for image blob type\n"
AKASHI Takahiro9e637862022-01-18 13:39:45 +090062 "\t-i, --index <index> update image index\n"
63 "\t-I, --instance <instance> update hardware instance\n"
Masahisa Kojima000806f2023-06-07 14:41:56 +090064 "\t-v, --fw-version <version> firmware version\n"
AKASHI Takahiro16abff22022-02-09 19:10:35 +090065 "\t-p, --private-key <privkey file> private key file\n"
66 "\t-c, --certificate <cert file> signer's certificate file\n"
67 "\t-m, --monotonic-count <count> monotonic count\n"
68 "\t-d, --dump_sig dump signature (*.p7)\n"
Sughosh Ganu6da92712022-10-21 18:16:06 +053069 "\t-A, --fw-accept firmware accept capsule, requires GUID, no image blob\n"
70 "\t-R, --fw-revert firmware revert capsule, takes no GUID, no image blob\n"
Sughosh Ganuf65ee992022-10-21 18:16:07 +053071 "\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n"
Sughosh Ganu69840772023-10-10 14:40:54 +053072 "\t-D, --dump-capsule dump the contents of the capsule headers\n"
AKASHI Takahiro9e637862022-01-18 13:39:45 +090073 "\t-h, --help print a help message\n",
74 tool_name);
AKASHI Takahirofab430b2020-11-30 18:12:15 +090075}
76
AKASHI Takahiro9e637862022-01-18 13:39:45 +090077/**
AKASHI Takahiro16abff22022-02-09 19:10:35 +090078 * auth_context - authentication context
79 * @key_file: Path to a private key file
80 * @cert_file: Path to a certificate file
81 * @image_data: Pointer to firmware data
82 * @image_size: Size of firmware data
83 * @auth: Authentication header
84 * @sig_data: Signature data
85 * @sig_size: Size of signature data
86 *
87 * Data structure used in create_auth_data(). @key_file through
88 * @image_size are input parameters. @auth, @sig_data and @sig_size
89 * are filled in by create_auth_data().
90 */
91struct auth_context {
92 char *key_file;
93 char *cert_file;
94 uint8_t *image_data;
95 size_t image_size;
96 struct efi_firmware_image_authentication auth;
97 uint8_t *sig_data;
98 size_t sig_size;
99};
100
101static int dump_sig;
102
103/**
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900104 * read_bin_file - read a firmware binary file
105 * @bin: Path to a firmware binary file
106 * @data: Pointer to pointer of allocated buffer
107 * @bin_size: Size of allocated buffer
108 *
109 * Read out a content of binary, @bin, into @data.
110 * A caller should free @data.
111 *
112 * Return:
113 * * 0 - on success
114 * * -1 - on failure
115 */
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900116static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size)
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900117{
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900118 FILE *g;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900119 struct stat bin_stat;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900120 void *buf;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900121 size_t size;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900122 int ret = 0;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900123
124 g = fopen(bin, "r");
125 if (!g) {
AKASHI Takahirodf1ce602022-01-18 13:39:44 +0900126 fprintf(stderr, "cannot open %s\n", bin);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900127 return -1;
128 }
129 if (stat(bin, &bin_stat) < 0) {
AKASHI Takahirodf1ce602022-01-18 13:39:44 +0900130 fprintf(stderr, "cannot determine the size of %s\n", bin);
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900131 ret = -1;
132 goto err;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900133 }
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900134 if (bin_stat.st_size > SIZE_MAX) {
135 fprintf(stderr, "file size is too large for malloc: %s\n", bin);
136 ret = -1;
137 goto err;
138 }
139 buf = malloc(bin_stat.st_size);
140 if (!buf) {
AKASHI Takahirodf1ce602022-01-18 13:39:44 +0900141 fprintf(stderr, "cannot allocate memory: %zx\n",
142 (size_t)bin_stat.st_size);
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900143 ret = -1;
144 goto err;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900145 }
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900146
147 size = fread(buf, 1, bin_stat.st_size, g);
148 if (size < bin_stat.st_size) {
149 fprintf(stderr, "read failed (%zx)\n", size);
150 ret = -1;
151 goto err;
152 }
153
154 *data = buf;
155 *bin_size = bin_stat.st_size;
156err:
157 fclose(g);
158
159 return ret;
160}
161
162/**
163 * write_capsule_file - write a capsule file
164 * @bin: FILE stream
165 * @data: Pointer to data
166 * @bin_size: Size of data
167 *
168 * Write out data, @data, with the size @bin_size.
169 *
170 * Return:
171 * * 0 - on success
172 * * -1 - on failure
173 */
174static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg)
175{
176 size_t size_written;
177
178 size_written = fwrite(data, 1, size, f);
179 if (size_written < size) {
180 fprintf(stderr, "%s: write failed (%zx != %zx)\n", msg,
181 size_written, size);
182 return -1;
183 }
184
185 return 0;
186}
187
188/**
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900189 * create_auth_data - compose authentication data in capsule
190 * @auth_context: Pointer to authentication context
191 *
192 * Fill up an authentication header (.auth) and signature data (.sig_data)
193 * in @auth_context, using library functions from openssl.
194 * All the parameters in @auth_context must be filled in by a caller.
195 *
196 * Return:
197 * * 0 - on success
198 * * -1 - on failure
199 */
200static int create_auth_data(struct auth_context *ctx)
201{
202 gnutls_datum_t cert;
203 gnutls_datum_t key;
204 off_t file_size;
205 gnutls_privkey_t pkey;
206 gnutls_x509_crt_t x509;
207 gnutls_pkcs7_t pkcs7;
208 gnutls_datum_t data;
209 gnutls_datum_t signature;
210 int ret;
211
212 ret = read_bin_file(ctx->cert_file, &cert.data, &file_size);
213 if (ret < 0)
214 return -1;
215 if (file_size > UINT_MAX)
216 return -1;
217 cert.size = file_size;
218
219 ret = read_bin_file(ctx->key_file, &key.data, &file_size);
220 if (ret < 0)
221 return -1;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900222 if (file_size > UINT_MAX)
223 return -1;
224 key.size = file_size;
225
226 /*
227 * For debugging,
228 * gnutls_global_set_time_function(mytime);
229 * gnutls_global_set_log_function(tls_log_func);
230 * gnutls_global_set_log_level(6);
231 */
232
233 ret = gnutls_privkey_init(&pkey);
234 if (ret < 0) {
235 fprintf(stderr, "error in gnutls_privkey_init(): %s\n",
236 gnutls_strerror(ret));
237 return -1;
238 }
239
240 ret = gnutls_x509_crt_init(&x509);
241 if (ret < 0) {
242 fprintf(stderr, "error in gnutls_x509_crt_init(): %s\n",
243 gnutls_strerror(ret));
244 return -1;
245 }
246
247 /* load a private key */
248 ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM,
249 0, 0);
250 if (ret < 0) {
251 fprintf(stderr,
252 "error in gnutls_privkey_import_x509_raw(): %s\n",
253 gnutls_strerror(ret));
254 return -1;
255 }
256
257 /* load x509 certificate */
258 ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM);
259 if (ret < 0) {
260 fprintf(stderr, "error in gnutls_x509_crt_import(): %s\n",
261 gnutls_strerror(ret));
262 return -1;
263 }
264
265 /* generate a PKCS #7 structure */
266 ret = gnutls_pkcs7_init(&pkcs7);
267 if (ret < 0) {
268 fprintf(stderr, "error in gnutls_pkcs7_init(): %s\n",
269 gnutls_strerror(ret));
270 return -1;
271 }
272
273 /* sign */
274 /*
275 * Data should have
276 * * firmware image
277 * * monotonic count
278 * in this order!
279 * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
280 */
281 data.size = ctx->image_size + sizeof(ctx->auth.monotonic_count);
282 data.data = malloc(data.size);
283 if (!data.data) {
284 fprintf(stderr, "allocating memory (0x%x) failed\n", data.size);
285 return -1;
286 }
287 memcpy(data.data, ctx->image_data, ctx->image_size);
288 memcpy(data.data + ctx->image_size, &ctx->auth.monotonic_count,
289 sizeof(ctx->auth.monotonic_count));
290
291 ret = gnutls_pkcs7_sign(pkcs7, x509, pkey, &data, NULL, NULL,
292 GNUTLS_DIG_SHA256,
293 /* GNUTLS_PKCS7_EMBED_DATA? */
294 GNUTLS_PKCS7_INCLUDE_CERT |
295 GNUTLS_PKCS7_INCLUDE_TIME);
296 if (ret < 0) {
297 fprintf(stderr, "error in gnutls_pkcs7)sign(): %s\n",
298 gnutls_strerror(ret));
299 return -1;
300 }
301
302 /* export */
303 ret = gnutls_pkcs7_export2(pkcs7, GNUTLS_X509_FMT_DER, &signature);
304 if (ret < 0) {
305 fprintf(stderr, "error in gnutls_pkcs7_export2: %s\n",
306 gnutls_strerror(ret));
307 return -1;
308 }
309 ctx->sig_data = signature.data;
310 ctx->sig_size = signature.size;
311
312 /* fill auth_info */
313 ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
314 + ctx->sig_size;
315 ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
316 ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
317 memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
318 sizeof(efi_guid_cert_type_pkcs7));
319
320 /*
321 * For better clean-ups,
322 * gnutls_pkcs7_deinit(pkcs7);
323 * gnutls_privkey_deinit(pkey);
324 * gnutls_x509_crt_deinit(x509);
325 * free(cert.data);
326 * free(key.data);
327 * if error
328 * gnutls_free(signature.data);
329 */
330
331 return 0;
332}
333
334/**
335 * dump_signature - dump out a signature
336 * @path: Path to a capsule file
337 * @signature: Signature data
338 * @sig_size: Size of signature data
339 *
340 * Signature data pointed to by @signature will be saved into
341 * a file whose file name is @path with ".p7" suffix.
342 *
343 * Return:
344 * * 0 - on success
345 * * -1 - on failure
346 */
347static int dump_signature(const char *path, uint8_t *signature, size_t sig_size)
348{
349 char *sig_path;
350 FILE *f;
351 size_t size;
352 int ret = -1;
353
354 sig_path = malloc(strlen(path) + 3 + 1);
355 if (!sig_path)
356 return ret;
357
358 sprintf(sig_path, "%s.p7", path);
359 f = fopen(sig_path, "w");
360 if (!f)
361 goto err;
362
363 size = fwrite(signature, 1, sig_size, f);
364 if (size == sig_size)
365 ret = 0;
366
367 fclose(f);
368err:
369 free(sig_path);
370 return ret;
371}
372
373/**
374 * free_sig_data - free out signature data
375 * @ctx: Pointer to authentication context
376 *
377 * Free signature data allocated in create_auth_data().
378 */
379static void free_sig_data(struct auth_context *ctx)
380{
381 if (ctx->sig_size)
382 gnutls_free(ctx->sig_data);
383}
384
385/**
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900386 * create_fwbin - create an uefi capsule file
387 * @path: Path to a created capsule file
388 * @bin: Path to a firmware binary to encapsulate
389 * @guid: GUID of related FMP driver
390 * @index: Index number in capsule
391 * @instance: Instance number in capsule
392 * @mcount: Monotonic count in authentication information
393 * @private_file: Path to a private key file
394 * @cert_file: Path to a certificate file
Sughosh Ganuf65ee992022-10-21 18:16:07 +0530395 * @oemflags: Capsule OEM Flags, bits 0-15
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900396 *
397 * This function actually does the job of creating an uefi capsule file.
398 * All the arguments must be supplied.
399 * If either @private_file ror @cert_file is NULL, the capsule file
400 * won't be signed.
401 *
402 * Return:
403 * * 0 - on success
404 * * -1 - on failure
405 */
406static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900407 unsigned long index, unsigned long instance,
Masahisa Kojima000806f2023-06-07 14:41:56 +0900408 struct fmp_payload_header_params *fmp_ph_params,
Sughosh Ganuf65ee992022-10-21 18:16:07 +0530409 uint64_t mcount, char *privkey_file, char *cert_file,
410 uint16_t oemflags)
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900411{
412 struct efi_capsule_header header;
413 struct efi_firmware_management_capsule_header capsule;
414 struct efi_firmware_management_capsule_image_header image;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900415 struct auth_context auth_context;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900416 FILE *f;
Masahisa Kojima000806f2023-06-07 14:41:56 +0900417 uint8_t *data, *new_data, *buf;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900418 off_t bin_size;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900419 uint64_t offset;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900420 int ret;
Masahisa Kojima000806f2023-06-07 14:41:56 +0900421 struct fmp_payload_header payload_header;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900422
423#ifdef DEBUG
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900424 fprintf(stderr, "For output: %s\n", path);
425 fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid);
426 fprintf(stderr, "\tindex: %lu\n\tinstance: %lu\n", index, instance);
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900427#endif
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900428 auth_context.sig_size = 0;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900429 f = NULL;
430 data = NULL;
Masahisa Kojima000806f2023-06-07 14:41:56 +0900431 new_data = NULL;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900432 ret = -1;
433
434 /*
435 * read a firmware binary
436 */
437 if (read_bin_file(bin, &data, &bin_size))
438 goto err;
439
Masahisa Kojima000806f2023-06-07 14:41:56 +0900440 buf = data;
441
442 /* insert fmp payload header right before the payload */
443 if (fmp_ph_params->have_header) {
444 new_data = malloc(bin_size + sizeof(payload_header));
445 if (!new_data)
446 goto err;
447
448 payload_header.signature = FMP_PAYLOAD_HDR_SIGNATURE;
449 payload_header.header_size = sizeof(payload_header);
450 payload_header.fw_version = fmp_ph_params->fw_version;
451 payload_header.lowest_supported_version = 0; /* not used */
452 memcpy(new_data, &payload_header, sizeof(payload_header));
453 memcpy(new_data + sizeof(payload_header), data, bin_size);
454 buf = new_data;
455 bin_size += sizeof(payload_header);
456 }
457
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900458 /* first, calculate signature to determine its size */
459 if (privkey_file && cert_file) {
460 auth_context.key_file = privkey_file;
461 auth_context.cert_file = cert_file;
462 auth_context.auth.monotonic_count = mcount;
Masahisa Kojima000806f2023-06-07 14:41:56 +0900463 auth_context.image_data = buf;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900464 auth_context.image_size = bin_size;
465
466 if (create_auth_data(&auth_context)) {
467 fprintf(stderr, "Signing firmware image failed\n");
468 goto err;
469 }
470
471 if (dump_sig &&
472 dump_signature(path, auth_context.sig_data,
473 auth_context.sig_size)) {
474 fprintf(stderr, "Creating signature file failed\n");
475 goto err;
476 }
477 }
478
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900479 /*
480 * write a capsule file
481 */
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900482 f = fopen(path, "w");
483 if (!f) {
AKASHI Takahirodf1ce602022-01-18 13:39:44 +0900484 fprintf(stderr, "cannot open %s\n", path);
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900485 goto err;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900486 }
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900487
488 /*
489 * capsule file header
490 */
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900491 header.capsule_guid = efi_guid_fm_capsule;
492 header.header_size = sizeof(header);
AKASHI Takahiro450596f2020-11-30 18:12:16 +0900493 /* TODO: The current implementation ignores flags */
494 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
Sughosh Ganuf65ee992022-10-21 18:16:07 +0530495 if (oemflags)
496 header.flags |= oemflags;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900497 header.capsule_image_size = sizeof(header)
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900498 + sizeof(capsule) + sizeof(uint64_t)
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900499 + sizeof(image)
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900500 + bin_size;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900501 if (auth_context.sig_size)
502 header.capsule_image_size += sizeof(auth_context.auth)
503 + auth_context.sig_size;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900504 if (write_capsule_file(f, &header, sizeof(header),
505 "Capsule header"))
506 goto err;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900507
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900508 /*
509 * firmware capsule header
510 * This capsule has only one firmware capsule image.
511 */
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900512 capsule.version = 0x00000001;
513 capsule.embedded_driver_count = 0;
514 capsule.payload_item_count = 1;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900515 if (write_capsule_file(f, &capsule, sizeof(capsule),
516 "Firmware capsule header"))
517 goto err;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900518
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900519 offset = sizeof(capsule) + sizeof(uint64_t);
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900520 if (write_capsule_file(f, &offset, sizeof(offset),
521 "Offset to capsule image"))
522 goto err;
523
524 /*
525 * firmware capsule image header
526 */
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900527 image.version = 0x00000003;
528 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
529 image.update_image_index = index;
AKASHI Takahirof7cd8b72021-01-22 10:43:49 +0900530 image.reserved[0] = 0;
531 image.reserved[1] = 0;
532 image.reserved[2] = 0;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900533 image.update_image_size = bin_size;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900534 if (auth_context.sig_size)
535 image.update_image_size += sizeof(auth_context.auth)
536 + auth_context.sig_size;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900537 image.update_vendor_code_size = 0; /* none */
538 image.update_hardware_instance = instance;
539 image.image_capsule_support = 0;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900540 if (auth_context.sig_size)
541 image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900542 if (write_capsule_file(f, &image, sizeof(image),
543 "Firmware capsule image header"))
544 goto err;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900545
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900546 /*
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900547 * signature
548 */
549 if (auth_context.sig_size) {
550 if (write_capsule_file(f, &auth_context.auth,
551 sizeof(auth_context.auth),
552 "Authentication header"))
553 goto err;
554
555 if (write_capsule_file(f, auth_context.sig_data,
556 auth_context.sig_size, "Signature"))
557 goto err;
558 }
559
560 /*
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900561 * firmware binary
562 */
Masahisa Kojima000806f2023-06-07 14:41:56 +0900563 if (write_capsule_file(f, buf, bin_size, "Firmware binary"))
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900564 goto err;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900565
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900566 ret = 0;
567err:
568 if (f)
569 fclose(f);
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900570 free_sig_data(&auth_context);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900571 free(data);
Masahisa Kojima000806f2023-06-07 14:41:56 +0900572 free(new_data);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900573
AKASHI Takahiro9e637862022-01-18 13:39:45 +0900574 return ret;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900575}
576
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900577/**
AKASHI Takahirod9612f42022-02-09 19:10:39 +0900578 * convert_uuid_to_guid() - convert UUID to GUID
579 * @buf: UUID binary
580 *
581 * UUID and GUID have the same data structure, but their binary
582 * formats are different due to the endianness. See lib/uuid.c.
583 * Since uuid_parse() can handle only UUID, this function must
584 * be called to get correct data for GUID when parsing a string.
585 *
586 * The correct data will be returned in @buf.
587 */
588void convert_uuid_to_guid(unsigned char *buf)
589{
590 unsigned char c;
591
592 c = buf[0];
593 buf[0] = buf[3];
594 buf[3] = c;
595 c = buf[1];
596 buf[1] = buf[2];
597 buf[2] = c;
598
599 c = buf[4];
600 buf[4] = buf[5];
601 buf[5] = c;
602
603 c = buf[6];
604 buf[6] = buf[7];
605 buf[7] = c;
606}
607
Sughosh Ganu6da92712022-10-21 18:16:06 +0530608static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
609{
610 struct efi_capsule_header header = { 0 };
611 FILE *f = NULL;
612 int ret = -1;
613 efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
614 efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
615 efi_guid_t capsule_guid;
616
617 f = fopen(path, "w");
618 if (!f) {
619 fprintf(stderr, "cannot open %s\n", path);
620 goto err;
621 }
622
623 capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
624
625 memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
626 header.header_size = sizeof(header);
627 header.flags = 0;
628
629 header.capsule_image_size = fw_accept ?
630 sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
631
632 if (write_capsule_file(f, &header, sizeof(header),
633 "Capsule header"))
634 goto err;
635
636 if (fw_accept) {
637 if (write_capsule_file(f, guid, sizeof(*guid),
638 "FW Accept Capsule Payload"))
639 goto err;
640 }
641
642 ret = 0;
643
644err:
645 if (f)
646 fclose(f);
647
648 return ret;
649}
650
Sughosh Ganu69840772023-10-10 14:40:54 +0530651static void print_guid(void *ptr)
652{
653 int i;
654 efi_guid_t *guid = ptr;
655 const uint8_t seq[] = {
656 3, 2, 1, 0, '-', 5, 4, '-', 7, 6,
657 '-', 8, 9, '-', 10, 11, 12, 13, 14, 15 };
658
659 for (i = 0; i < ARRAY_SIZE(seq); i++) {
660 if (seq[i] == '-')
661 putchar(seq[i]);
662 else
663 printf("%02X", guid->b[seq[i]]);
664 }
665
666 printf("\n");
667}
668
669static uint32_t dump_fmp_payload_header(
670 struct fmp_payload_header *fmp_payload_hdr)
671{
672 if (fmp_payload_hdr->signature == FMP_PAYLOAD_HDR_SIGNATURE) {
673 printf("--------\n");
674 printf("FMP_PAYLOAD_HDR.SIGNATURE\t\t\t: %08X\n",
675 FMP_PAYLOAD_HDR_SIGNATURE);
676 printf("FMP_PAYLOAD_HDR.HEADER_SIZE\t\t\t: %08X\n",
677 fmp_payload_hdr->header_size);
678 printf("FMP_PAYLOAD_HDR.FW_VERSION\t\t\t: %08X\n",
679 fmp_payload_hdr->fw_version);
680 printf("FMP_PAYLOAD_HDR.LOWEST_SUPPORTED_VERSION\t: %08X\n",
681 fmp_payload_hdr->lowest_supported_version);
682 return fmp_payload_hdr->header_size;
683 }
684
685 return 0;
686}
687
688static void dump_capsule_auth_header(
689 struct efi_firmware_image_authentication *capsule_auth_hdr)
690{
691 printf("EFI_FIRMWARE_IMAGE_AUTH.MONOTONIC_COUNT\t\t: %08lX\n",
692 capsule_auth_hdr->monotonic_count);
693 printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.dwLENGTH\t: %08X\n",
694 capsule_auth_hdr->auth_info.hdr.dwLength);
695 printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION\t: %08X\n",
696 capsule_auth_hdr->auth_info.hdr.wRevision);
697 printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE\t: %08X\n",
698 capsule_auth_hdr->auth_info.hdr.wCertificateType);
699 printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE\t: ");
700 print_guid(&capsule_auth_hdr->auth_info.cert_type);
701}
702
703static void dump_fmp_capsule_image_header(
704 struct efi_firmware_management_capsule_image_header *image_hdr)
705{
706 void *capsule_auth_hdr;
707 void *fmp_payload_hdr;
708 uint64_t signature_size = 0;
709 uint32_t payload_size = 0;
710 uint32_t fmp_payload_hdr_size = 0;
711 struct efi_firmware_image_authentication *auth_hdr;
712
713 printf("--------\n");
714 printf("FMP_CAPSULE_IMAGE_HDR.VERSION\t\t\t: %08X\n",
715 image_hdr->version);
716 printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID\t: ");
717 print_guid(&image_hdr->update_image_type_id);
718 printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX\t: %08X\n",
719 image_hdr->update_image_index);
720 printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_SIZE\t\t: %08X\n",
721 image_hdr->update_image_size);
722 printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_VENDOR_CODE_SIZE\t: %08X\n",
723 image_hdr->update_vendor_code_size);
724 printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_HARDWARE_INSTANCE\t: %08lX\n",
725 image_hdr->update_hardware_instance);
726 printf("FMP_CAPSULE_IMAGE_HDR.IMAGE_CAPSULE_SUPPORT\t: %08lX\n",
727 image_hdr->image_capsule_support);
728
729 printf("--------\n");
730 if (image_hdr->image_capsule_support & CAPSULE_SUPPORT_AUTHENTICATION) {
731 capsule_auth_hdr = (char *)image_hdr + sizeof(*image_hdr);
732 dump_capsule_auth_header(capsule_auth_hdr);
733
734 auth_hdr = capsule_auth_hdr;
735 signature_size = sizeof(auth_hdr->monotonic_count) +
736 auth_hdr->auth_info.hdr.dwLength;
737 fmp_payload_hdr = (char *)capsule_auth_hdr + signature_size;
738 } else {
739 printf("Capsule Authentication Not Enabled\n");
740 fmp_payload_hdr = (char *)image_hdr + sizeof(*image_hdr);
741 }
742
743 fmp_payload_hdr_size = dump_fmp_payload_header(fmp_payload_hdr);
744
745 payload_size = image_hdr->update_image_size - signature_size -
746 fmp_payload_hdr_size;
747 printf("--------\n");
748 printf("Payload Image Size\t\t\t\t: %08X\n", payload_size);
749}
750
751static void dump_fmp_header(
752 struct efi_firmware_management_capsule_header *fmp_hdr)
753{
754 int i;
755 void *capsule_image_hdr;
756
757 printf("EFI_FMP_HDR.VERSION\t\t\t\t: %08X\n", fmp_hdr->version);
758 printf("EFI_FMP_HDR.EMBEDDED_DRIVER_COUNT\t\t: %08X\n",
759 fmp_hdr->embedded_driver_count);
760 printf("EFI_FMP_HDR.PAYLOAD_ITEM_COUNT\t\t\t: %08X\n",
761 fmp_hdr->payload_item_count);
762
763 /*
764 * We currently don't support Embedded Drivers.
765 * Only worry about the payload items.
766 */
767 for (i = 0; i < fmp_hdr->payload_item_count; i++) {
768 capsule_image_hdr = (char *)fmp_hdr +
769 fmp_hdr->item_offset_list[i];
770 dump_fmp_capsule_image_header(capsule_image_hdr);
771 }
772}
773
774static void dump_capsule_header(struct efi_capsule_header *capsule_hdr)
775{
776 printf("EFI_CAPSULE_HDR.CAPSULE_GUID\t\t\t: ");
777 print_guid((void *)&capsule_hdr->capsule_guid);
778 printf("EFI_CAPSULE_HDR.HEADER_SIZE\t\t\t: %08X\n",
779 capsule_hdr->header_size);
780 printf("EFI_CAPSULE_HDR.FLAGS\t\t\t\t: %08X\n", capsule_hdr->flags);
781 printf("EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE\t\t: %08X\n",
782 capsule_hdr->capsule_image_size);
783}
784
785static void normal_capsule_dump(void *capsule_buf)
786{
787 void *fmp_hdr;
788 struct efi_capsule_header *hdr = capsule_buf;
789
790 dump_capsule_header(hdr);
791 printf("--------\n");
792
793 fmp_hdr = (char *)capsule_buf + sizeof(*hdr);
794 dump_fmp_header(fmp_hdr);
795}
796
797static void empty_capsule_dump(void *capsule_buf)
798{
799 efi_guid_t *accept_image_guid;
800 struct efi_capsule_header *hdr = capsule_buf;
801 efi_guid_t efi_empty_accept_capsule = FW_ACCEPT_OS_GUID;
802
803 dump_capsule_header(hdr);
804
805 if (!memcmp(&efi_empty_accept_capsule, &hdr->capsule_guid,
806 sizeof(efi_guid_t))) {
807 accept_image_guid = (void *)(char *)capsule_buf +
808 sizeof(struct efi_capsule_header);
809 printf("--------\n");
810 printf("ACCEPT_IMAGE_GUID\t\t\t\t: ");
811 print_guid(accept_image_guid);
812 }
813}
814
815static void dump_capsule_contents(char *capsule_file)
816{
817 int fd;
818 char *ptr;
819 efi_guid_t efi_fmp_guid = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
820 efi_guid_t efi_empty_accept_capsule = FW_ACCEPT_OS_GUID;
821 efi_guid_t efi_empty_revert_capsule = FW_REVERT_OS_GUID;
822 struct stat sbuf;
823
824 if (!capsule_file) {
825 fprintf(stderr, "No capsule file provided\n");
826 exit(EXIT_FAILURE);
827 }
828
829 if ((fd = open(capsule_file, O_RDONLY)) < 0) {
830 fprintf(stderr, "Error opening capsule file: %s\n",
831 capsule_file);
832 exit(EXIT_FAILURE);
833 }
834
835 if (fstat(fd, &sbuf) < 0) {
836 fprintf(stderr, "Can't stat capsule file: %s\n", capsule_file);
837 exit(EXIT_FAILURE);
838 }
839
840 if ((ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0))
841 == MAP_FAILED) {
842 fprintf(stderr, "Can't mmap capsule file: %s\n", capsule_file);
843 exit(EXIT_FAILURE);
844 }
845
846 if (!memcmp(&efi_fmp_guid, ptr, sizeof(efi_guid_t))) {
847 normal_capsule_dump(ptr);
848 } else if (!memcmp(&efi_empty_accept_capsule, ptr,
849 sizeof(efi_guid_t)) ||
850 !memcmp(&efi_empty_revert_capsule, ptr,
851 sizeof(efi_guid_t))) {
852 empty_capsule_dump(ptr);
853 } else {
854 fprintf(stderr, "Unable to decode the capsule file: %s\n",
855 capsule_file);
856 exit(EXIT_FAILURE);
857 }
858}
859
AKASHI Takahirod9612f42022-02-09 19:10:39 +0900860/**
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900861 * main - main entry function of mkeficapsule
862 * @argc: Number of arguments
863 * @argv: Array of pointers to arguments
864 *
865 * Create an uefi capsule file, optionally signing it.
866 * Parse all the arguments and pass them on to create_fwbin().
867 *
868 * Return:
869 * * 0 - on success
870 * * -1 - on failure
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900871 */
872int main(int argc, char **argv)
873{
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900874 efi_guid_t *guid;
AKASHI Takahirod9612f42022-02-09 19:10:39 +0900875 unsigned char uuid_buf[16];
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900876 unsigned long index, instance;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900877 uint64_t mcount;
Sughosh Ganuf65ee992022-10-21 18:16:07 +0530878 unsigned long oemflags;
Sughosh Ganu69840772023-10-10 14:40:54 +0530879 bool capsule_dump;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900880 char *privkey_file, *cert_file;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900881 int c, idx;
Masahisa Kojima000806f2023-06-07 14:41:56 +0900882 struct fmp_payload_header_params fmp_ph_params = { 0 };
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900883
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900884 guid = NULL;
885 index = 0;
886 instance = 0;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900887 mcount = 0;
888 privkey_file = NULL;
889 cert_file = NULL;
Sughosh Ganu69840772023-10-10 14:40:54 +0530890 capsule_dump = false;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900891 dump_sig = 0;
Sughosh Ganu6da92712022-10-21 18:16:06 +0530892 capsule_type = CAPSULE_NORMAL_BLOB;
Sughosh Ganuf65ee992022-10-21 18:16:07 +0530893 oemflags = 0;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900894 for (;;) {
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900895 c = getopt_long(argc, argv, opts_short, options, &idx);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900896 if (c == -1)
897 break;
898
899 switch (c) {
AKASHI Takahirod9612f42022-02-09 19:10:39 +0900900 case 'g':
901 if (guid) {
902 fprintf(stderr,
903 "Image type already specified\n");
904 exit(EXIT_FAILURE);
905 }
906 if (uuid_parse(optarg, uuid_buf)) {
907 fprintf(stderr, "Wrong guid format\n");
908 exit(EXIT_FAILURE);
909 }
910 convert_uuid_to_guid(uuid_buf);
911 guid = (efi_guid_t *)uuid_buf;
912 break;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900913 case 'i':
914 index = strtoul(optarg, NULL, 0);
915 break;
916 case 'I':
917 instance = strtoul(optarg, NULL, 0);
918 break;
Masahisa Kojima000806f2023-06-07 14:41:56 +0900919 case 'v':
920 fmp_ph_params.fw_version = strtoul(optarg, NULL, 0);
921 fmp_ph_params.have_header = true;
922 break;
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900923 case 'p':
924 if (privkey_file) {
925 fprintf(stderr,
926 "Private Key already specified\n");
927 exit(EXIT_FAILURE);
928 }
929 privkey_file = optarg;
930 break;
931 case 'c':
932 if (cert_file) {
933 fprintf(stderr,
934 "Certificate file already specified\n");
935 exit(EXIT_FAILURE);
936 }
937 cert_file = optarg;
938 break;
939 case 'm':
940 mcount = strtoul(optarg, NULL, 0);
941 break;
942 case 'd':
943 dump_sig = 1;
944 break;
Sughosh Ganu6da92712022-10-21 18:16:06 +0530945 case 'A':
946 if (capsule_type) {
947 fprintf(stderr,
948 "Select either of Accept or Revert capsule generation\n");
949 exit(1);
950 }
951 capsule_type = CAPSULE_ACCEPT;
952 break;
953 case 'R':
954 if (capsule_type) {
955 fprintf(stderr,
956 "Select either of Accept or Revert capsule generation\n");
957 exit(1);
958 }
959 capsule_type = CAPSULE_REVERT;
960 break;
Sughosh Ganuf65ee992022-10-21 18:16:07 +0530961 case 'o':
962 oemflags = strtoul(optarg, NULL, 0);
963 if (oemflags > 0xffff) {
964 fprintf(stderr,
965 "oemflags must be between 0x0 and 0xffff\n");
966 exit(1);
967 }
968 break;
Sughosh Ganu69840772023-10-10 14:40:54 +0530969 case 'D':
970 capsule_dump = true;
971 break;
Sughosh Ganu6da92712022-10-21 18:16:06 +0530972 default:
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900973 print_usage();
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900974 exit(EXIT_SUCCESS);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900975 }
976 }
977
Sughosh Ganu69840772023-10-10 14:40:54 +0530978 if (capsule_dump) {
979 if (argc != optind + 1) {
980 fprintf(stderr, "Must provide the capsule file to parse\n");
981 exit(EXIT_FAILURE);
982 }
983 dump_capsule_contents(argv[argc - 1]);
984 exit(EXIT_SUCCESS);
985 }
986
AKASHI Takahiro16abff22022-02-09 19:10:35 +0900987 /* check necessary parameters */
Sughosh Ganu6da92712022-10-21 18:16:06 +0530988 if ((capsule_type == CAPSULE_NORMAL_BLOB &&
989 ((argc != optind + 2) || !guid ||
990 ((privkey_file && !cert_file) ||
991 (!privkey_file && cert_file)))) ||
992 (capsule_type != CAPSULE_NORMAL_BLOB &&
993 ((argc != optind + 1) ||
994 ((capsule_type == CAPSULE_ACCEPT) && !guid) ||
995 ((capsule_type == CAPSULE_REVERT) && guid)))) {
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900996 print_usage();
Sughosh Ganud33f3182021-01-22 20:34:56 +0530997 exit(EXIT_FAILURE);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900998 }
999
Sughosh Ganu6da92712022-10-21 18:16:06 +05301000 if (capsule_type != CAPSULE_NORMAL_BLOB) {
1001 if (create_empty_capsule(argv[argc - 1], guid,
1002 capsule_type == CAPSULE_ACCEPT) < 0) {
1003 fprintf(stderr, "Creating empty capsule failed\n");
1004 exit(EXIT_FAILURE);
1005 }
1006 } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
Masahisa Kojima000806f2023-06-07 14:41:56 +09001007 index, instance, &fmp_ph_params, mcount, privkey_file,
Sughosh Ganuf65ee992022-10-21 18:16:07 +05301008 cert_file, (uint16_t)oemflags) < 0) {
AKASHI Takahirodf1ce602022-01-18 13:39:44 +09001009 fprintf(stderr, "Creating firmware capsule failed\n");
Sughosh Ganud33f3182021-01-22 20:34:56 +05301010 exit(EXIT_FAILURE);
AKASHI Takahirofab430b2020-11-30 18:12:15 +09001011 }
1012
Sughosh Ganud33f3182021-01-22 20:34:56 +05301013 exit(EXIT_SUCCESS);
AKASHI Takahirofab430b2020-11-30 18:12:15 +09001014}