1 // SPDX-License-Identifier: GPL-2.0+
3 * Menu-driven UEFI Secure Boot Key Maintenance
5 * Copyright (c) 2022 Masahisa Kojima, Linaro Limited
15 #include <efi_loader.h>
16 #include <efi_config.h>
17 #include <efi_variable.h>
18 #include <crypto/pkcs7_parser.h>
20 struct eficonfig_sig_data {
21 struct efi_signature_list *esl;
22 struct efi_signature_data *esd;
23 struct list_head list;
27 enum efi_sbkey_signature_type {
34 struct eficonfig_sigtype_to_str {
37 enum efi_sbkey_signature_type type;
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}, */
57 * file_have_auth_header() - check file has EFI_VARIABLE_AUTHENTICATION_2 header
58 * @buf: pointer to file
60 * Return: true if file has auth header, false otherwise
62 static bool file_have_auth_header(void *buf, efi_uintn_t size)
64 struct efi_variable_authentication_2 *auth = buf;
66 if (auth->auth_info.hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
69 if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
76 * file_is_null_key() - check the file is an authenticated and signed null key
78 * @auth: pointer to the file
80 * @null_key: pointer to store the result
83 static efi_status_t file_is_null_key(struct efi_variable_authentication_2 *auth,
84 efi_uintn_t size, bool *null_key)
86 efi_uintn_t auth_size =
87 sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
90 return EFI_INVALID_PARAMETER;
92 *null_key = (size == auth_size);
98 * eficonfig_process_enroll_key() - enroll key into signature database
100 * @data: pointer to the data for each entry
101 * Return: status code
103 static efi_status_t eficonfig_process_enroll_key(void *data)
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;
114 file_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
115 if (!file_info.current_path) {
116 ret = EFI_OUT_OF_RESOURCES;
120 ret = eficonfig_process_select_file(&file_info);
121 if (ret != EFI_SUCCESS)
124 full_dp = eficonfig_create_device_path(file_info.dp_volume, file_info.current_path);
126 ret = EFI_OUT_OF_RESOURCES;
129 f = efi_file_from_path(full_dp);
136 ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, NULL));
137 if (ret != EFI_BUFFER_TOO_SMALL)
142 ret = EFI_OUT_OF_RESOURCES;
145 ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, buf));
146 if (ret != EFI_SUCCESS)
149 size = ((struct efi_file_info *)buf)->file_size;
153 eficonfig_print_msg("ERROR! File is empty.");
154 ret = EFI_INVALID_PARAMETER;
160 ret = EFI_OUT_OF_RESOURCES;
164 ret = EFI_CALL(f->read(f, &size, buf));
165 if (ret != EFI_SUCCESS) {
166 eficonfig_print_msg("ERROR! Failed to read file.");
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;
175 ret = file_is_null_key((struct efi_variable_authentication_2 *)buf,
177 if (ret != EFI_SUCCESS) {
178 eficonfig_print_msg("ERROR! Invalid file format.");
182 attr = EFI_VARIABLE_NON_VOLATILE |
183 EFI_VARIABLE_BOOTSERVICE_ACCESS |
184 EFI_VARIABLE_RUNTIME_ACCESS |
185 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
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.
192 if (u16_strcmp(data, u"PK") && !null_key) {
193 efi_uintn_t db_size = 0;
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;
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");
208 free(file_info.current_path);
210 efi_free_pool(full_dp);
212 EFI_CALL(f->close(f));
214 /* return to the parent menu */
215 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
221 * eficonfig_process_show_siglist() - show signature list content
223 * @data: pointer to the data for each entry
224 * Return: status code
226 static efi_status_t eficonfig_process_show_siglist(void *data)
229 struct eficonfig_sig_data *sg = data;
231 puts(ANSI_CURSOR_HIDE);
232 puts(ANSI_CLEAR_CONSOLE);
233 printf(ANSI_CURSOR_POSITION, 1, 1);
235 printf("\n ** Show Signature Database (%ls) **\n\n"
238 sg->varname, sg->esd->signature_owner.b);
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);
245 switch (sigtype_to_str[i].type) {
248 struct x509_certificate *cert_tmp;
250 cert_tmp = x509_cert_parse(sg->esd->signature_data,
251 sg->esl->signature_size);
256 cert_tmp->subject, cert_tmp->issuer);
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 +
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);
278 u32 hash_size = sg->esl->signature_size - sizeof(efi_guid_t);
281 print_hex_dump(" ", DUMP_PREFIX_NONE, 16, 1,
282 sg->esd->signature_data, hash_size, false);
286 eficonfig_print_msg("ERROR! Unsupported format.");
287 return EFI_INVALID_PARAMETER;
295 printf("\n\n Press any key to continue");
302 * prepare_signature_list_menu() - create the signature list menu entry
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
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)
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;
322 INIT_LIST_HEAD(&efi_menu->list);
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) {
338 if (num >= EFICONFIG_ENTRY_NUM_MAX - 1) {
339 ret = EFI_OUT_OF_RESOURCES;
343 sg = calloc(1, sizeof(struct eficonfig_sig_data));
345 ret = EFI_OUT_OF_RESOURCES;
349 snprintf(buf, sizeof(buf), "%pUL", &esd->signature_owner);
353 ret = EFI_OUT_OF_RESOURCES;
359 sg->varname = varname;
360 ret = eficonfig_append_menu_entry(efi_menu, title, func, sg);
361 if (ret != EFI_SUCCESS) {
366 esd = (struct efi_signature_data *)((u8 *)esd + esl->signature_size);
370 size -= esl->signature_list_size;
371 esl = (struct efi_signature_list *)((u8 *)esl + esl->signature_list_size);
374 ret = eficonfig_append_quit_entry(efi_menu);
380 * enumerate_and_show_signature_database() - enumerate and show the signature database
382 * @data: pointer to the data for each entry
383 * Return: status code
385 static efi_status_t enumerate_and_show_signature_database(void *varname)
391 struct efimenu *efi_menu;
392 struct list_head *pos, *n;
393 struct eficonfig_entry *entry;
395 db = efi_get_var(varname, efi_auth_var_get_guid(varname), &db_size);
397 eficonfig_print_msg("There is no entry in the signature database.");
398 return EFI_NOT_FOUND;
401 efi_menu = calloc(1, sizeof(struct efimenu));
404 return EFI_OUT_OF_RESOURCES;
407 ret = prepare_signature_list_menu(efi_menu, varname, db, db_size,
408 eficonfig_process_show_siglist);
409 if (ret != EFI_SUCCESS)
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);
418 list_for_each_safe(pos, n, &efi_menu->list) {
419 entry = list_entry(pos, struct eficonfig_entry, list);
422 eficonfig_destroy(efi_menu);
429 * eficonfig_process_show_signature_database() - process show signature database
431 * @data: pointer to the data for each entry
432 * Return: status code
434 static efi_status_t eficonfig_process_show_signature_database(void *data)
439 ret = enumerate_and_show_signature_database(data);
440 if (ret != EFI_SUCCESS && ret != EFI_NOT_READY)
444 /* return to the parent menu */
445 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
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},
457 * eficonfig_process_set_secure_boot_key() - display the key configuration menu
459 * @data: pointer to the data for each entry
460 * Return: status code
462 static efi_status_t eficonfig_process_set_secure_boot_key(void *data)
467 struct efimenu *efi_menu;
469 for (i = 0; i < ARRAY_SIZE(key_config_menu_items); i++)
470 key_config_menu_items[i].data = data;
472 snprintf(header_str, sizeof(header_str), " ** Configure %ls **", (u16 *)data);
475 efi_menu = eficonfig_create_fixed_menu(key_config_menu_items,
476 ARRAY_SIZE(key_config_menu_items));
478 ret = eficonfig_process_common(efi_menu, header_str,
480 eficonfig_display_statusline,
481 eficonfig_print_entry,
482 eficonfig_choice_entry);
483 eficonfig_destroy(efi_menu);
485 if (ret == EFI_ABORTED)
489 /* return to the parent menu */
490 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
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},
504 * eficonfig_process_secure_boot_config() - display the key list menu
506 * @data: pointer to the data for each entry
507 * Return: status code
509 efi_status_t eficonfig_process_secure_boot_config(void *data)
512 struct efimenu *efi_menu;
517 snprintf(header_str, sizeof(header_str),
518 " ** UEFI Secure Boot Key Configuration (SecureBoot : %s) **",
519 (efi_secure_boot_enabled() ? "ON" : "OFF"));
521 efi_menu = eficonfig_create_fixed_menu(secure_boot_menu_items,
522 ARRAY_SIZE(secure_boot_menu_items));
524 ret = EFI_OUT_OF_RESOURCES;
528 ret = eficonfig_process_common(efi_menu, header_str,
530 eficonfig_display_statusline,
531 eficonfig_print_entry,
532 eficonfig_choice_entry);
534 eficonfig_destroy(efi_menu);
536 if (ret == EFI_ABORTED)
540 /* return to the parent menu */
541 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;