Merge tag 'efi-2023-04-rc1-3' of https://source.denx.de/u-boot/custodians/u-boot-efi
[platform/kernel/u-boot.git] / cmd / eficonfig_sbkey.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Menu-driven UEFI Secure Boot Key Maintenance
4  *
5  *  Copyright (c) 2022 Masahisa Kojima, Linaro Limited
6  */
7
8 #include <ansi.h>
9 #include <common.h>
10 #include <charset.h>
11 #include <hexdump.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <menu.h>
15 #include <efi_loader.h>
16 #include <efi_config.h>
17 #include <efi_variable.h>
18 #include <crypto/pkcs7_parser.h>
19
20 struct eficonfig_sig_data {
21         struct efi_signature_list *esl;
22         struct efi_signature_data *esd;
23         struct list_head list;
24         u16 *varname;
25 };
26
27 enum efi_sbkey_signature_type {
28         SIG_TYPE_X509 = 0,
29         SIG_TYPE_HASH,
30         SIG_TYPE_CRL,
31         SIG_TYPE_RSA2048,
32 };
33
34 struct eficonfig_sigtype_to_str {
35         efi_guid_t sig_type;
36         char *str;
37         enum efi_sbkey_signature_type type;
38 };
39
40 static const struct eficonfig_sigtype_to_str sigtype_to_str[] = {
41         {EFI_CERT_X509_GUID,            "X509",                 SIG_TYPE_X509},
42         {EFI_CERT_SHA256_GUID,          "SHA256",               SIG_TYPE_HASH},
43         {EFI_CERT_X509_SHA256_GUID,     "X509_SHA256 CRL",      SIG_TYPE_CRL},
44         {EFI_CERT_X509_SHA384_GUID,     "X509_SHA384 CRL",      SIG_TYPE_CRL},
45         {EFI_CERT_X509_SHA512_GUID,     "X509_SHA512 CRL",      SIG_TYPE_CRL},
46         /* U-Boot does not support the following signature types */
47 /*      {EFI_CERT_RSA2048_GUID,         "RSA2048",              SIG_TYPE_RSA2048}, */
48 /*      {EFI_CERT_RSA2048_SHA256_GUID,  "RSA2048_SHA256",       SIG_TYPE_RSA2048}, */
49 /*      {EFI_CERT_SHA1_GUID,            "SHA1",                 SIG_TYPE_HASH}, */
50 /*      {EFI_CERT_RSA2048_SHA_GUID,     "RSA2048_SHA",          SIG_TYPE_RSA2048 }, */
51 /*      {EFI_CERT_SHA224_GUID,          "SHA224",               SIG_TYPE_HASH}, */
52 /*      {EFI_CERT_SHA384_GUID,          "SHA384",               SIG_TYPE_HASH}, */
53 /*      {EFI_CERT_SHA512_GUID,          "SHA512",               SIG_TYPE_HASH}, */
54 };
55
56 /**
57  * file_have_auth_header() - check file has EFI_VARIABLE_AUTHENTICATION_2 header
58  * @buf:        pointer to file
59  * @size:       file size
60  * Return:      true if file has auth header, false otherwise
61  */
62 static bool file_have_auth_header(void *buf, efi_uintn_t size)
63 {
64         struct efi_variable_authentication_2 *auth = buf;
65
66         if (auth->auth_info.hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
67                 return false;
68
69         if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
70                 return false;
71
72         return true;
73 }
74
75 /**
76  * file_is_null_key() - check the file is an authenticated and signed null key
77  *
78  * @auth:       pointer to the file
79  * @size:       file size
80  * @null_key:   pointer to store the result
81  * Return:      status code
82  */
83 static efi_status_t file_is_null_key(struct efi_variable_authentication_2 *auth,
84                                      efi_uintn_t size, bool *null_key)
85 {
86         efi_uintn_t auth_size =
87                 sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
88
89         if (size < auth_size)
90                 return EFI_INVALID_PARAMETER;
91
92         *null_key = (size == auth_size);
93
94         return EFI_SUCCESS;
95 }
96
97 /**
98  * eficonfig_process_enroll_key() - enroll key into signature database
99  *
100  * @data:       pointer to the data for each entry
101  * Return:      status code
102  */
103 static efi_status_t eficonfig_process_enroll_key(void *data)
104 {
105         u32 attr;
106         char *buf = NULL;
107         efi_uintn_t size;
108         efi_status_t ret;
109         bool null_key = false;
110         struct efi_file_handle *f = NULL;
111         struct efi_device_path *full_dp = NULL;
112         struct eficonfig_select_file_info file_info;
113
114         file_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
115         if (!file_info.current_path) {
116                 ret = EFI_OUT_OF_RESOURCES;
117                 goto out;
118         }
119
120         ret = eficonfig_process_select_file(&file_info);
121         if (ret != EFI_SUCCESS)
122                 goto out;
123
124         full_dp = eficonfig_create_device_path(file_info.dp_volume, file_info.current_path);
125         if (!full_dp) {
126                 ret = EFI_OUT_OF_RESOURCES;
127                 goto out;
128         }
129         f = efi_file_from_path(full_dp);
130         if (!f) {
131                 ret = EFI_NOT_FOUND;
132                 goto out;
133         }
134
135         size = 0;
136         ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, NULL));
137         if (ret != EFI_BUFFER_TOO_SMALL)
138                 goto out;
139
140         buf = malloc(size);
141         if (!buf) {
142                 ret = EFI_OUT_OF_RESOURCES;
143                 goto out;
144         }
145         ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, buf));
146         if (ret != EFI_SUCCESS)
147                 goto out;
148
149         size = ((struct efi_file_info *)buf)->file_size;
150         free(buf);
151
152         if (!size) {
153                 eficonfig_print_msg("ERROR! File is empty.");
154                 ret = EFI_INVALID_PARAMETER;
155                 goto out;
156         }
157
158         buf = malloc(size);
159         if (!buf) {
160                 ret = EFI_OUT_OF_RESOURCES;
161                 goto out;
162         }
163
164         ret = EFI_CALL(f->read(f, &size, buf));
165         if (ret != EFI_SUCCESS) {
166                 eficonfig_print_msg("ERROR! Failed to read file.");
167                 goto out;
168         }
169         if (!file_have_auth_header(buf, size)) {
170                 eficonfig_print_msg("ERROR! Invalid file format. Only .auth variables is allowed.");
171                 ret = EFI_INVALID_PARAMETER;
172                 goto out;
173         }
174
175         ret = file_is_null_key((struct efi_variable_authentication_2 *)buf,
176                                size, &null_key);
177         if (ret != EFI_SUCCESS) {
178                 eficonfig_print_msg("ERROR! Invalid file format.");
179                 goto out;
180         }
181
182         attr = EFI_VARIABLE_NON_VOLATILE |
183                EFI_VARIABLE_BOOTSERVICE_ACCESS |
184                EFI_VARIABLE_RUNTIME_ACCESS |
185                EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
186
187         /*
188          * PK can enroll only one certificate.
189          * The signed null key is used to clear KEK, db and dbx.
190          * EFI_VARIABLE_APPEND_WRITE attribute must not be set in these cases.
191          */
192         if (u16_strcmp(data, u"PK") && !null_key) {
193                 efi_uintn_t db_size = 0;
194
195                 /* check the variable exists. If exists, add APPEND_WRITE attribute */
196                 ret = efi_get_variable_int(data, efi_auth_var_get_guid(data), NULL,
197                                            &db_size, NULL,  NULL);
198                 if (ret == EFI_BUFFER_TOO_SMALL)
199                         attr |= EFI_VARIABLE_APPEND_WRITE;
200         }
201
202         ret = efi_set_variable_int((u16 *)data, efi_auth_var_get_guid((u16 *)data),
203                                    attr, size, buf, false);
204         if (ret != EFI_SUCCESS)
205                 eficonfig_print_msg("ERROR! Failed to update signature database");
206
207 out:
208         free(file_info.current_path);
209         free(buf);
210         efi_free_pool(full_dp);
211         if (f)
212                 EFI_CALL(f->close(f));
213
214         /* return to the parent menu */
215         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
216
217         return ret;
218 }
219
220 /**
221  * eficonfig_process_show_siglist() - show signature list content
222  *
223  * @data:       pointer to the data for each entry
224  * Return:      status code
225  */
226 static efi_status_t eficonfig_process_show_siglist(void *data)
227 {
228         u32 i;
229         struct eficonfig_sig_data *sg = data;
230
231         puts(ANSI_CURSOR_HIDE);
232         puts(ANSI_CLEAR_CONSOLE);
233         printf(ANSI_CURSOR_POSITION, 1, 1);
234
235         printf("\n  ** Show Signature Database (%ls) **\n\n"
236                "    Owner GUID:\n"
237                "      %pUL\n",
238                sg->varname, sg->esd->signature_owner.b);
239
240         for (i = 0; i < ARRAY_SIZE(sigtype_to_str); i++) {
241                 if (!guidcmp(&sg->esl->signature_type, &sigtype_to_str[i].sig_type)) {
242                         printf("    Signature Type:\n"
243                                "      %s\n", sigtype_to_str[i].str);
244
245                         switch (sigtype_to_str[i].type) {
246                         case SIG_TYPE_X509:
247                         {
248                                 struct x509_certificate *cert_tmp;
249
250                                 cert_tmp = x509_cert_parse(sg->esd->signature_data,
251                                                            sg->esl->signature_size);
252                                 printf("    Subject:\n"
253                                        "      %s\n"
254                                        "    Issuer:\n"
255                                        "      %s\n",
256                                        cert_tmp->subject, cert_tmp->issuer);
257                                 break;
258                         }
259                         case SIG_TYPE_CRL:
260                         {
261                                 u32 hash_size = sg->esl->signature_size - sizeof(efi_guid_t) -
262                                                 sizeof(struct efi_time);
263                                 struct efi_time *time =
264                                         (struct efi_time *)((u8 *)sg->esd->signature_data +
265                                         hash_size);
266
267                                 printf("    ToBeSignedHash:\n");
268                                 print_hex_dump("      ", DUMP_PREFIX_NONE, 16, 1,
269                                                sg->esd->signature_data, hash_size, false);
270                                 printf("    TimeOfRevocation:\n"
271                                        "      %d-%d-%d %02d:%02d:%02d\n",
272                                        time->year, time->month, time->day,
273                                        time->hour, time->minute, time->second);
274                                 break;
275                         }
276                         case SIG_TYPE_HASH:
277                         {
278                                 u32 hash_size = sg->esl->signature_size - sizeof(efi_guid_t);
279
280                                 printf("    Hash:\n");
281                                 print_hex_dump("      ", DUMP_PREFIX_NONE, 16, 1,
282                                                sg->esd->signature_data, hash_size, false);
283                                 break;
284                         }
285                         default:
286                                 eficonfig_print_msg("ERROR! Unsupported format.");
287                                 return EFI_INVALID_PARAMETER;
288                         }
289                 }
290         }
291
292         while (tstc())
293                 getchar();
294
295         printf("\n\n  Press any key to continue");
296         getchar();
297
298         return EFI_SUCCESS;
299 }
300
301 /**
302  * prepare_signature_list_menu() - create the signature list menu entry
303  *
304  * @efimenu:    pointer to the efimenu structure
305  * @varname:    pointer to the variable name
306  * @db:         pointer to the variable raw data
307  * @db_size:    variable data size
308  * @func:       callback of each entry
309  * Return:      status code
310  */
311 static efi_status_t prepare_signature_list_menu(struct efimenu *efi_menu, void *varname,
312                                                 void *db, efi_uintn_t db_size,
313                                                 eficonfig_entry_func func)
314 {
315         u32 num = 0;
316         efi_uintn_t size;
317         struct eficonfig_sig_data *sg;
318         struct efi_signature_list *esl;
319         struct efi_signature_data *esd;
320         efi_status_t ret = EFI_SUCCESS;
321
322         INIT_LIST_HEAD(&efi_menu->list);
323
324         esl = db;
325         size = db_size;
326         while (size > 0) {
327                 u32 remain;
328
329                 esd = (struct efi_signature_data *)((u8 *)esl +
330                                                     (sizeof(struct efi_signature_list) +
331                                                     esl->signature_header_size));
332                 remain = esl->signature_list_size - sizeof(struct efi_signature_list) -
333                          esl->signature_header_size;
334                 for (; remain > 0; remain -= esl->signature_size) {
335                         char buf[37];
336                         char *title;
337
338                         if (num >= EFICONFIG_ENTRY_NUM_MAX - 1) {
339                                 ret = EFI_OUT_OF_RESOURCES;
340                                 goto out;
341                         }
342
343                         sg = calloc(1, sizeof(struct eficonfig_sig_data));
344                         if (!sg) {
345                                 ret = EFI_OUT_OF_RESOURCES;
346                                 goto err;
347                         }
348
349                         snprintf(buf, sizeof(buf), "%pUL", &esd->signature_owner);
350                         title = strdup(buf);
351                         if (!title) {
352                                 free(sg);
353                                 ret = EFI_OUT_OF_RESOURCES;
354                                 goto err;
355                         }
356
357                         sg->esl = esl;
358                         sg->esd = esd;
359                         sg->varname = varname;
360                         ret = eficonfig_append_menu_entry(efi_menu, title, func, sg);
361                         if (ret != EFI_SUCCESS) {
362                                 free(sg);
363                                 free(title);
364                                 goto err;
365                         }
366                         esd = (struct efi_signature_data *)((u8 *)esd + esl->signature_size);
367                         num++;
368                 }
369
370                 size -= esl->signature_list_size;
371                 esl = (struct efi_signature_list *)((u8 *)esl + esl->signature_list_size);
372         }
373 out:
374         ret = eficonfig_append_quit_entry(efi_menu);
375 err:
376         return ret;
377 }
378
379 /**
380  * enumerate_and_show_signature_database() - enumerate and show the signature database
381  *
382  * @data:       pointer to the data for each entry
383  * Return:      status code
384  */
385 static efi_status_t enumerate_and_show_signature_database(void *varname)
386 {
387         void *db;
388         char buf[50];
389         efi_status_t ret;
390         efi_uintn_t db_size;
391         struct efimenu *efi_menu;
392         struct list_head *pos, *n;
393         struct eficonfig_entry *entry;
394
395         db = efi_get_var(varname, efi_auth_var_get_guid(varname), &db_size);
396         if (!db) {
397                 eficonfig_print_msg("There is no entry in the signature database.");
398                 return EFI_NOT_FOUND;
399         }
400
401         efi_menu = calloc(1, sizeof(struct efimenu));
402         if (!efi_menu) {
403                 free(db);
404                 return EFI_OUT_OF_RESOURCES;
405         }
406
407         ret = prepare_signature_list_menu(efi_menu, varname, db, db_size,
408                                           eficonfig_process_show_siglist);
409         if (ret != EFI_SUCCESS)
410                 goto out;
411
412         snprintf(buf, sizeof(buf), "  ** Show Signature Database (%ls) **", (u16 *)varname);
413         ret = eficonfig_process_common(efi_menu, buf, eficonfig_menu_desc,
414                                        eficonfig_display_statusline,
415                                        eficonfig_print_entry,
416                                        eficonfig_choice_entry);
417 out:
418         list_for_each_safe(pos, n, &efi_menu->list) {
419                 entry = list_entry(pos, struct eficonfig_entry, list);
420                 free(entry->data);
421         }
422         eficonfig_destroy(efi_menu);
423         free(db);
424
425         return ret;
426 }
427
428 /**
429  * eficonfig_process_show_signature_database() - process show signature database
430  *
431  * @data:       pointer to the data for each entry
432  * Return:      status code
433  */
434 static efi_status_t eficonfig_process_show_signature_database(void *data)
435 {
436         efi_status_t ret;
437
438         while (1) {
439                 ret = enumerate_and_show_signature_database(data);
440                 if (ret != EFI_SUCCESS && ret != EFI_NOT_READY)
441                         break;
442         }
443
444         /* return to the parent menu */
445         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
446
447         return ret;
448 }
449
450 static struct eficonfig_item key_config_menu_items[] = {
451         {"Enroll New Key", eficonfig_process_enroll_key},
452         {"Show Signature Database", eficonfig_process_show_signature_database},
453         {"Quit", eficonfig_process_quit},
454 };
455
456 /**
457  * eficonfig_process_set_secure_boot_key() - display the key configuration menu
458  *
459  * @data:       pointer to the data for each entry
460  * Return:      status code
461  */
462 static efi_status_t eficonfig_process_set_secure_boot_key(void *data)
463 {
464         u32 i;
465         efi_status_t ret;
466         char header_str[32];
467         struct efimenu *efi_menu;
468
469         for (i = 0; i < ARRAY_SIZE(key_config_menu_items); i++)
470                 key_config_menu_items[i].data = data;
471
472         snprintf(header_str, sizeof(header_str), "  ** Configure %ls **", (u16 *)data);
473
474         while (1) {
475                 efi_menu = eficonfig_create_fixed_menu(key_config_menu_items,
476                                                        ARRAY_SIZE(key_config_menu_items));
477
478                 ret = eficonfig_process_common(efi_menu, header_str,
479                                                eficonfig_menu_desc,
480                                                eficonfig_display_statusline,
481                                                eficonfig_print_entry,
482                                                eficonfig_choice_entry);
483                 eficonfig_destroy(efi_menu);
484
485                 if (ret == EFI_ABORTED)
486                         break;
487         }
488
489         /* return to the parent menu */
490         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
491
492         return ret;
493 }
494
495 static const struct eficonfig_item secure_boot_menu_items[] = {
496         {"PK", eficonfig_process_set_secure_boot_key, u"PK"},
497         {"KEK", eficonfig_process_set_secure_boot_key, u"KEK"},
498         {"db", eficonfig_process_set_secure_boot_key, u"db"},
499         {"dbx", eficonfig_process_set_secure_boot_key, u"dbx"},
500         {"Quit", eficonfig_process_quit},
501 };
502
503 /**
504  * eficonfig_process_secure_boot_config() - display the key list menu
505  *
506  * @data:       pointer to the data for each entry
507  * Return:      status code
508  */
509 efi_status_t eficonfig_process_secure_boot_config(void *data)
510 {
511         efi_status_t ret;
512         struct efimenu *efi_menu;
513
514         while (1) {
515                 char header_str[64];
516
517                 snprintf(header_str, sizeof(header_str),
518                          "  ** UEFI Secure Boot Key Configuration (SecureBoot : %s) **",
519                          (efi_secure_boot_enabled() ? "ON" : "OFF"));
520
521                 efi_menu = eficonfig_create_fixed_menu(secure_boot_menu_items,
522                                                        ARRAY_SIZE(secure_boot_menu_items));
523                 if (!efi_menu) {
524                         ret = EFI_OUT_OF_RESOURCES;
525                         break;
526                 }
527
528                 ret = eficonfig_process_common(efi_menu, header_str,
529                                                eficonfig_menu_desc,
530                                                eficonfig_display_statusline,
531                                                eficonfig_print_entry,
532                                                eficonfig_choice_entry);
533
534                 eficonfig_destroy(efi_menu);
535
536                 if (ret == EFI_ABORTED)
537                         break;
538         }
539
540         /* return to the parent menu */
541         ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
542
543         return ret;
544 }