Convert CONFIG_BOARD_COMMON to Kconfig
[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_image_type_uboot_fit =
31                 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
32 efi_guid_t efi_guid_image_type_uboot_raw =
33                 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
34 efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
35
36 static const char *opts_short = "frg:i:I:v:p:c:m:dh";
37
38 static struct option options[] = {
39         {"fit", no_argument, NULL, 'f'},
40         {"raw", no_argument, NULL, 'r'},
41         {"guid", required_argument, NULL, 'g'},
42         {"index", required_argument, NULL, 'i'},
43         {"instance", required_argument, NULL, 'I'},
44         {"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'},
48         {"help", no_argument, NULL, 'h'},
49         {NULL, 0, NULL, 0},
50 };
51
52 static void print_usage(void)
53 {
54         fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
55                 "Options:\n"
56
57                 "\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"
60                 "\t-i, --index <index>         update image index\n"
61                 "\t-I, --instance <instance>   update hardware instance\n"
62                 "\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"
66                 "\t-h, --help                  print a help message\n",
67                 tool_name);
68 }
69
70 /**
71  * 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  */
84 struct 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
94 static int dump_sig;
95
96 /**
97  * 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  */
109 static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size)
110 {
111         FILE *g;
112         struct stat bin_stat;
113         void *buf;
114         size_t size;
115         int ret = 0;
116
117         g = fopen(bin, "r");
118         if (!g) {
119                 fprintf(stderr, "cannot open %s\n", bin);
120                 return -1;
121         }
122         if (stat(bin, &bin_stat) < 0) {
123                 fprintf(stderr, "cannot determine the size of %s\n", bin);
124                 ret = -1;
125                 goto err;
126         }
127         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) {
134                 fprintf(stderr, "cannot allocate memory: %zx\n",
135                         (size_t)bin_stat.st_size);
136                 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;
149 err:
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  */
167 static 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;
176         }
177
178         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  */
193 static 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 (file_size > UINT_MAX)
216                 return -1;
217         key.size = file_size;
218
219         /*
220          * For debugging,
221          * gnutls_global_set_time_function(mytime);
222          * gnutls_global_set_log_function(tls_log_func);
223          * gnutls_global_set_log_level(6);
224          */
225
226         ret = gnutls_privkey_init(&pkey);
227         if (ret < 0) {
228                 fprintf(stderr, "error in gnutls_privkey_init(): %s\n",
229                         gnutls_strerror(ret));
230                 return -1;
231         }
232
233         ret = gnutls_x509_crt_init(&x509);
234         if (ret < 0) {
235                 fprintf(stderr, "error in gnutls_x509_crt_init(): %s\n",
236                         gnutls_strerror(ret));
237                 return -1;
238         }
239
240         /* load a private key */
241         ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM,
242                                              0, 0);
243         if (ret < 0) {
244                 fprintf(stderr,
245                         "error in gnutls_privkey_import_x509_raw(): %s\n",
246                         gnutls_strerror(ret));
247                 return -1;
248         }
249
250         /* load x509 certificate */
251         ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM);
252         if (ret < 0) {
253                 fprintf(stderr, "error in gnutls_x509_crt_import(): %s\n",
254                         gnutls_strerror(ret));
255                 return -1;
256         }
257
258         /* generate a PKCS #7 structure */
259         ret = gnutls_pkcs7_init(&pkcs7);
260         if (ret < 0) {
261                 fprintf(stderr, "error in gnutls_pkcs7_init(): %s\n",
262                         gnutls_strerror(ret));
263                 return -1;
264         }
265
266         /* sign */
267         /*
268          * Data should have
269          *  * firmware image
270          *  * monotonic count
271          * in this order!
272          * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
273          */
274         data.size = ctx->image_size + sizeof(ctx->auth.monotonic_count);
275         data.data = malloc(data.size);
276         if (!data.data) {
277                 fprintf(stderr, "allocating memory (0x%x) failed\n", data.size);
278                 return -1;
279         }
280         memcpy(data.data, ctx->image_data, ctx->image_size);
281         memcpy(data.data + ctx->image_size, &ctx->auth.monotonic_count,
282                sizeof(ctx->auth.monotonic_count));
283
284         ret = gnutls_pkcs7_sign(pkcs7, x509, pkey, &data, NULL, NULL,
285                                 GNUTLS_DIG_SHA256,
286                                 /* GNUTLS_PKCS7_EMBED_DATA? */
287                                 GNUTLS_PKCS7_INCLUDE_CERT |
288                                 GNUTLS_PKCS7_INCLUDE_TIME);
289         if (ret < 0) {
290                 fprintf(stderr, "error in gnutls_pkcs7)sign(): %s\n",
291                         gnutls_strerror(ret));
292                 return -1;
293         }
294
295         /* export */
296         ret = gnutls_pkcs7_export2(pkcs7, GNUTLS_X509_FMT_DER, &signature);
297         if (ret < 0) {
298                 fprintf(stderr, "error in gnutls_pkcs7_export2: %s\n",
299                         gnutls_strerror(ret));
300                 return -1;
301         }
302         ctx->sig_data = signature.data;
303         ctx->sig_size = signature.size;
304
305         /* fill auth_info */
306         ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
307                                                 + ctx->sig_size;
308         ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
309         ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
310         memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
311                sizeof(efi_guid_cert_type_pkcs7));
312
313         /*
314          * For better clean-ups,
315          * gnutls_pkcs7_deinit(pkcs7);
316          * gnutls_privkey_deinit(pkey);
317          * gnutls_x509_crt_deinit(x509);
318          * free(cert.data);
319          * free(key.data);
320          * if error
321          *   gnutls_free(signature.data);
322          */
323
324         return 0;
325 }
326
327 /**
328  * dump_signature - dump out a signature
329  * @path:       Path to a capsule file
330  * @signature:  Signature data
331  * @sig_size:   Size of signature data
332  *
333  * Signature data pointed to by @signature will be saved into
334  * a file whose file name is @path with ".p7" suffix.
335  *
336  * Return:
337  * * 0  - on success
338  * * -1 - on failure
339  */
340 static int dump_signature(const char *path, uint8_t *signature, size_t sig_size)
341 {
342         char *sig_path;
343         FILE *f;
344         size_t size;
345         int ret = -1;
346
347         sig_path = malloc(strlen(path) + 3 + 1);
348         if (!sig_path)
349                 return ret;
350
351         sprintf(sig_path, "%s.p7", path);
352         f = fopen(sig_path, "w");
353         if (!f)
354                 goto err;
355
356         size = fwrite(signature, 1, sig_size, f);
357         if (size == sig_size)
358                 ret = 0;
359
360         fclose(f);
361 err:
362         free(sig_path);
363         return ret;
364 }
365
366 /**
367  * free_sig_data - free out signature data
368  * @ctx:        Pointer to authentication context
369  *
370  * Free signature data allocated in create_auth_data().
371  */
372 static void free_sig_data(struct auth_context *ctx)
373 {
374         if (ctx->sig_size)
375                 gnutls_free(ctx->sig_data);
376 }
377
378 /**
379  * create_fwbin - create an uefi capsule file
380  * @path:       Path to a created capsule file
381  * @bin:        Path to a firmware binary to encapsulate
382  * @guid:       GUID of related FMP driver
383  * @index:      Index number in capsule
384  * @instance:   Instance number in capsule
385  * @mcount:     Monotonic count in authentication information
386  * @private_file:       Path to a private key file
387  * @cert_file:  Path to a certificate file
388  *
389  * This function actually does the job of creating an uefi capsule file.
390  * All the arguments must be supplied.
391  * If either @private_file ror @cert_file is NULL, the capsule file
392  * won't be signed.
393  *
394  * Return:
395  * * 0  - on success
396  * * -1 - on failure
397  */
398 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
399                         unsigned long index, unsigned long instance,
400                         uint64_t mcount, char *privkey_file, char *cert_file)
401 {
402         struct efi_capsule_header header;
403         struct efi_firmware_management_capsule_header capsule;
404         struct efi_firmware_management_capsule_image_header image;
405         struct auth_context auth_context;
406         FILE *f;
407         uint8_t *data;
408         off_t bin_size;
409         uint64_t offset;
410         int ret;
411
412 #ifdef DEBUG
413         fprintf(stderr, "For output: %s\n", path);
414         fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid);
415         fprintf(stderr, "\tindex: %lu\n\tinstance: %lu\n", index, instance);
416 #endif
417         auth_context.sig_size = 0;
418         f = NULL;
419         data = NULL;
420         ret = -1;
421
422         /*
423          * read a firmware binary
424          */
425         if (read_bin_file(bin, &data, &bin_size))
426                 goto err;
427
428         /* first, calculate signature to determine its size */
429         if (privkey_file && cert_file) {
430                 auth_context.key_file = privkey_file;
431                 auth_context.cert_file = cert_file;
432                 auth_context.auth.monotonic_count = mcount;
433                 auth_context.image_data = data;
434                 auth_context.image_size = bin_size;
435
436                 if (create_auth_data(&auth_context)) {
437                         fprintf(stderr, "Signing firmware image failed\n");
438                         goto err;
439                 }
440
441                 if (dump_sig &&
442                     dump_signature(path, auth_context.sig_data,
443                                    auth_context.sig_size)) {
444                         fprintf(stderr, "Creating signature file failed\n");
445                         goto err;
446                 }
447         }
448
449         /*
450          * write a capsule file
451          */
452         f = fopen(path, "w");
453         if (!f) {
454                 fprintf(stderr, "cannot open %s\n", path);
455                 goto err;
456         }
457
458         /*
459          * capsule file header
460          */
461         header.capsule_guid = efi_guid_fm_capsule;
462         header.header_size = sizeof(header);
463         /* TODO: The current implementation ignores flags */
464         header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
465         header.capsule_image_size = sizeof(header)
466                                         + sizeof(capsule) + sizeof(uint64_t)
467                                         + sizeof(image)
468                                         + bin_size;
469         if (auth_context.sig_size)
470                 header.capsule_image_size += sizeof(auth_context.auth)
471                                 + auth_context.sig_size;
472         if (write_capsule_file(f, &header, sizeof(header),
473                                "Capsule header"))
474                 goto err;
475
476         /*
477          * firmware capsule header
478          * This capsule has only one firmware capsule image.
479          */
480         capsule.version = 0x00000001;
481         capsule.embedded_driver_count = 0;
482         capsule.payload_item_count = 1;
483         if (write_capsule_file(f, &capsule, sizeof(capsule),
484                                "Firmware capsule header"))
485                 goto err;
486
487         offset = sizeof(capsule) + sizeof(uint64_t);
488         if (write_capsule_file(f, &offset, sizeof(offset),
489                                "Offset to capsule image"))
490                 goto err;
491
492         /*
493          * firmware capsule image header
494          */
495         image.version = 0x00000003;
496         memcpy(&image.update_image_type_id, guid, sizeof(*guid));
497         image.update_image_index = index;
498         image.reserved[0] = 0;
499         image.reserved[1] = 0;
500         image.reserved[2] = 0;
501         image.update_image_size = bin_size;
502         if (auth_context.sig_size)
503                 image.update_image_size += sizeof(auth_context.auth)
504                                 + auth_context.sig_size;
505         image.update_vendor_code_size = 0; /* none */
506         image.update_hardware_instance = instance;
507         image.image_capsule_support = 0;
508         if (auth_context.sig_size)
509                 image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
510         if (write_capsule_file(f, &image, sizeof(image),
511                                "Firmware capsule image header"))
512                 goto err;
513
514         /*
515          * signature
516          */
517         if (auth_context.sig_size) {
518                 if (write_capsule_file(f, &auth_context.auth,
519                                        sizeof(auth_context.auth),
520                                        "Authentication header"))
521                         goto err;
522
523                 if (write_capsule_file(f, auth_context.sig_data,
524                                        auth_context.sig_size, "Signature"))
525                         goto err;
526         }
527
528         /*
529          * firmware binary
530          */
531         if (write_capsule_file(f, data, bin_size, "Firmware binary"))
532                 goto err;
533
534         ret = 0;
535 err:
536         if (f)
537                 fclose(f);
538         free_sig_data(&auth_context);
539         free(data);
540
541         return ret;
542 }
543
544 /**
545  * convert_uuid_to_guid() - convert UUID to GUID
546  * @buf:        UUID binary
547  *
548  * UUID and GUID have the same data structure, but their binary
549  * formats are different due to the endianness. See lib/uuid.c.
550  * Since uuid_parse() can handle only UUID, this function must
551  * be called to get correct data for GUID when parsing a string.
552  *
553  * The correct data will be returned in @buf.
554  */
555 void convert_uuid_to_guid(unsigned char *buf)
556 {
557         unsigned char c;
558
559         c = buf[0];
560         buf[0] = buf[3];
561         buf[3] = c;
562         c = buf[1];
563         buf[1] = buf[2];
564         buf[2] = c;
565
566         c = buf[4];
567         buf[4] = buf[5];
568         buf[5] = c;
569
570         c = buf[6];
571         buf[6] = buf[7];
572         buf[7] = c;
573 }
574
575 /**
576  * main - main entry function of mkeficapsule
577  * @argc:       Number of arguments
578  * @argv:       Array of pointers to arguments
579  *
580  * Create an uefi capsule file, optionally signing it.
581  * Parse all the arguments and pass them on to create_fwbin().
582  *
583  * Return:
584  * * 0  - on success
585  * * -1 - on failure
586  */
587 int main(int argc, char **argv)
588 {
589         efi_guid_t *guid;
590         unsigned char uuid_buf[16];
591         unsigned long index, instance;
592         uint64_t mcount;
593         char *privkey_file, *cert_file;
594         int c, idx;
595
596         guid = NULL;
597         index = 0;
598         instance = 0;
599         mcount = 0;
600         privkey_file = NULL;
601         cert_file = NULL;
602         dump_sig = 0;
603         for (;;) {
604                 c = getopt_long(argc, argv, opts_short, options, &idx);
605                 if (c == -1)
606                         break;
607
608                 switch (c) {
609                 case 'f':
610                         if (guid) {
611                                 fprintf(stderr,
612                                         "Image type already specified\n");
613                                 exit(EXIT_FAILURE);
614                         }
615                         guid = &efi_guid_image_type_uboot_fit;
616                         break;
617                 case 'r':
618                         if (guid) {
619                                 fprintf(stderr,
620                                         "Image type already specified\n");
621                                 exit(EXIT_FAILURE);
622                         }
623                         guid = &efi_guid_image_type_uboot_raw;
624                         break;
625                 case 'g':
626                         if (guid) {
627                                 fprintf(stderr,
628                                         "Image type already specified\n");
629                                 exit(EXIT_FAILURE);
630                         }
631                         if (uuid_parse(optarg, uuid_buf)) {
632                                 fprintf(stderr, "Wrong guid format\n");
633                                 exit(EXIT_FAILURE);
634                         }
635                         convert_uuid_to_guid(uuid_buf);
636                         guid = (efi_guid_t *)uuid_buf;
637                         break;
638                 case 'i':
639                         index = strtoul(optarg, NULL, 0);
640                         break;
641                 case 'I':
642                         instance = strtoul(optarg, NULL, 0);
643                         break;
644                 case 'p':
645                         if (privkey_file) {
646                                 fprintf(stderr,
647                                         "Private Key already specified\n");
648                                 exit(EXIT_FAILURE);
649                         }
650                         privkey_file = optarg;
651                         break;
652                 case 'c':
653                         if (cert_file) {
654                                 fprintf(stderr,
655                                         "Certificate file already specified\n");
656                                 exit(EXIT_FAILURE);
657                         }
658                         cert_file = optarg;
659                         break;
660                 case 'm':
661                         mcount = strtoul(optarg, NULL, 0);
662                         break;
663                 case 'd':
664                         dump_sig = 1;
665                         break;
666                 case 'h':
667                         print_usage();
668                         exit(EXIT_SUCCESS);
669                 }
670         }
671
672         /* check necessary parameters */
673         if ((argc != optind + 2) || !guid ||
674             ((privkey_file && !cert_file) ||
675              (!privkey_file && cert_file))) {
676                 print_usage();
677                 exit(EXIT_FAILURE);
678         }
679
680         if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
681                          mcount, privkey_file, cert_file) < 0) {
682                 fprintf(stderr, "Creating firmware capsule failed\n");
683                 exit(EXIT_FAILURE);
684         }
685
686         exit(EXIT_SUCCESS);
687 }