blob: 5f74d23b9e397d61fd03670ed1849c6a36fc05d9 [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;
AKASHI Takahiroc246b762022-02-09 19:10:35 +090030efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
31
Sughosh Ganue00eed72022-04-15 11:29:40 +053032static const char *opts_short = "g:i:I:v:p:c:m:dh";
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090033
34static struct option options[] = {
AKASHI Takahiroba212432022-02-09 19:10:39 +090035 {"guid", required_argument, NULL, 'g'},
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090036 {"index", required_argument, NULL, 'i'},
37 {"instance", required_argument, NULL, 'I'},
AKASHI Takahiroc246b762022-02-09 19:10:35 +090038 {"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'},
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090042 {"help", no_argument, NULL, 'h'},
43 {NULL, 0, NULL, 0},
44};
45
46static void print_usage(void)
47{
AKASHI Takahiroba212432022-02-09 19:10:39 +090048 fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090049 "Options:\n"
Sughosh Ganu079fcf22020-12-30 19:26:59 +053050
AKASHI Takahiroba212432022-02-09 19:10:39 +090051 "\t-g, --guid <guid string> guid for image blob type\n"
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090052 "\t-i, --index <index> update image index\n"
53 "\t-I, --instance <instance> update hardware instance\n"
AKASHI Takahiroc246b762022-02-09 19:10:35 +090054 "\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"
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090058 "\t-h, --help print a help message\n",
59 tool_name);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090060}
61
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090062/**
AKASHI Takahiroc246b762022-02-09 19:10:35 +090063 * 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
71 *
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().
75 */
76struct auth_context {
77 char *key_file;
78 char *cert_file;
79 uint8_t *image_data;
80 size_t image_size;
81 struct efi_firmware_image_authentication auth;
82 uint8_t *sig_data;
83 size_t sig_size;
84};
85
86static int dump_sig;
87
88/**
AKASHI Takahiro30fcea22022-01-18 13:39:45 +090089 * 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
93 *
94 * Read out a content of binary, @bin, into @data.
95 * A caller should free @data.
96 *
97 * Return:
98 * * 0 - on success
99 * * -1 - on failure
100 */
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900101static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size)
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900102{
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900103 FILE *g;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900104 struct stat bin_stat;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900105 void *buf;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900106 size_t size;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900107 int ret = 0;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900108
109 g = fopen(bin, "r");
110 if (!g) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900111 fprintf(stderr, "cannot open %s\n", bin);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900112 return -1;
113 }
114 if (stat(bin, &bin_stat) < 0) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900115 fprintf(stderr, "cannot determine the size of %s\n", bin);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900116 ret = -1;
117 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900118 }
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900119 if (bin_stat.st_size > SIZE_MAX) {
120 fprintf(stderr, "file size is too large for malloc: %s\n", bin);
121 ret = -1;
122 goto err;
123 }
124 buf = malloc(bin_stat.st_size);
125 if (!buf) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900126 fprintf(stderr, "cannot allocate memory: %zx\n",
127 (size_t)bin_stat.st_size);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900128 ret = -1;
129 goto err;
130 }
131
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);
135 ret = -1;
136 goto err;
137 }
138
139 *data = buf;
140 *bin_size = bin_stat.st_size;
141err:
142 fclose(g);
143
144 return ret;
145}
146
147/**
148 * write_capsule_file - write a capsule file
149 * @bin: FILE stream
150 * @data: Pointer to data
151 * @bin_size: Size of data
152 *
153 * Write out data, @data, with the size @bin_size.
154 *
155 * Return:
156 * * 0 - on success
157 * * -1 - on failure
158 */
159static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg)
160{
161 size_t size_written;
162
163 size_written = fwrite(data, 1, size, f);
164 if (size_written < size) {
165 fprintf(stderr, "%s: write failed (%zx != %zx)\n", msg,
166 size_written, size);
167 return -1;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900168 }
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900169
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900170 return 0;
171}
172
173/**
174 * create_auth_data - compose authentication data in capsule
175 * @auth_context: Pointer to authentication context
176 *
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.
180 *
181 * Return:
182 * * 0 - on success
183 * * -1 - on failure
184 */
185static int create_auth_data(struct auth_context *ctx)
186{
187 gnutls_datum_t cert;
188 gnutls_datum_t key;
189 off_t file_size;
190 gnutls_privkey_t pkey;
191 gnutls_x509_crt_t x509;
192 gnutls_pkcs7_t pkcs7;
193 gnutls_datum_t data;
194 gnutls_datum_t signature;
195 int ret;
196
197 ret = read_bin_file(ctx->cert_file, &cert.data, &file_size);
198 if (ret < 0)
199 return -1;
200 if (file_size > UINT_MAX)
201 return -1;
202 cert.size = file_size;
203
204 ret = read_bin_file(ctx->key_file, &key.data, &file_size);
205 if (ret < 0)
206 return -1;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900207 if (file_size > UINT_MAX)
208 return -1;
209 key.size = file_size;
210
211 /*
212 * For debugging,
213 * gnutls_global_set_time_function(mytime);
214 * gnutls_global_set_log_function(tls_log_func);
215 * gnutls_global_set_log_level(6);
216 */
217
218 ret = gnutls_privkey_init(&pkey);
219 if (ret < 0) {
220 fprintf(stderr, "error in gnutls_privkey_init(): %s\n",
221 gnutls_strerror(ret));
222 return -1;
223 }
224
225 ret = gnutls_x509_crt_init(&x509);
226 if (ret < 0) {
227 fprintf(stderr, "error in gnutls_x509_crt_init(): %s\n",
228 gnutls_strerror(ret));
229 return -1;
230 }
231
232 /* load a private key */
233 ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM,
234 0, 0);
235 if (ret < 0) {
236 fprintf(stderr,
237 "error in gnutls_privkey_import_x509_raw(): %s\n",
238 gnutls_strerror(ret));
239 return -1;
240 }
241
242 /* load x509 certificate */
243 ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM);
244 if (ret < 0) {
245 fprintf(stderr, "error in gnutls_x509_crt_import(): %s\n",
246 gnutls_strerror(ret));
247 return -1;
248 }
249
250 /* generate a PKCS #7 structure */
251 ret = gnutls_pkcs7_init(&pkcs7);
252 if (ret < 0) {
253 fprintf(stderr, "error in gnutls_pkcs7_init(): %s\n",
254 gnutls_strerror(ret));
255 return -1;
256 }
257
258 /* sign */
259 /*
260 * Data should have
261 * * firmware image
262 * * monotonic count
263 * in this order!
264 * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
265 */
266 data.size = ctx->image_size + sizeof(ctx->auth.monotonic_count);
267 data.data = malloc(data.size);
268 if (!data.data) {
269 fprintf(stderr, "allocating memory (0x%x) failed\n", data.size);
270 return -1;
271 }
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));
275
276 ret = gnutls_pkcs7_sign(pkcs7, x509, pkey, &data, NULL, NULL,
277 GNUTLS_DIG_SHA256,
278 /* GNUTLS_PKCS7_EMBED_DATA? */
279 GNUTLS_PKCS7_INCLUDE_CERT |
280 GNUTLS_PKCS7_INCLUDE_TIME);
281 if (ret < 0) {
282 fprintf(stderr, "error in gnutls_pkcs7)sign(): %s\n",
283 gnutls_strerror(ret));
284 return -1;
285 }
286
287 /* export */
288 ret = gnutls_pkcs7_export2(pkcs7, GNUTLS_X509_FMT_DER, &signature);
289 if (ret < 0) {
290 fprintf(stderr, "error in gnutls_pkcs7_export2: %s\n",
291 gnutls_strerror(ret));
292 return -1;
293 }
294 ctx->sig_data = signature.data;
295 ctx->sig_size = signature.size;
296
297 /* fill auth_info */
298 ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
299 + ctx->sig_size;
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));
304
305 /*
306 * For better clean-ups,
307 * gnutls_pkcs7_deinit(pkcs7);
308 * gnutls_privkey_deinit(pkey);
309 * gnutls_x509_crt_deinit(x509);
310 * free(cert.data);
311 * free(key.data);
312 * if error
313 * gnutls_free(signature.data);
314 */
315
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900316 return 0;
317}
318
319/**
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900320 * dump_signature - dump out a signature
321 * @path: Path to a capsule file
322 * @signature: Signature data
323 * @sig_size: Size of signature data
324 *
325 * Signature data pointed to by @signature will be saved into
326 * a file whose file name is @path with ".p7" suffix.
327 *
328 * Return:
329 * * 0 - on success
330 * * -1 - on failure
331 */
332static int dump_signature(const char *path, uint8_t *signature, size_t sig_size)
333{
334 char *sig_path;
335 FILE *f;
336 size_t size;
337 int ret = -1;
338
339 sig_path = malloc(strlen(path) + 3 + 1);
340 if (!sig_path)
341 return ret;
342
343 sprintf(sig_path, "%s.p7", path);
344 f = fopen(sig_path, "w");
345 if (!f)
346 goto err;
347
348 size = fwrite(signature, 1, sig_size, f);
349 if (size == sig_size)
350 ret = 0;
351
352 fclose(f);
353err:
354 free(sig_path);
355 return ret;
356}
357
358/**
359 * free_sig_data - free out signature data
360 * @ctx: Pointer to authentication context
361 *
362 * Free signature data allocated in create_auth_data().
363 */
364static void free_sig_data(struct auth_context *ctx)
365{
366 if (ctx->sig_size)
367 gnutls_free(ctx->sig_data);
368}
369
370/**
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900371 * 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
380 *
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
384 * won't be signed.
385 *
386 * Return:
387 * * 0 - on success
388 * * -1 - on failure
389 */
390static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900391 unsigned long index, unsigned long instance,
392 uint64_t mcount, char *privkey_file, char *cert_file)
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900393{
394 struct efi_capsule_header header;
395 struct efi_firmware_management_capsule_header capsule;
396 struct efi_firmware_management_capsule_image_header image;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900397 struct auth_context auth_context;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900398 FILE *f;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900399 uint8_t *data;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900400 off_t bin_size;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900401 uint64_t offset;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900402 int ret;
403
404#ifdef DEBUG
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900405 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);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900408#endif
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900409 auth_context.sig_size = 0;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900410 f = NULL;
411 data = NULL;
412 ret = -1;
413
414 /*
415 * read a firmware binary
416 */
417 if (read_bin_file(bin, &data, &bin_size))
418 goto err;
419
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900420 /* 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;
427
428 if (create_auth_data(&auth_context)) {
429 fprintf(stderr, "Signing firmware image failed\n");
430 goto err;
431 }
432
433 if (dump_sig &&
434 dump_signature(path, auth_context.sig_data,
435 auth_context.sig_size)) {
436 fprintf(stderr, "Creating signature file failed\n");
437 goto err;
438 }
439 }
440
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900441 /*
442 * write a capsule file
443 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900444 f = fopen(path, "w");
445 if (!f) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900446 fprintf(stderr, "cannot open %s\n", path);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900447 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900448 }
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900449
450 /*
451 * capsule file header
452 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900453 header.capsule_guid = efi_guid_fm_capsule;
454 header.header_size = sizeof(header);
AKASHI Takahiro0f626ce2020-11-30 18:12:16 +0900455 /* TODO: The current implementation ignores flags */
456 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900457 header.capsule_image_size = sizeof(header)
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900458 + sizeof(capsule) + sizeof(uint64_t)
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900459 + sizeof(image)
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900460 + bin_size;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900461 if (auth_context.sig_size)
462 header.capsule_image_size += sizeof(auth_context.auth)
463 + auth_context.sig_size;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900464 if (write_capsule_file(f, &header, sizeof(header),
465 "Capsule header"))
466 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900467
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900468 /*
469 * firmware capsule header
470 * This capsule has only one firmware capsule image.
471 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900472 capsule.version = 0x00000001;
473 capsule.embedded_driver_count = 0;
474 capsule.payload_item_count = 1;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900475 if (write_capsule_file(f, &capsule, sizeof(capsule),
476 "Firmware capsule header"))
477 goto err;
478
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900479 offset = sizeof(capsule) + sizeof(uint64_t);
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900480 if (write_capsule_file(f, &offset, sizeof(offset),
481 "Offset to capsule image"))
482 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900483
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900484 /*
485 * firmware capsule image header
486 */
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900487 image.version = 0x00000003;
488 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
489 image.update_image_index = index;
AKASHI Takahiroa4c14aa2021-01-22 10:43:49 +0900490 image.reserved[0] = 0;
491 image.reserved[1] = 0;
492 image.reserved[2] = 0;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900493 image.update_image_size = bin_size;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900494 if (auth_context.sig_size)
495 image.update_image_size += sizeof(auth_context.auth)
496 + auth_context.sig_size;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900497 image.update_vendor_code_size = 0; /* none */
498 image.update_hardware_instance = instance;
499 image.image_capsule_support = 0;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900500 if (auth_context.sig_size)
501 image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900502 if (write_capsule_file(f, &image, sizeof(image),
503 "Firmware capsule image header"))
504 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900505
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900506 /*
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900507 * signature
508 */
509 if (auth_context.sig_size) {
510 if (write_capsule_file(f, &auth_context.auth,
511 sizeof(auth_context.auth),
512 "Authentication header"))
513 goto err;
514
515 if (write_capsule_file(f, auth_context.sig_data,
516 auth_context.sig_size, "Signature"))
517 goto err;
518 }
519
520 /*
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900521 * firmware binary
522 */
523 if (write_capsule_file(f, data, bin_size, "Firmware binary"))
524 goto err;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900525
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900526 ret = 0;
527err:
528 if (f)
529 fclose(f);
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900530 free_sig_data(&auth_context);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900531 free(data);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900532
AKASHI Takahiro30fcea22022-01-18 13:39:45 +0900533 return ret;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900534}
535
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900536/**
AKASHI Takahiroba212432022-02-09 19:10:39 +0900537 * convert_uuid_to_guid() - convert UUID to GUID
538 * @buf: UUID binary
539 *
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.
544 *
545 * The correct data will be returned in @buf.
546 */
547void convert_uuid_to_guid(unsigned char *buf)
548{
549 unsigned char c;
550
551 c = buf[0];
552 buf[0] = buf[3];
553 buf[3] = c;
554 c = buf[1];
555 buf[1] = buf[2];
556 buf[2] = c;
557
558 c = buf[4];
559 buf[4] = buf[5];
560 buf[5] = c;
561
562 c = buf[6];
563 buf[6] = buf[7];
564 buf[7] = c;
565}
566
567/**
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900568 * main - main entry function of mkeficapsule
569 * @argc: Number of arguments
570 * @argv: Array of pointers to arguments
571 *
572 * Create an uefi capsule file, optionally signing it.
573 * Parse all the arguments and pass them on to create_fwbin().
574 *
575 * Return:
576 * * 0 - on success
577 * * -1 - on failure
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900578 */
579int main(int argc, char **argv)
580{
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900581 efi_guid_t *guid;
AKASHI Takahiroba212432022-02-09 19:10:39 +0900582 unsigned char uuid_buf[16];
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900583 unsigned long index, instance;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900584 uint64_t mcount;
585 char *privkey_file, *cert_file;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900586 int c, idx;
587
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900588 guid = NULL;
589 index = 0;
590 instance = 0;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900591 mcount = 0;
592 privkey_file = NULL;
593 cert_file = NULL;
594 dump_sig = 0;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900595 for (;;) {
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900596 c = getopt_long(argc, argv, opts_short, options, &idx);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900597 if (c == -1)
598 break;
599
600 switch (c) {
AKASHI Takahiroba212432022-02-09 19:10:39 +0900601 case 'g':
602 if (guid) {
603 fprintf(stderr,
604 "Image type already specified\n");
605 exit(EXIT_FAILURE);
606 }
607 if (uuid_parse(optarg, uuid_buf)) {
608 fprintf(stderr, "Wrong guid format\n");
609 exit(EXIT_FAILURE);
610 }
611 convert_uuid_to_guid(uuid_buf);
612 guid = (efi_guid_t *)uuid_buf;
613 break;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900614 case 'i':
615 index = strtoul(optarg, NULL, 0);
616 break;
617 case 'I':
618 instance = strtoul(optarg, NULL, 0);
619 break;
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900620 case 'p':
621 if (privkey_file) {
622 fprintf(stderr,
623 "Private Key already specified\n");
624 exit(EXIT_FAILURE);
625 }
626 privkey_file = optarg;
627 break;
628 case 'c':
629 if (cert_file) {
630 fprintf(stderr,
631 "Certificate file already specified\n");
632 exit(EXIT_FAILURE);
633 }
634 cert_file = optarg;
635 break;
636 case 'm':
637 mcount = strtoul(optarg, NULL, 0);
638 break;
639 case 'd':
640 dump_sig = 1;
641 break;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900642 case 'h':
643 print_usage();
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900644 exit(EXIT_SUCCESS);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900645 }
646 }
647
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900648 /* check necessary parameters */
AKASHI Takahiroba212432022-02-09 19:10:39 +0900649 if ((argc != optind + 2) || !guid ||
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900650 ((privkey_file && !cert_file) ||
651 (!privkey_file && cert_file))) {
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900652 print_usage();
Sughosh Ganu14b44202021-01-22 20:34:56 +0530653 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900654 }
655
AKASHI Takahiroba212432022-02-09 19:10:39 +0900656 if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
AKASHI Takahiroc246b762022-02-09 19:10:35 +0900657 mcount, privkey_file, cert_file) < 0) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900658 fprintf(stderr, "Creating firmware capsule failed\n");
Sughosh Ganu14b44202021-01-22 20:34:56 +0530659 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900660 }
661
Sughosh Ganu14b44202021-01-22 20:34:56 +0530662 exit(EXIT_SUCCESS);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900663}