blob: f7590e482f10aa09b9279286b8bc0dffd845ea21 [file] [log] [blame]
AKASHI Takahiro19122aa2020-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 Takahiroc246b762022-02-09 19:10:35 +09008#include <pe.h>
AKASHI Takahiro19122aa2020-11-30 18:12:15 +09009#include <stdbool.h>
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090010#include <stdint.h>
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090011#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <linux/types.h>
Sughosh Ganu079fcf22020-12-30 19:26:59 +053015
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090016#include <sys/stat.h>
17#include <sys/types.h>
AKASHI Takahiroba212432022-02-09 19:10:39 +090018#include <uuid/uuid.h>
AKASHI Takahiroc246b762022-02-09 19:10:35 +090019#include <linux/kconfig.h>
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090020
AKASHI Takahiroc246b762022-02-09 19:10:35 +090021#include <gnutls/gnutls.h>
22#include <gnutls/pkcs7.h>
23#include <gnutls/abstract.h>
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090024
AKASHI Takahiroc246b762022-02-09 19:10:35 +090025#include "eficapsule.h"
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090026
27static const char *tool_name = "mkeficapsule";
28
29efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
30efi_guid_t efi_guid_image_type_uboot_fit =
31 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
32efi_guid_t efi_guid_image_type_uboot_raw =
33 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
AKASHI Takahiroc246b762022-02-09 19:10:35 +090034efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
35
AKASHI Takahiroba212432022-02-09 19:10:39 +090036static const char *opts_short = "frg:i:I:v:p:c:m:dh";
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090037
38static struct option options[] = {
AKASHI Takahiroba212432022-02-09 19:10:39 +090039 {"fit", no_argument, NULL, 'f'},
40 {"raw", no_argument, NULL, 'r'},
41 {"guid", required_argument, NULL, 'g'},
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090042 {"index", required_argument, NULL, 'i'},
43 {"instance", required_argument, NULL, 'I'},
AKASHI Takahiroc246b762022-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'},
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090048 {"help", no_argument, NULL, 'h'},
49 {NULL, 0, NULL, 0},
50};
51
52static void print_usage(void)
53{
AKASHI Takahiroba212432022-02-09 19:10:39 +090054 fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090055 "Options:\n"
Sughosh Ganu079fcf22020-12-30 19:26:59 +053056
AKASHI Takahiroba212432022-02-09 19:10:39 +090057 "\t-f, --fit FIT image type\n"
58 "\t-r, --raw raw image type\n"
59 "\t-g, --guid <guid string> guid for image blob type\n"
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090060 "\t-i, --index <index> update image index\n"
61 "\t-I, --instance <instance> update hardware instance\n"
AKASHI Takahiroc246b762022-02-09 19:10:35 +090062 "\t-p, --private-key <privkey file> private key file\n"
63 "\t-c, --certificate <cert file> signer's certificate file\n"
64 "\t-m, --monotonic-count <count> monotonic count\n"
65 "\t-d, --dump_sig dump signature (*.p7)\n"
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090066 "\t-h, --help print a help message\n",
67 tool_name);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090068}
69
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090070/**
AKASHI Takahiroc246b762022-02-09 19:10:35 +090071 * auth_context - authentication context
72 * @key_file: Path to a private key file
73 * @cert_file: Path to a certificate file
74 * @image_data: Pointer to firmware data
75 * @image_size: Size of firmware data
76 * @auth: Authentication header
77 * @sig_data: Signature data
78 * @sig_size: Size of signature data
79 *
80 * Data structure used in create_auth_data(). @key_file through
81 * @image_size are input parameters. @auth, @sig_data and @sig_size
82 * are filled in by create_auth_data().
83 */
84struct auth_context {
85 char *key_file;
86 char *cert_file;
87 uint8_t *image_data;
88 size_t image_size;
89 struct efi_firmware_image_authentication auth;
90 uint8_t *sig_data;
91 size_t sig_size;
92};
93
94static int dump_sig;
95
96/**
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090097 * read_bin_file - read a firmware binary file
98 * @bin: Path to a firmware binary file
99 * @data: Pointer to pointer of allocated buffer
100 * @bin_size: Size of allocated buffer
101 *
102 * Read out a content of binary, @bin, into @data.
103 * A caller should free @data.
104 *
105 * Return:
106 * * 0 - on success
107 * * -1 - on failure
108 */
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900109static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size)
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900110{
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900111 FILE *g;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900112 struct stat bin_stat;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900113 void *buf;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900114 size_t size;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900115 int ret = 0;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900116
117 g = fopen(bin, "r");
118 if (!g) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900119 fprintf(stderr, "cannot open %s\n", bin);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900120 return -1;
121 }
122 if (stat(bin, &bin_stat) < 0) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900123 fprintf(stderr, "cannot determine the size of %s\n", bin);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900124 ret = -1;
125 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900126 }
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900127 if (bin_stat.st_size > SIZE_MAX) {
128 fprintf(stderr, "file size is too large for malloc: %s\n", bin);
129 ret = -1;
130 goto err;
131 }
132 buf = malloc(bin_stat.st_size);
133 if (!buf) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900134 fprintf(stderr, "cannot allocate memory: %zx\n",
135 (size_t)bin_stat.st_size);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900136 ret = -1;
137 goto err;
138 }
139
140 size = fread(buf, 1, bin_stat.st_size, g);
141 if (size < bin_stat.st_size) {
142 fprintf(stderr, "read failed (%zx)\n", size);
143 ret = -1;
144 goto err;
145 }
146
147 *data = buf;
148 *bin_size = bin_stat.st_size;
149err:
150 fclose(g);
151
152 return ret;
153}
154
155/**
156 * write_capsule_file - write a capsule file
157 * @bin: FILE stream
158 * @data: Pointer to data
159 * @bin_size: Size of data
160 *
161 * Write out data, @data, with the size @bin_size.
162 *
163 * Return:
164 * * 0 - on success
165 * * -1 - on failure
166 */
167static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg)
168{
169 size_t size_written;
170
171 size_written = fwrite(data, 1, size, f);
172 if (size_written < size) {
173 fprintf(stderr, "%s: write failed (%zx != %zx)\n", msg,
174 size_written, size);
175 return -1;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900176 }
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900177
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900178 return 0;
179}
180
181/**
182 * create_auth_data - compose authentication data in capsule
183 * @auth_context: Pointer to authentication context
184 *
185 * Fill up an authentication header (.auth) and signature data (.sig_data)
186 * in @auth_context, using library functions from openssl.
187 * All the parameters in @auth_context must be filled in by a caller.
188 *
189 * Return:
190 * * 0 - on success
191 * * -1 - on failure
192 */
193static int create_auth_data(struct auth_context *ctx)
194{
195 gnutls_datum_t cert;
196 gnutls_datum_t key;
197 off_t file_size;
198 gnutls_privkey_t pkey;
199 gnutls_x509_crt_t x509;
200 gnutls_pkcs7_t pkcs7;
201 gnutls_datum_t data;
202 gnutls_datum_t signature;
203 int ret;
204
205 ret = read_bin_file(ctx->cert_file, &cert.data, &file_size);
206 if (ret < 0)
207 return -1;
208 if (file_size > UINT_MAX)
209 return -1;
210 cert.size = file_size;
211
212 ret = read_bin_file(ctx->key_file, &key.data, &file_size);
213 if (ret < 0)
214 return -1;
215 if (ret < 0)
216 return -1;
217 if (file_size > UINT_MAX)
218 return -1;
219 key.size = file_size;
220
221 /*
222 * For debugging,
223 * gnutls_global_set_time_function(mytime);
224 * gnutls_global_set_log_function(tls_log_func);
225 * gnutls_global_set_log_level(6);
226 */
227
228 ret = gnutls_privkey_init(&pkey);
229 if (ret < 0) {
230 fprintf(stderr, "error in gnutls_privkey_init(): %s\n",
231 gnutls_strerror(ret));
232 return -1;
233 }
234
235 ret = gnutls_x509_crt_init(&x509);
236 if (ret < 0) {
237 fprintf(stderr, "error in gnutls_x509_crt_init(): %s\n",
238 gnutls_strerror(ret));
239 return -1;
240 }
241
242 /* load a private key */
243 ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM,
244 0, 0);
245 if (ret < 0) {
246 fprintf(stderr,
247 "error in gnutls_privkey_import_x509_raw(): %s\n",
248 gnutls_strerror(ret));
249 return -1;
250 }
251
252 /* load x509 certificate */
253 ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM);
254 if (ret < 0) {
255 fprintf(stderr, "error in gnutls_x509_crt_import(): %s\n",
256 gnutls_strerror(ret));
257 return -1;
258 }
259
260 /* generate a PKCS #7 structure */
261 ret = gnutls_pkcs7_init(&pkcs7);
262 if (ret < 0) {
263 fprintf(stderr, "error in gnutls_pkcs7_init(): %s\n",
264 gnutls_strerror(ret));
265 return -1;
266 }
267
268 /* sign */
269 /*
270 * Data should have
271 * * firmware image
272 * * monotonic count
273 * in this order!
274 * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
275 */
276 data.size = ctx->image_size + sizeof(ctx->auth.monotonic_count);
277 data.data = malloc(data.size);
278 if (!data.data) {
279 fprintf(stderr, "allocating memory (0x%x) failed\n", data.size);
280 return -1;
281 }
282 memcpy(data.data, ctx->image_data, ctx->image_size);
283 memcpy(data.data + ctx->image_size, &ctx->auth.monotonic_count,
284 sizeof(ctx->auth.monotonic_count));
285
286 ret = gnutls_pkcs7_sign(pkcs7, x509, pkey, &data, NULL, NULL,
287 GNUTLS_DIG_SHA256,
288 /* GNUTLS_PKCS7_EMBED_DATA? */
289 GNUTLS_PKCS7_INCLUDE_CERT |
290 GNUTLS_PKCS7_INCLUDE_TIME);
291 if (ret < 0) {
292 fprintf(stderr, "error in gnutls_pkcs7)sign(): %s\n",
293 gnutls_strerror(ret));
294 return -1;
295 }
296
297 /* export */
298 ret = gnutls_pkcs7_export2(pkcs7, GNUTLS_X509_FMT_DER, &signature);
299 if (ret < 0) {
300 fprintf(stderr, "error in gnutls_pkcs7_export2: %s\n",
301 gnutls_strerror(ret));
302 return -1;
303 }
304 ctx->sig_data = signature.data;
305 ctx->sig_size = signature.size;
306
307 /* fill auth_info */
308 ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
309 + ctx->sig_size;
310 ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
311 ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
312 memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
313 sizeof(efi_guid_cert_type_pkcs7));
314
315 /*
316 * For better clean-ups,
317 * gnutls_pkcs7_deinit(pkcs7);
318 * gnutls_privkey_deinit(pkey);
319 * gnutls_x509_crt_deinit(x509);
320 * free(cert.data);
321 * free(key.data);
322 * if error
323 * gnutls_free(signature.data);
324 */
325
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900326 return 0;
327}
328
329/**
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900330 * dump_signature - dump out a signature
331 * @path: Path to a capsule file
332 * @signature: Signature data
333 * @sig_size: Size of signature data
334 *
335 * Signature data pointed to by @signature will be saved into
336 * a file whose file name is @path with ".p7" suffix.
337 *
338 * Return:
339 * * 0 - on success
340 * * -1 - on failure
341 */
342static int dump_signature(const char *path, uint8_t *signature, size_t sig_size)
343{
344 char *sig_path;
345 FILE *f;
346 size_t size;
347 int ret = -1;
348
349 sig_path = malloc(strlen(path) + 3 + 1);
350 if (!sig_path)
351 return ret;
352
353 sprintf(sig_path, "%s.p7", path);
354 f = fopen(sig_path, "w");
355 if (!f)
356 goto err;
357
358 size = fwrite(signature, 1, sig_size, f);
359 if (size == sig_size)
360 ret = 0;
361
362 fclose(f);
363err:
364 free(sig_path);
365 return ret;
366}
367
368/**
369 * free_sig_data - free out signature data
370 * @ctx: Pointer to authentication context
371 *
372 * Free signature data allocated in create_auth_data().
373 */
374static void free_sig_data(struct auth_context *ctx)
375{
376 if (ctx->sig_size)
377 gnutls_free(ctx->sig_data);
378}
379
380/**
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900381 * create_fwbin - create an uefi capsule file
382 * @path: Path to a created capsule file
383 * @bin: Path to a firmware binary to encapsulate
384 * @guid: GUID of related FMP driver
385 * @index: Index number in capsule
386 * @instance: Instance number in capsule
387 * @mcount: Monotonic count in authentication information
388 * @private_file: Path to a private key file
389 * @cert_file: Path to a certificate file
390 *
391 * This function actually does the job of creating an uefi capsule file.
392 * All the arguments must be supplied.
393 * If either @private_file ror @cert_file is NULL, the capsule file
394 * won't be signed.
395 *
396 * Return:
397 * * 0 - on success
398 * * -1 - on failure
399 */
400static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900401 unsigned long index, unsigned long instance,
402 uint64_t mcount, char *privkey_file, char *cert_file)
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900403{
404 struct efi_capsule_header header;
405 struct efi_firmware_management_capsule_header capsule;
406 struct efi_firmware_management_capsule_image_header image;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900407 struct auth_context auth_context;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900408 FILE *f;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900409 uint8_t *data;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900410 off_t bin_size;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900411 uint64_t offset;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900412 int ret;
413
414#ifdef DEBUG
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900415 fprintf(stderr, "For output: %s\n", path);
416 fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid);
417 fprintf(stderr, "\tindex: %lu\n\tinstance: %lu\n", index, instance);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900418#endif
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900419 auth_context.sig_size = 0;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900420 f = NULL;
421 data = NULL;
422 ret = -1;
423
424 /*
425 * read a firmware binary
426 */
427 if (read_bin_file(bin, &data, &bin_size))
428 goto err;
429
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900430 /* first, calculate signature to determine its size */
431 if (privkey_file && cert_file) {
432 auth_context.key_file = privkey_file;
433 auth_context.cert_file = cert_file;
434 auth_context.auth.monotonic_count = mcount;
435 auth_context.image_data = data;
436 auth_context.image_size = bin_size;
437
438 if (create_auth_data(&auth_context)) {
439 fprintf(stderr, "Signing firmware image failed\n");
440 goto err;
441 }
442
443 if (dump_sig &&
444 dump_signature(path, auth_context.sig_data,
445 auth_context.sig_size)) {
446 fprintf(stderr, "Creating signature file failed\n");
447 goto err;
448 }
449 }
450
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900451 /*
452 * write a capsule file
453 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900454 f = fopen(path, "w");
455 if (!f) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900456 fprintf(stderr, "cannot open %s\n", path);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900457 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900458 }
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900459
460 /*
461 * capsule file header
462 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900463 header.capsule_guid = efi_guid_fm_capsule;
464 header.header_size = sizeof(header);
AKASHI Takahiro0f626ce2020-11-30 18:12:16 +0900465 /* TODO: The current implementation ignores flags */
466 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900467 header.capsule_image_size = sizeof(header)
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900468 + sizeof(capsule) + sizeof(uint64_t)
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900469 + sizeof(image)
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900470 + bin_size;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900471 if (auth_context.sig_size)
472 header.capsule_image_size += sizeof(auth_context.auth)
473 + auth_context.sig_size;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900474 if (write_capsule_file(f, &header, sizeof(header),
475 "Capsule header"))
476 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900477
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900478 /*
479 * firmware capsule header
480 * This capsule has only one firmware capsule image.
481 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900482 capsule.version = 0x00000001;
483 capsule.embedded_driver_count = 0;
484 capsule.payload_item_count = 1;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900485 if (write_capsule_file(f, &capsule, sizeof(capsule),
486 "Firmware capsule header"))
487 goto err;
488
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900489 offset = sizeof(capsule) + sizeof(uint64_t);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900490 if (write_capsule_file(f, &offset, sizeof(offset),
491 "Offset to capsule image"))
492 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900493
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900494 /*
495 * firmware capsule image header
496 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900497 image.version = 0x00000003;
498 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
499 image.update_image_index = index;
AKASHI Takahiroa4c14aa2021-01-22 10:43:49 +0900500 image.reserved[0] = 0;
501 image.reserved[1] = 0;
502 image.reserved[2] = 0;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900503 image.update_image_size = bin_size;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900504 if (auth_context.sig_size)
505 image.update_image_size += sizeof(auth_context.auth)
506 + auth_context.sig_size;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900507 image.update_vendor_code_size = 0; /* none */
508 image.update_hardware_instance = instance;
509 image.image_capsule_support = 0;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900510 if (auth_context.sig_size)
511 image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900512 if (write_capsule_file(f, &image, sizeof(image),
513 "Firmware capsule image header"))
514 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900515
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900516 /*
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900517 * signature
518 */
519 if (auth_context.sig_size) {
520 if (write_capsule_file(f, &auth_context.auth,
521 sizeof(auth_context.auth),
522 "Authentication header"))
523 goto err;
524
525 if (write_capsule_file(f, auth_context.sig_data,
526 auth_context.sig_size, "Signature"))
527 goto err;
528 }
529
530 /*
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900531 * firmware binary
532 */
533 if (write_capsule_file(f, data, bin_size, "Firmware binary"))
534 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900535
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900536 ret = 0;
537err:
538 if (f)
539 fclose(f);
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900540 free_sig_data(&auth_context);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900541 free(data);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900542
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900543 return ret;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900544}
545
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900546/**
AKASHI Takahiroba212432022-02-09 19:10:39 +0900547 * convert_uuid_to_guid() - convert UUID to GUID
548 * @buf: UUID binary
549 *
550 * UUID and GUID have the same data structure, but their binary
551 * formats are different due to the endianness. See lib/uuid.c.
552 * Since uuid_parse() can handle only UUID, this function must
553 * be called to get correct data for GUID when parsing a string.
554 *
555 * The correct data will be returned in @buf.
556 */
557void convert_uuid_to_guid(unsigned char *buf)
558{
559 unsigned char c;
560
561 c = buf[0];
562 buf[0] = buf[3];
563 buf[3] = c;
564 c = buf[1];
565 buf[1] = buf[2];
566 buf[2] = c;
567
568 c = buf[4];
569 buf[4] = buf[5];
570 buf[5] = c;
571
572 c = buf[6];
573 buf[6] = buf[7];
574 buf[7] = c;
575}
576
577/**
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900578 * main - main entry function of mkeficapsule
579 * @argc: Number of arguments
580 * @argv: Array of pointers to arguments
581 *
582 * Create an uefi capsule file, optionally signing it.
583 * Parse all the arguments and pass them on to create_fwbin().
584 *
585 * Return:
586 * * 0 - on success
587 * * -1 - on failure
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900588 */
589int main(int argc, char **argv)
590{
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900591 efi_guid_t *guid;
AKASHI Takahiroba212432022-02-09 19:10:39 +0900592 unsigned char uuid_buf[16];
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900593 unsigned long index, instance;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900594 uint64_t mcount;
595 char *privkey_file, *cert_file;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900596 int c, idx;
597
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900598 guid = NULL;
599 index = 0;
600 instance = 0;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900601 mcount = 0;
602 privkey_file = NULL;
603 cert_file = NULL;
604 dump_sig = 0;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900605 for (;;) {
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900606 c = getopt_long(argc, argv, opts_short, options, &idx);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900607 if (c == -1)
608 break;
609
610 switch (c) {
611 case 'f':
AKASHI Takahiroba212432022-02-09 19:10:39 +0900612 if (guid) {
613 fprintf(stderr,
614 "Image type already specified\n");
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900615 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900616 }
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900617 guid = &efi_guid_image_type_uboot_fit;
618 break;
619 case 'r':
AKASHI Takahiroba212432022-02-09 19:10:39 +0900620 if (guid) {
621 fprintf(stderr,
622 "Image type already specified\n");
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900623 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900624 }
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900625 guid = &efi_guid_image_type_uboot_raw;
626 break;
AKASHI Takahiroba212432022-02-09 19:10:39 +0900627 case 'g':
628 if (guid) {
629 fprintf(stderr,
630 "Image type already specified\n");
631 exit(EXIT_FAILURE);
632 }
633 if (uuid_parse(optarg, uuid_buf)) {
634 fprintf(stderr, "Wrong guid format\n");
635 exit(EXIT_FAILURE);
636 }
637 convert_uuid_to_guid(uuid_buf);
638 guid = (efi_guid_t *)uuid_buf;
639 break;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900640 case 'i':
641 index = strtoul(optarg, NULL, 0);
642 break;
643 case 'I':
644 instance = strtoul(optarg, NULL, 0);
645 break;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900646 case 'p':
647 if (privkey_file) {
648 fprintf(stderr,
649 "Private Key already specified\n");
650 exit(EXIT_FAILURE);
651 }
652 privkey_file = optarg;
653 break;
654 case 'c':
655 if (cert_file) {
656 fprintf(stderr,
657 "Certificate file already specified\n");
658 exit(EXIT_FAILURE);
659 }
660 cert_file = optarg;
661 break;
662 case 'm':
663 mcount = strtoul(optarg, NULL, 0);
664 break;
665 case 'd':
666 dump_sig = 1;
667 break;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900668 case 'h':
669 print_usage();
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900670 exit(EXIT_SUCCESS);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900671 }
672 }
673
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900674 /* check necessary parameters */
AKASHI Takahiroba212432022-02-09 19:10:39 +0900675 if ((argc != optind + 2) || !guid ||
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900676 ((privkey_file && !cert_file) ||
677 (!privkey_file && cert_file))) {
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900678 print_usage();
Sughosh Ganu14b44202021-01-22 20:34:56 +0530679 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900680 }
681
AKASHI Takahiroba212432022-02-09 19:10:39 +0900682 if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900683 mcount, privkey_file, cert_file) < 0) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900684 fprintf(stderr, "Creating firmware capsule failed\n");
Sughosh Ganu14b44202021-01-22 20:34:56 +0530685 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900686 }
687
Sughosh Ganu14b44202021-01-22 20:34:56 +0530688 exit(EXIT_SUCCESS);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900689}