:)
[platform/kernel/u-boot.git] / tools / mkeficapsule.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2018 Linaro Limited
4  *              Author: AKASHI Takahiro
5  */
6
7 #include <getopt.h>
8 #include <pe.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <linux/types.h>
15
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <uuid/uuid.h>
19 #include <linux/kconfig.h>
20
21 #include <gnutls/gnutls.h>
22 #include <gnutls/pkcs7.h>
23 #include <gnutls/abstract.h>
24
25 #include "eficapsule.h"
26
27 static const char *tool_name = "mkeficapsule";
28
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;
31
32 static const char *opts_short = "g:i:I:v:p:c:m:dh";
33
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'},
43         {NULL, 0, NULL, 0},
44 };
45
46 static void print_usage(void)
47 {
48         fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
49                 "Options:\n"
50
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",
59                 tool_name);
60 }
61
62 /**
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
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  */
76 struct 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
86 static int dump_sig;
87
88 /**
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
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  */
101 static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size)
102 {
103         FILE *g;
104         struct stat bin_stat;
105         void *buf;
106         size_t size;
107         int ret = 0;
108
109         g = fopen(bin, "r");
110         if (!g) {
111                 fprintf(stderr, "cannot open %s\n", bin);
112                 return -1;
113         }
114         if (stat(bin, &bin_stat) < 0) {
115                 fprintf(stderr, "cannot determine the size of %s\n", bin);
116                 ret = -1;
117                 goto err;
118         }
119         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) {
126                 fprintf(stderr, "cannot allocate memory: %zx\n",
127                         (size_t)bin_stat.st_size);
128                 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;
141 err:
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  */
159 static 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;
168         }
169
170         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  */
185 static 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;
207         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
316         return 0;
317 }
318
319 /**
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
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  */
332 static 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);
353 err:
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  */
364 static void free_sig_data(struct auth_context *ctx)
365 {
366         if (ctx->sig_size)
367                 gnutls_free(ctx->sig_data);
368 }
369
370 /**
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
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  */
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)
393 {
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;
398         FILE *f;
399         uint8_t *data;
400         off_t bin_size;
401         uint64_t offset;
402         int ret;
403
404 #ifdef DEBUG
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);
408 #endif
409         auth_context.sig_size = 0;
410         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
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;
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
441         /*
442          * write a capsule file
443          */
444         f = fopen(path, "w");
445         if (!f) {
446                 fprintf(stderr, "cannot open %s\n", path);
447                 goto err;
448         }
449
450         /*
451          * capsule file header
452          */
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)
459                                         + sizeof(image)
460                                         + bin_size;
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),
465                                "Capsule header"))
466                 goto err;
467
468         /*
469          * firmware capsule header
470          * This capsule has only one firmware capsule image.
471          */
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"))
477                 goto err;
478
479         offset = sizeof(capsule) + sizeof(uint64_t);
480         if (write_capsule_file(f, &offset, sizeof(offset),
481                                "Offset to capsule image"))
482                 goto err;
483
484         /*
485          * firmware capsule image header
486          */
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"))
504                 goto err;
505
506         /*
507          * 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         /*
521          * firmware binary
522          */
523         if (write_capsule_file(f, data, bin_size, "Firmware binary"))
524                 goto err;
525
526         ret = 0;
527 err:
528         if (f)
529                 fclose(f);
530         free_sig_data(&auth_context);
531         free(data);
532
533         return ret;
534 }
535
536 /**
537  * 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  */
547 void 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 /**
568  * 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
578  */
579 int main(int argc, char **argv)
580 {
581         efi_guid_t *guid;
582         unsigned char uuid_buf[16];
583         unsigned long index, instance;
584         uint64_t mcount;
585         char *privkey_file, *cert_file;
586         int c, idx;
587
588         guid = NULL;
589         index = 0;
590         instance = 0;
591         mcount = 0;
592         privkey_file = NULL;
593         cert_file = NULL;
594         dump_sig = 0;
595         for (;;) {
596                 c = getopt_long(argc, argv, opts_short, options, &idx);
597                 if (c == -1)
598                         break;
599
600                 switch (c) {
601                 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;
614                 case 'i':
615                         index = strtoul(optarg, NULL, 0);
616                         break;
617                 case 'I':
618                         instance = strtoul(optarg, NULL, 0);
619                         break;
620                 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;
642                 case 'h':
643                         print_usage();
644                         exit(EXIT_SUCCESS);
645                 }
646         }
647
648         /* check necessary parameters */
649         if ((argc != optind + 2) || !guid ||
650             ((privkey_file && !cert_file) ||
651              (!privkey_file && cert_file))) {
652                 print_usage();
653                 exit(EXIT_FAILURE);
654         }
655
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");
659                 exit(EXIT_FAILURE);
660         }
661
662         exit(EXIT_SUCCESS);
663 }