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:dh";
34 static struct option options[] = {
35 {"guid", required_argument, NULL, 'g'},
36 {"index", required_argument, NULL, 'i'},
37 {"instance", required_argument, NULL, 'I'},
38 {"private-key", required_argument, NULL, 'p'},
39 {"certificate", required_argument, NULL, 'c'},
40 {"monotonic-count", required_argument, NULL, 'm'},
41 {"dump-sig", no_argument, NULL, 'd'},
42 {"help", no_argument, NULL, 'h'},
46 static void print_usage(void)
48 fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
51 "\t-g, --guid <guid string> guid for image blob type\n"
52 "\t-i, --index <index> update image index\n"
53 "\t-I, --instance <instance> update hardware instance\n"
54 "\t-p, --private-key <privkey file> private key file\n"
55 "\t-c, --certificate <cert file> signer's certificate file\n"
56 "\t-m, --monotonic-count <count> monotonic count\n"
57 "\t-d, --dump_sig dump signature (*.p7)\n"
58 "\t-h, --help print a help message\n",
63 * auth_context - authentication context
64 * @key_file: Path to a private key file
65 * @cert_file: Path to a certificate file
66 * @image_data: Pointer to firmware data
67 * @image_size: Size of firmware data
68 * @auth: Authentication header
69 * @sig_data: Signature data
70 * @sig_size: Size of signature data
72 * Data structure used in create_auth_data(). @key_file through
73 * @image_size are input parameters. @auth, @sig_data and @sig_size
74 * are filled in by create_auth_data().
81 struct efi_firmware_image_authentication auth;
89 * read_bin_file - read a firmware binary file
90 * @bin: Path to a firmware binary file
91 * @data: Pointer to pointer of allocated buffer
92 * @bin_size: Size of allocated buffer
94 * Read out a content of binary, @bin, into @data.
95 * A caller should free @data.
101 static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size)
104 struct stat bin_stat;
111 fprintf(stderr, "cannot open %s\n", bin);
114 if (stat(bin, &bin_stat) < 0) {
115 fprintf(stderr, "cannot determine the size of %s\n", bin);
119 if (bin_stat.st_size > SIZE_MAX) {
120 fprintf(stderr, "file size is too large for malloc: %s\n", bin);
124 buf = malloc(bin_stat.st_size);
126 fprintf(stderr, "cannot allocate memory: %zx\n",
127 (size_t)bin_stat.st_size);
132 size = fread(buf, 1, bin_stat.st_size, g);
133 if (size < bin_stat.st_size) {
134 fprintf(stderr, "read failed (%zx)\n", size);
140 *bin_size = bin_stat.st_size;
148 * write_capsule_file - write a capsule file
150 * @data: Pointer to data
151 * @bin_size: Size of data
153 * Write out data, @data, with the size @bin_size.
159 static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg)
163 size_written = fwrite(data, 1, size, f);
164 if (size_written < size) {
165 fprintf(stderr, "%s: write failed (%zx != %zx)\n", msg,
174 * create_auth_data - compose authentication data in capsule
175 * @auth_context: Pointer to authentication context
177 * Fill up an authentication header (.auth) and signature data (.sig_data)
178 * in @auth_context, using library functions from openssl.
179 * All the parameters in @auth_context must be filled in by a caller.
185 static int create_auth_data(struct auth_context *ctx)
190 gnutls_privkey_t pkey;
191 gnutls_x509_crt_t x509;
192 gnutls_pkcs7_t pkcs7;
194 gnutls_datum_t signature;
197 ret = read_bin_file(ctx->cert_file, &cert.data, &file_size);
200 if (file_size > UINT_MAX)
202 cert.size = file_size;
204 ret = read_bin_file(ctx->key_file, &key.data, &file_size);
207 if (file_size > UINT_MAX)
209 key.size = file_size;
213 * gnutls_global_set_time_function(mytime);
214 * gnutls_global_set_log_function(tls_log_func);
215 * gnutls_global_set_log_level(6);
218 ret = gnutls_privkey_init(&pkey);
220 fprintf(stderr, "error in gnutls_privkey_init(): %s\n",
221 gnutls_strerror(ret));
225 ret = gnutls_x509_crt_init(&x509);
227 fprintf(stderr, "error in gnutls_x509_crt_init(): %s\n",
228 gnutls_strerror(ret));
232 /* load a private key */
233 ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM,
237 "error in gnutls_privkey_import_x509_raw(): %s\n",
238 gnutls_strerror(ret));
242 /* load x509 certificate */
243 ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM);
245 fprintf(stderr, "error in gnutls_x509_crt_import(): %s\n",
246 gnutls_strerror(ret));
250 /* generate a PKCS #7 structure */
251 ret = gnutls_pkcs7_init(&pkcs7);
253 fprintf(stderr, "error in gnutls_pkcs7_init(): %s\n",
254 gnutls_strerror(ret));
264 * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
266 data.size = ctx->image_size + sizeof(ctx->auth.monotonic_count);
267 data.data = malloc(data.size);
269 fprintf(stderr, "allocating memory (0x%x) failed\n", data.size);
272 memcpy(data.data, ctx->image_data, ctx->image_size);
273 memcpy(data.data + ctx->image_size, &ctx->auth.monotonic_count,
274 sizeof(ctx->auth.monotonic_count));
276 ret = gnutls_pkcs7_sign(pkcs7, x509, pkey, &data, NULL, NULL,
278 /* GNUTLS_PKCS7_EMBED_DATA? */
279 GNUTLS_PKCS7_INCLUDE_CERT |
280 GNUTLS_PKCS7_INCLUDE_TIME);
282 fprintf(stderr, "error in gnutls_pkcs7)sign(): %s\n",
283 gnutls_strerror(ret));
288 ret = gnutls_pkcs7_export2(pkcs7, GNUTLS_X509_FMT_DER, &signature);
290 fprintf(stderr, "error in gnutls_pkcs7_export2: %s\n",
291 gnutls_strerror(ret));
294 ctx->sig_data = signature.data;
295 ctx->sig_size = signature.size;
298 ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
300 ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
301 ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
302 memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
303 sizeof(efi_guid_cert_type_pkcs7));
306 * For better clean-ups,
307 * gnutls_pkcs7_deinit(pkcs7);
308 * gnutls_privkey_deinit(pkey);
309 * gnutls_x509_crt_deinit(x509);
313 * gnutls_free(signature.data);
320 * dump_signature - dump out a signature
321 * @path: Path to a capsule file
322 * @signature: Signature data
323 * @sig_size: Size of signature data
325 * Signature data pointed to by @signature will be saved into
326 * a file whose file name is @path with ".p7" suffix.
332 static int dump_signature(const char *path, uint8_t *signature, size_t sig_size)
339 sig_path = malloc(strlen(path) + 3 + 1);
343 sprintf(sig_path, "%s.p7", path);
344 f = fopen(sig_path, "w");
348 size = fwrite(signature, 1, sig_size, f);
349 if (size == sig_size)
359 * free_sig_data - free out signature data
360 * @ctx: Pointer to authentication context
362 * Free signature data allocated in create_auth_data().
364 static void free_sig_data(struct auth_context *ctx)
367 gnutls_free(ctx->sig_data);
371 * create_fwbin - create an uefi capsule file
372 * @path: Path to a created capsule file
373 * @bin: Path to a firmware binary to encapsulate
374 * @guid: GUID of related FMP driver
375 * @index: Index number in capsule
376 * @instance: Instance number in capsule
377 * @mcount: Monotonic count in authentication information
378 * @private_file: Path to a private key file
379 * @cert_file: Path to a certificate file
381 * This function actually does the job of creating an uefi capsule file.
382 * All the arguments must be supplied.
383 * If either @private_file ror @cert_file is NULL, the capsule file
390 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
391 unsigned long index, unsigned long instance,
392 uint64_t mcount, char *privkey_file, char *cert_file)
394 struct efi_capsule_header header;
395 struct efi_firmware_management_capsule_header capsule;
396 struct efi_firmware_management_capsule_image_header image;
397 struct auth_context auth_context;
405 fprintf(stderr, "For output: %s\n", path);
406 fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid);
407 fprintf(stderr, "\tindex: %lu\n\tinstance: %lu\n", index, instance);
409 auth_context.sig_size = 0;
415 * read a firmware binary
417 if (read_bin_file(bin, &data, &bin_size))
420 /* first, calculate signature to determine its size */
421 if (privkey_file && cert_file) {
422 auth_context.key_file = privkey_file;
423 auth_context.cert_file = cert_file;
424 auth_context.auth.monotonic_count = mcount;
425 auth_context.image_data = data;
426 auth_context.image_size = bin_size;
428 if (create_auth_data(&auth_context)) {
429 fprintf(stderr, "Signing firmware image failed\n");
434 dump_signature(path, auth_context.sig_data,
435 auth_context.sig_size)) {
436 fprintf(stderr, "Creating signature file failed\n");
442 * write a capsule file
444 f = fopen(path, "w");
446 fprintf(stderr, "cannot open %s\n", path);
451 * capsule file header
453 header.capsule_guid = efi_guid_fm_capsule;
454 header.header_size = sizeof(header);
455 /* TODO: The current implementation ignores flags */
456 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
457 header.capsule_image_size = sizeof(header)
458 + sizeof(capsule) + sizeof(uint64_t)
461 if (auth_context.sig_size)
462 header.capsule_image_size += sizeof(auth_context.auth)
463 + auth_context.sig_size;
464 if (write_capsule_file(f, &header, sizeof(header),
469 * firmware capsule header
470 * This capsule has only one firmware capsule image.
472 capsule.version = 0x00000001;
473 capsule.embedded_driver_count = 0;
474 capsule.payload_item_count = 1;
475 if (write_capsule_file(f, &capsule, sizeof(capsule),
476 "Firmware capsule header"))
479 offset = sizeof(capsule) + sizeof(uint64_t);
480 if (write_capsule_file(f, &offset, sizeof(offset),
481 "Offset to capsule image"))
485 * firmware capsule image header
487 image.version = 0x00000003;
488 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
489 image.update_image_index = index;
490 image.reserved[0] = 0;
491 image.reserved[1] = 0;
492 image.reserved[2] = 0;
493 image.update_image_size = bin_size;
494 if (auth_context.sig_size)
495 image.update_image_size += sizeof(auth_context.auth)
496 + auth_context.sig_size;
497 image.update_vendor_code_size = 0; /* none */
498 image.update_hardware_instance = instance;
499 image.image_capsule_support = 0;
500 if (auth_context.sig_size)
501 image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
502 if (write_capsule_file(f, &image, sizeof(image),
503 "Firmware capsule image header"))
509 if (auth_context.sig_size) {
510 if (write_capsule_file(f, &auth_context.auth,
511 sizeof(auth_context.auth),
512 "Authentication header"))
515 if (write_capsule_file(f, auth_context.sig_data,
516 auth_context.sig_size, "Signature"))
523 if (write_capsule_file(f, data, bin_size, "Firmware binary"))
530 free_sig_data(&auth_context);
537 * convert_uuid_to_guid() - convert UUID to GUID
540 * UUID and GUID have the same data structure, but their binary
541 * formats are different due to the endianness. See lib/uuid.c.
542 * Since uuid_parse() can handle only UUID, this function must
543 * be called to get correct data for GUID when parsing a string.
545 * The correct data will be returned in @buf.
547 void convert_uuid_to_guid(unsigned char *buf)
568 * main - main entry function of mkeficapsule
569 * @argc: Number of arguments
570 * @argv: Array of pointers to arguments
572 * Create an uefi capsule file, optionally signing it.
573 * Parse all the arguments and pass them on to create_fwbin().
579 int main(int argc, char **argv)
582 unsigned char uuid_buf[16];
583 unsigned long index, instance;
585 char *privkey_file, *cert_file;
596 c = getopt_long(argc, argv, opts_short, options, &idx);
604 "Image type already specified\n");
607 if (uuid_parse(optarg, uuid_buf)) {
608 fprintf(stderr, "Wrong guid format\n");
611 convert_uuid_to_guid(uuid_buf);
612 guid = (efi_guid_t *)uuid_buf;
615 index = strtoul(optarg, NULL, 0);
618 instance = strtoul(optarg, NULL, 0);
623 "Private Key already specified\n");
626 privkey_file = optarg;
631 "Certificate file already specified\n");
637 mcount = strtoul(optarg, NULL, 0);
648 /* check necessary parameters */
649 if ((argc != optind + 2) || !guid ||
650 ((privkey_file && !cert_file) ||
651 (!privkey_file && cert_file))) {
656 if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
657 mcount, privkey_file, cert_file) < 0) {
658 fprintf(stderr, "Creating firmware capsule failed\n");