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