1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2018 Linaro Limited
4 * Author: AKASHI Takahiro
14 #include <linux/types.h>
17 #include <sys/types.h>
18 #include <uuid/uuid.h>
19 #include <linux/kconfig.h>
21 #include <gnutls/gnutls.h>
22 #include <gnutls/pkcs7.h>
23 #include <gnutls/abstract.h>
25 #include "eficapsule.h"
27 static const char *tool_name = "mkeficapsule";
29 efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
30 efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
32 static const char *opts_short = "g:i:I:v:p:c:m:o:dhAR";
35 CAPSULE_NORMAL_BLOB = 0,
40 static struct option options[] = {
41 {"guid", required_argument, NULL, 'g'},
42 {"index", required_argument, NULL, 'i'},
43 {"instance", required_argument, NULL, 'I'},
44 {"fw-version", required_argument, NULL, 'v'},
45 {"private-key", required_argument, NULL, 'p'},
46 {"certificate", required_argument, NULL, 'c'},
47 {"monotonic-count", required_argument, NULL, 'm'},
48 {"dump-sig", no_argument, NULL, 'd'},
49 {"fw-accept", no_argument, NULL, 'A'},
50 {"fw-revert", no_argument, NULL, 'R'},
51 {"capoemflag", required_argument, NULL, 'o'},
52 {"help", no_argument, NULL, 'h'},
56 static void print_usage(void)
58 fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
61 "\t-g, --guid <guid string> guid for image blob type\n"
62 "\t-i, --index <index> update image index\n"
63 "\t-I, --instance <instance> update hardware instance\n"
64 "\t-v, --fw-version <version> firmware version\n"
65 "\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"
69 "\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"
71 "\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n"
72 "\t-h, --help print a help message\n",
77 * auth_context - authentication context
78 * @key_file: Path to a private key file
79 * @cert_file: Path to a certificate file
80 * @image_data: Pointer to firmware data
81 * @image_size: Size of firmware data
82 * @auth: Authentication header
83 * @sig_data: Signature data
84 * @sig_size: Size of signature data
86 * Data structure used in create_auth_data(). @key_file through
87 * @image_size are input parameters. @auth, @sig_data and @sig_size
88 * are filled in by create_auth_data().
95 struct efi_firmware_image_authentication auth;
103 * read_bin_file - read a firmware binary file
104 * @bin: Path to a firmware binary file
105 * @data: Pointer to pointer of allocated buffer
106 * @bin_size: Size of allocated buffer
108 * Read out a content of binary, @bin, into @data.
109 * A caller should free @data.
115 static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size)
118 struct stat bin_stat;
125 fprintf(stderr, "cannot open %s\n", bin);
128 if (stat(bin, &bin_stat) < 0) {
129 fprintf(stderr, "cannot determine the size of %s\n", bin);
133 if (bin_stat.st_size > SIZE_MAX) {
134 fprintf(stderr, "file size is too large for malloc: %s\n", bin);
138 buf = malloc(bin_stat.st_size);
140 fprintf(stderr, "cannot allocate memory: %zx\n",
141 (size_t)bin_stat.st_size);
146 size = fread(buf, 1, bin_stat.st_size, g);
147 if (size < bin_stat.st_size) {
148 fprintf(stderr, "read failed (%zx)\n", size);
154 *bin_size = bin_stat.st_size;
162 * write_capsule_file - write a capsule file
164 * @data: Pointer to data
165 * @bin_size: Size of data
167 * Write out data, @data, with the size @bin_size.
173 static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg)
177 size_written = fwrite(data, 1, size, f);
178 if (size_written < size) {
179 fprintf(stderr, "%s: write failed (%zx != %zx)\n", msg,
188 * create_auth_data - compose authentication data in capsule
189 * @auth_context: Pointer to authentication context
191 * Fill up an authentication header (.auth) and signature data (.sig_data)
192 * in @auth_context, using library functions from openssl.
193 * All the parameters in @auth_context must be filled in by a caller.
199 static int create_auth_data(struct auth_context *ctx)
204 gnutls_privkey_t pkey;
205 gnutls_x509_crt_t x509;
206 gnutls_pkcs7_t pkcs7;
208 gnutls_datum_t signature;
211 ret = read_bin_file(ctx->cert_file, &cert.data, &file_size);
214 if (file_size > UINT_MAX)
216 cert.size = file_size;
218 ret = read_bin_file(ctx->key_file, &key.data, &file_size);
221 if (file_size > UINT_MAX)
223 key.size = file_size;
227 * gnutls_global_set_time_function(mytime);
228 * gnutls_global_set_log_function(tls_log_func);
229 * gnutls_global_set_log_level(6);
232 ret = gnutls_privkey_init(&pkey);
234 fprintf(stderr, "error in gnutls_privkey_init(): %s\n",
235 gnutls_strerror(ret));
239 ret = gnutls_x509_crt_init(&x509);
241 fprintf(stderr, "error in gnutls_x509_crt_init(): %s\n",
242 gnutls_strerror(ret));
246 /* load a private key */
247 ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM,
251 "error in gnutls_privkey_import_x509_raw(): %s\n",
252 gnutls_strerror(ret));
256 /* load x509 certificate */
257 ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM);
259 fprintf(stderr, "error in gnutls_x509_crt_import(): %s\n",
260 gnutls_strerror(ret));
264 /* generate a PKCS #7 structure */
265 ret = gnutls_pkcs7_init(&pkcs7);
267 fprintf(stderr, "error in gnutls_pkcs7_init(): %s\n",
268 gnutls_strerror(ret));
278 * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
280 data.size = ctx->image_size + sizeof(ctx->auth.monotonic_count);
281 data.data = malloc(data.size);
283 fprintf(stderr, "allocating memory (0x%x) failed\n", data.size);
286 memcpy(data.data, ctx->image_data, ctx->image_size);
287 memcpy(data.data + ctx->image_size, &ctx->auth.monotonic_count,
288 sizeof(ctx->auth.monotonic_count));
290 ret = gnutls_pkcs7_sign(pkcs7, x509, pkey, &data, NULL, NULL,
292 /* GNUTLS_PKCS7_EMBED_DATA? */
293 GNUTLS_PKCS7_INCLUDE_CERT |
294 GNUTLS_PKCS7_INCLUDE_TIME);
296 fprintf(stderr, "error in gnutls_pkcs7)sign(): %s\n",
297 gnutls_strerror(ret));
302 ret = gnutls_pkcs7_export2(pkcs7, GNUTLS_X509_FMT_DER, &signature);
304 fprintf(stderr, "error in gnutls_pkcs7_export2: %s\n",
305 gnutls_strerror(ret));
308 ctx->sig_data = signature.data;
309 ctx->sig_size = signature.size;
312 ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
314 ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
315 ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
316 memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
317 sizeof(efi_guid_cert_type_pkcs7));
320 * For better clean-ups,
321 * gnutls_pkcs7_deinit(pkcs7);
322 * gnutls_privkey_deinit(pkey);
323 * gnutls_x509_crt_deinit(x509);
327 * gnutls_free(signature.data);
334 * dump_signature - dump out a signature
335 * @path: Path to a capsule file
336 * @signature: Signature data
337 * @sig_size: Size of signature data
339 * Signature data pointed to by @signature will be saved into
340 * a file whose file name is @path with ".p7" suffix.
346 static int dump_signature(const char *path, uint8_t *signature, size_t sig_size)
353 sig_path = malloc(strlen(path) + 3 + 1);
357 sprintf(sig_path, "%s.p7", path);
358 f = fopen(sig_path, "w");
362 size = fwrite(signature, 1, sig_size, f);
363 if (size == sig_size)
373 * free_sig_data - free out signature data
374 * @ctx: Pointer to authentication context
376 * Free signature data allocated in create_auth_data().
378 static void free_sig_data(struct auth_context *ctx)
381 gnutls_free(ctx->sig_data);
385 * create_fwbin - create an uefi capsule file
386 * @path: Path to a created capsule file
387 * @bin: Path to a firmware binary to encapsulate
388 * @guid: GUID of related FMP driver
389 * @index: Index number in capsule
390 * @instance: Instance number in capsule
391 * @mcount: Monotonic count in authentication information
392 * @private_file: Path to a private key file
393 * @cert_file: Path to a certificate file
394 * @oemflags: Capsule OEM Flags, bits 0-15
396 * This function actually does the job of creating an uefi capsule file.
397 * All the arguments must be supplied.
398 * If either @private_file ror @cert_file is NULL, the capsule file
405 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
406 unsigned long index, unsigned long instance,
407 struct fmp_payload_header_params *fmp_ph_params,
408 uint64_t mcount, char *privkey_file, char *cert_file,
411 struct efi_capsule_header header;
412 struct efi_firmware_management_capsule_header capsule;
413 struct efi_firmware_management_capsule_image_header image;
414 struct auth_context auth_context;
416 uint8_t *data, *new_data, *buf;
420 struct fmp_payload_header payload_header;
423 fprintf(stderr, "For output: %s\n", path);
424 fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid);
425 fprintf(stderr, "\tindex: %lu\n\tinstance: %lu\n", index, instance);
427 auth_context.sig_size = 0;
434 * read a firmware binary
436 if (read_bin_file(bin, &data, &bin_size))
441 /* insert fmp payload header right before the payload */
442 if (fmp_ph_params->have_header) {
443 new_data = malloc(bin_size + sizeof(payload_header));
447 payload_header.signature = FMP_PAYLOAD_HDR_SIGNATURE;
448 payload_header.header_size = sizeof(payload_header);
449 payload_header.fw_version = fmp_ph_params->fw_version;
450 payload_header.lowest_supported_version = 0; /* not used */
451 memcpy(new_data, &payload_header, sizeof(payload_header));
452 memcpy(new_data + sizeof(payload_header), data, bin_size);
454 bin_size += sizeof(payload_header);
457 /* first, calculate signature to determine its size */
458 if (privkey_file && cert_file) {
459 auth_context.key_file = privkey_file;
460 auth_context.cert_file = cert_file;
461 auth_context.auth.monotonic_count = mcount;
462 auth_context.image_data = buf;
463 auth_context.image_size = bin_size;
465 if (create_auth_data(&auth_context)) {
466 fprintf(stderr, "Signing firmware image failed\n");
471 dump_signature(path, auth_context.sig_data,
472 auth_context.sig_size)) {
473 fprintf(stderr, "Creating signature file failed\n");
479 * write a capsule file
481 f = fopen(path, "w");
483 fprintf(stderr, "cannot open %s\n", path);
488 * capsule file header
490 header.capsule_guid = efi_guid_fm_capsule;
491 header.header_size = sizeof(header);
492 /* TODO: The current implementation ignores flags */
493 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
495 header.flags |= oemflags;
496 header.capsule_image_size = sizeof(header)
497 + sizeof(capsule) + sizeof(uint64_t)
500 if (auth_context.sig_size)
501 header.capsule_image_size += sizeof(auth_context.auth)
502 + auth_context.sig_size;
503 if (write_capsule_file(f, &header, sizeof(header),
508 * firmware capsule header
509 * This capsule has only one firmware capsule image.
511 capsule.version = 0x00000001;
512 capsule.embedded_driver_count = 0;
513 capsule.payload_item_count = 1;
514 if (write_capsule_file(f, &capsule, sizeof(capsule),
515 "Firmware capsule header"))
518 offset = sizeof(capsule) + sizeof(uint64_t);
519 if (write_capsule_file(f, &offset, sizeof(offset),
520 "Offset to capsule image"))
524 * firmware capsule image header
526 image.version = 0x00000003;
527 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
528 image.update_image_index = index;
529 image.reserved[0] = 0;
530 image.reserved[1] = 0;
531 image.reserved[2] = 0;
532 image.update_image_size = bin_size;
533 if (auth_context.sig_size)
534 image.update_image_size += sizeof(auth_context.auth)
535 + auth_context.sig_size;
536 image.update_vendor_code_size = 0; /* none */
537 image.update_hardware_instance = instance;
538 image.image_capsule_support = 0;
539 if (auth_context.sig_size)
540 image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
541 if (write_capsule_file(f, &image, sizeof(image),
542 "Firmware capsule image header"))
548 if (auth_context.sig_size) {
549 if (write_capsule_file(f, &auth_context.auth,
550 sizeof(auth_context.auth),
551 "Authentication header"))
554 if (write_capsule_file(f, auth_context.sig_data,
555 auth_context.sig_size, "Signature"))
562 if (write_capsule_file(f, buf, bin_size, "Firmware binary"))
569 free_sig_data(&auth_context);
577 * convert_uuid_to_guid() - convert UUID to GUID
580 * UUID and GUID have the same data structure, but their binary
581 * formats are different due to the endianness. See lib/uuid.c.
582 * Since uuid_parse() can handle only UUID, this function must
583 * be called to get correct data for GUID when parsing a string.
585 * The correct data will be returned in @buf.
587 void convert_uuid_to_guid(unsigned char *buf)
607 static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
609 struct efi_capsule_header header = { 0 };
612 efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
613 efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
614 efi_guid_t capsule_guid;
616 f = fopen(path, "w");
618 fprintf(stderr, "cannot open %s\n", path);
622 capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
624 memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
625 header.header_size = sizeof(header);
628 header.capsule_image_size = fw_accept ?
629 sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
631 if (write_capsule_file(f, &header, sizeof(header),
636 if (write_capsule_file(f, guid, sizeof(*guid),
637 "FW Accept Capsule Payload"))
651 * main - main entry function of mkeficapsule
652 * @argc: Number of arguments
653 * @argv: Array of pointers to arguments
655 * Create an uefi capsule file, optionally signing it.
656 * Parse all the arguments and pass them on to create_fwbin().
662 int main(int argc, char **argv)
665 unsigned char uuid_buf[16];
666 unsigned long index, instance;
668 unsigned long oemflags;
669 char *privkey_file, *cert_file;
671 struct fmp_payload_header_params fmp_ph_params = { 0 };
680 capsule_type = CAPSULE_NORMAL_BLOB;
683 c = getopt_long(argc, argv, opts_short, options, &idx);
691 "Image type already specified\n");
694 if (uuid_parse(optarg, uuid_buf)) {
695 fprintf(stderr, "Wrong guid format\n");
698 convert_uuid_to_guid(uuid_buf);
699 guid = (efi_guid_t *)uuid_buf;
702 index = strtoul(optarg, NULL, 0);
705 instance = strtoul(optarg, NULL, 0);
708 fmp_ph_params.fw_version = strtoul(optarg, NULL, 0);
709 fmp_ph_params.have_header = true;
714 "Private Key already specified\n");
717 privkey_file = optarg;
722 "Certificate file already specified\n");
728 mcount = strtoul(optarg, NULL, 0);
736 "Select either of Accept or Revert capsule generation\n");
739 capsule_type = CAPSULE_ACCEPT;
744 "Select either of Accept or Revert capsule generation\n");
747 capsule_type = CAPSULE_REVERT;
750 oemflags = strtoul(optarg, NULL, 0);
751 if (oemflags > 0xffff) {
753 "oemflags must be between 0x0 and 0xffff\n");
763 /* check necessary parameters */
764 if ((capsule_type == CAPSULE_NORMAL_BLOB &&
765 ((argc != optind + 2) || !guid ||
766 ((privkey_file && !cert_file) ||
767 (!privkey_file && cert_file)))) ||
768 (capsule_type != CAPSULE_NORMAL_BLOB &&
769 ((argc != optind + 1) ||
770 ((capsule_type == CAPSULE_ACCEPT) && !guid) ||
771 ((capsule_type == CAPSULE_REVERT) && guid)))) {
776 if (capsule_type != CAPSULE_NORMAL_BLOB) {
777 if (create_empty_capsule(argv[argc - 1], guid,
778 capsule_type == CAPSULE_ACCEPT) < 0) {
779 fprintf(stderr, "Creating empty capsule failed\n");
782 } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
783 index, instance, &fmp_ph_params, mcount, privkey_file,
784 cert_file, (uint16_t)oemflags) < 0) {
785 fprintf(stderr, "Creating firmware capsule failed\n");